Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: str: implement several traits for `CStr`

Implement `Debug`, `Display`, `Deref` (into `BStr`), `AsRef<BStr>`
and a set of `Index<...>` traits.

This makes it `CStr` more convenient to use (and closer to `str`).

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

authored by

Gary Guo and committed by
Miguel Ojeda
c07e67bd d126d238

+123 -1
+123 -1
rust/kernel/str.rs
··· 2 2 3 3 //! String representations. 4 4 5 - use core::fmt; 5 + use core::fmt::{self, Write}; 6 + use core::ops::{self, Deref, Index}; 6 7 7 8 use crate::{ 8 9 bindings, ··· 197 196 #[inline] 198 197 pub unsafe fn as_str_unchecked(&self) -> &str { 199 198 unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } 199 + } 200 + } 201 + 202 + impl fmt::Display for CStr { 203 + /// Formats printable ASCII characters, escaping the rest. 204 + /// 205 + /// ``` 206 + /// # use kernel::c_str; 207 + /// # use kernel::str::CStr; 208 + /// # use kernel::str::CString; 209 + /// let penguin = c_str!("🐧"); 210 + /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap(); 211 + /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes()); 212 + /// 213 + /// let ascii = c_str!("so \"cool\""); 214 + /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap(); 215 + /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes()); 216 + /// ``` 217 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 218 + for &c in self.as_bytes() { 219 + if (0x20..0x7f).contains(&c) { 220 + // Printable character. 221 + f.write_char(c as char)?; 222 + } else { 223 + write!(f, "\\x{:02x}", c)?; 224 + } 225 + } 226 + Ok(()) 227 + } 228 + } 229 + 230 + impl fmt::Debug for CStr { 231 + /// Formats printable ASCII characters with a double quote on either end, escaping the rest. 232 + /// 233 + /// ``` 234 + /// # use kernel::c_str; 235 + /// # use kernel::str::CStr; 236 + /// # use kernel::str::CString; 237 + /// let penguin = c_str!("🐧"); 238 + /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap(); 239 + /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes()); 240 + /// 241 + /// // Embedded double quotes are escaped. 242 + /// let ascii = c_str!("so \"cool\""); 243 + /// let s = CString::try_from_fmt(fmt!("{:?}", ascii)).unwrap(); 244 + /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes()); 245 + /// ``` 246 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 247 + f.write_str("\"")?; 248 + for &c in self.as_bytes() { 249 + match c { 250 + // Printable characters. 251 + b'\"' => f.write_str("\\\"")?, 252 + 0x20..=0x7e => f.write_char(c as char)?, 253 + _ => write!(f, "\\x{:02x}", c)?, 254 + } 255 + } 256 + f.write_str("\"") 257 + } 258 + } 259 + 260 + impl AsRef<BStr> for CStr { 261 + #[inline] 262 + fn as_ref(&self) -> &BStr { 263 + self.as_bytes() 264 + } 265 + } 266 + 267 + impl Deref for CStr { 268 + type Target = BStr; 269 + 270 + #[inline] 271 + fn deref(&self) -> &Self::Target { 272 + self.as_bytes() 273 + } 274 + } 275 + 276 + impl Index<ops::RangeFrom<usize>> for CStr { 277 + type Output = CStr; 278 + 279 + #[inline] 280 + fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output { 281 + // Delegate bounds checking to slice. 282 + // Assign to _ to mute clippy's unnecessary operation warning. 283 + let _ = &self.as_bytes()[index.start..]; 284 + // SAFETY: We just checked the bounds. 285 + unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) } 286 + } 287 + } 288 + 289 + impl Index<ops::RangeFull> for CStr { 290 + type Output = CStr; 291 + 292 + #[inline] 293 + fn index(&self, _index: ops::RangeFull) -> &Self::Output { 294 + self 295 + } 296 + } 297 + 298 + mod private { 299 + use core::ops; 300 + 301 + // Marker trait for index types that can be forward to `BStr`. 302 + pub trait CStrIndex {} 303 + 304 + impl CStrIndex for usize {} 305 + impl CStrIndex for ops::Range<usize> {} 306 + impl CStrIndex for ops::RangeInclusive<usize> {} 307 + impl CStrIndex for ops::RangeToInclusive<usize> {} 308 + } 309 + 310 + impl<Idx> Index<Idx> for CStr 311 + where 312 + Idx: private::CStrIndex, 313 + BStr: Index<Idx>, 314 + { 315 + type Output = <BStr as Index<Idx>>::Output; 316 + 317 + #[inline] 318 + fn index(&self, index: Idx) -> &Self::Output { 319 + &self.as_bytes()[index] 200 320 } 201 321 } 202 322