Skip to content

Commit 9d4c59b

Browse files
dakrfbq
authored andcommitted
rust: str: add {make,to}_{upper,lower}case() to CString
Add functions to convert a CString to upper- / lowercase, either in-place or by creating a copy of the original CString. Naming followes the one from the Rust stdlib, where functions starting with 'to' create a copy and functions starting with 'make' perform an in-place conversion. This is required by the Nova project (GSP only Rust successor of Nouveau) to convert stringified enum values (representing different GPU chipsets) to strings in order to generate the corresponding firmware paths. See also [1]. [1] https://rust-for-linux.zulipchat.com/#narrow/stream/288089-General/topic/String.20manipulation.20in.20kernel.20Rust Reviewed-by: Alice Ryhl <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent e09ae6d commit 9d4c59b

File tree

1 file changed

+86
-1
lines changed

1 file changed

+86
-1
lines changed

rust/kernel/str.rs

+86-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use crate::alloc::{flags::*, vec_ext::VecExt, AllocError};
66
use alloc::vec::Vec;
77
use core::fmt::{self, Write};
8-
use core::ops::{self, Deref, Index};
8+
use core::ops::{self, Deref, DerefMut, Index};
99

1010
use crate::{
1111
bindings,
@@ -236,6 +236,19 @@ impl CStr {
236236
unsafe { core::mem::transmute(bytes) }
237237
}
238238

239+
/// Creates a mutable [`CStr`] from a `[u8]` without performing any
240+
/// additional checks.
241+
///
242+
/// # Safety
243+
///
244+
/// `bytes` *must* end with a `NUL` byte, and should only have a single
245+
/// `NUL` byte (or the string will be truncated).
246+
#[inline]
247+
pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr {
248+
// SAFETY: Properties of `bytes` guaranteed by the safety precondition.
249+
unsafe { &mut *(bytes as *mut [u8] as *mut CStr) }
250+
}
251+
239252
/// Returns a C pointer to the string.
240253
#[inline]
241254
pub const fn as_char_ptr(&self) -> *const core::ffi::c_char {
@@ -299,6 +312,70 @@ impl CStr {
299312
pub fn to_cstring(&self) -> Result<CString, AllocError> {
300313
CString::try_from(self)
301314
}
315+
316+
/// Converts this [`CStr`] to its ASCII lower case equivalent in-place.
317+
///
318+
/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
319+
/// but non-ASCII letters are unchanged.
320+
///
321+
/// To return a new lowercased value without modifying the existing one, use
322+
/// [`to_ascii_lowercase()`].
323+
///
324+
/// [`to_ascii_lowercase()`]: #method.to_ascii_lowercase
325+
pub fn make_ascii_lowercase(&mut self) {
326+
// INVARIANT: This doesn't introduce or remove NUL bytes in the C
327+
// string.
328+
self.0.make_ascii_lowercase();
329+
}
330+
331+
/// Converts this [`CStr`] to its ASCII upper case equivalent in-place.
332+
///
333+
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
334+
/// but non-ASCII letters are unchanged.
335+
///
336+
/// To return a new uppercased value without modifying the existing one, use
337+
/// [`to_ascii_uppercase()`].
338+
///
339+
/// [`to_ascii_uppercase()`]: #method.to_ascii_uppercase
340+
pub fn make_ascii_uppercase(&mut self) {
341+
// INVARIANT: This doesn't introduce or remove NUL bytes in the C
342+
// string.
343+
self.0.make_ascii_uppercase();
344+
}
345+
346+
/// Returns a copy of this [`CString`] where each character is mapped to its
347+
/// ASCII lower case equivalent.
348+
///
349+
/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
350+
/// but non-ASCII letters are unchanged.
351+
///
352+
/// To lowercase the value in-place, use [`make_ascii_lowercase`].
353+
///
354+
/// [`make_ascii_lowercase`]: str::make_ascii_lowercase
355+
pub fn to_ascii_lowercase(&self) -> Result<CString, AllocError> {
356+
let mut s = self.to_cstring()?;
357+
358+
s.make_ascii_lowercase();
359+
360+
Ok(s)
361+
}
362+
363+
/// Returns a copy of this [`CString`] where each character is mapped to its
364+
/// ASCII upper case equivalent.
365+
///
366+
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
367+
/// but non-ASCII letters are unchanged.
368+
///
369+
/// To uppercase the value in-place, use [`make_ascii_uppercase`].
370+
///
371+
/// [`make_ascii_uppercase`]: str::make_ascii_uppercase
372+
pub fn to_ascii_uppercase(&self) -> Result<CString, AllocError> {
373+
let mut s = self.to_cstring()?;
374+
375+
s.make_ascii_uppercase();
376+
377+
Ok(s)
378+
}
302379
}
303380

304381
impl fmt::Display for CStr {
@@ -764,6 +841,14 @@ impl Deref for CString {
764841
}
765842
}
766843

844+
impl DerefMut for CString {
845+
fn deref_mut(&mut self) -> &mut Self::Target {
846+
// SAFETY: A `CString` is always NUL-terminated and contains no other
847+
// NUL bytes.
848+
unsafe { CStr::from_bytes_with_nul_unchecked_mut(self.buf.as_mut_slice()) }
849+
}
850+
}
851+
767852
impl<'a> TryFrom<&'a CStr> for CString {
768853
type Error = AllocError;
769854

0 commit comments

Comments
 (0)