diff options
Diffstat (limited to 'rust/kernel/str.rs')
| -rw-r--r-- | rust/kernel/str.rs | 98 | 
1 files changed, 90 insertions, 8 deletions
| diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs index 925ced8fdc61..bb8d4f41475b 100644 --- a/rust/kernel/str.rs +++ b/rust/kernel/str.rs @@ -2,15 +2,12 @@  //! String representations. -use alloc::alloc::AllocError; +use crate::alloc::{flags::*, vec_ext::VecExt, AllocError};  use alloc::vec::Vec;  use core::fmt::{self, Write}; -use core::ops::{self, Deref, Index}; +use core::ops::{self, Deref, DerefMut, Index}; -use crate::{ -    bindings, -    error::{code::*, Error}, -}; +use crate::error::{code::*, Error};  /// Byte string without UTF-8 validity guarantee.  #[repr(transparent)] @@ -236,6 +233,19 @@ impl CStr {          unsafe { core::mem::transmute(bytes) }      } +    /// Creates a mutable [`CStr`] from a `[u8]` without performing any +    /// additional checks. +    /// +    /// # Safety +    /// +    /// `bytes` *must* end with a `NUL` byte, and should only have a single +    /// `NUL` byte (or the string will be truncated). +    #[inline] +    pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr { +        // SAFETY: Properties of `bytes` guaranteed by the safety precondition. +        unsafe { &mut *(bytes as *mut [u8] as *mut CStr) } +    } +      /// Returns a C pointer to the string.      #[inline]      pub const fn as_char_ptr(&self) -> *const core::ffi::c_char { @@ -299,6 +309,70 @@ impl CStr {      pub fn to_cstring(&self) -> Result<CString, AllocError> {          CString::try_from(self)      } + +    /// Converts this [`CStr`] to its ASCII lower case equivalent in-place. +    /// +    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', +    /// but non-ASCII letters are unchanged. +    /// +    /// To return a new lowercased value without modifying the existing one, use +    /// [`to_ascii_lowercase()`]. +    /// +    /// [`to_ascii_lowercase()`]: #method.to_ascii_lowercase +    pub fn make_ascii_lowercase(&mut self) { +        // INVARIANT: This doesn't introduce or remove NUL bytes in the C +        // string. +        self.0.make_ascii_lowercase(); +    } + +    /// Converts this [`CStr`] to its ASCII upper case equivalent in-place. +    /// +    /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', +    /// but non-ASCII letters are unchanged. +    /// +    /// To return a new uppercased value without modifying the existing one, use +    /// [`to_ascii_uppercase()`]. +    /// +    /// [`to_ascii_uppercase()`]: #method.to_ascii_uppercase +    pub fn make_ascii_uppercase(&mut self) { +        // INVARIANT: This doesn't introduce or remove NUL bytes in the C +        // string. +        self.0.make_ascii_uppercase(); +    } + +    /// Returns a copy of this [`CString`] where each character is mapped to its +    /// ASCII lower case equivalent. +    /// +    /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', +    /// but non-ASCII letters are unchanged. +    /// +    /// To lowercase the value in-place, use [`make_ascii_lowercase`]. +    /// +    /// [`make_ascii_lowercase`]: str::make_ascii_lowercase +    pub fn to_ascii_lowercase(&self) -> Result<CString, AllocError> { +        let mut s = self.to_cstring()?; + +        s.make_ascii_lowercase(); + +        Ok(s) +    } + +    /// Returns a copy of this [`CString`] where each character is mapped to its +    /// ASCII upper case equivalent. +    /// +    /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', +    /// but non-ASCII letters are unchanged. +    /// +    /// To uppercase the value in-place, use [`make_ascii_uppercase`]. +    /// +    /// [`make_ascii_uppercase`]: str::make_ascii_uppercase +    pub fn to_ascii_uppercase(&self) -> Result<CString, AllocError> { +        let mut s = self.to_cstring()?; + +        s.make_ascii_uppercase(); + +        Ok(s) +    }  }  impl fmt::Display for CStr { @@ -729,7 +803,7 @@ impl CString {          let size = f.bytes_written();          // Allocate a vector with the required number of bytes, and write to it. -        let mut buf = Vec::try_with_capacity(size)?; +        let mut buf = <Vec<_> as VecExt<_>>::with_capacity(size, GFP_KERNEL)?;          // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes.          let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) };          f.write_fmt(args)?; @@ -764,13 +838,21 @@ impl Deref for CString {      }  } +impl DerefMut for CString { +    fn deref_mut(&mut self) -> &mut Self::Target { +        // SAFETY: A `CString` is always NUL-terminated and contains no other +        // NUL bytes. +        unsafe { CStr::from_bytes_with_nul_unchecked_mut(self.buf.as_mut_slice()) } +    } +} +  impl<'a> TryFrom<&'a CStr> for CString {      type Error = AllocError;      fn try_from(cstr: &'a CStr) -> Result<CString, AllocError> {          let mut buf = Vec::new(); -        buf.try_extend_from_slice(cstr.as_bytes_with_nul()) +        <Vec<_> as VecExt<_>>::extend_from_slice(&mut buf, cstr.as_bytes_with_nul(), GFP_KERNEL)              .map_err(|_| AllocError)?;          // INVARIANT: The `CStr` and `CString` types have the same invariants for |