Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created March 1, 2023 01:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rust-play/2932a1418a564562e219597484669e1a to your computer and use it in GitHub Desktop.
Save rust-play/2932a1418a564562e219597484669e1a to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
pub trait TrimInPlace {
fn trim_in_place(&mut self) -> usize;
fn trim_start_in_place(&mut self) -> usize;
fn trim_end_in_place(&mut self) -> usize;
}
type SmartString = smartstring::alias::String;
/// # Safety
///
/// The output of trim_fn must be a substring of the input, absolutely no longer than the original.
#[inline]
unsafe fn trim_by_copy_zero<'p, F>(string: &'p mut SmartString, trim_fn: F) -> usize
where
F: FnOnce(&str) -> &str,
F: 'p,
{
let orig_len = string.len();
let start = string.as_mut_ptr();
let trimmed = trim_fn(string);
let trimmed_ptr = trimmed.as_ptr();
let trimmed_len = trimmed.len();
// Vital to ensure we don't write past the end
let diff = orig_len - trimmed_len;
if diff != 0 {
// Safety: trimmed_start and start_of_buf here are both valid for new_len bytes.
// core::ptr::copy allows copying between overlapping regions, like libc::memmove.
unsafe {
core::ptr::copy(trimmed_ptr, start, trimmed_len);
// Ensure there's a char boundary after `len` bytes, so truncate doesn't panic.
// Truncate is satisfied if a single byte at [len] is valid UTF-8. So we write one
// single-byte character.
*start.add(trimmed_len) = 0; // 0x00 is a valid UTF-8 character
}
string.truncate(trimmed_len);
}
diff
}
impl TrimInPlace for SmartString {
fn trim_in_place(&mut self) -> usize {
unsafe { trim_by_copy_zero(self, str::trim) }
}
fn trim_start_in_place(&mut self) -> usize {
unsafe { trim_by_copy_zero(self, str::trim_start) }
}
fn trim_end_in_place(&mut self) -> usize {
// Nothing special here.
let orig_len = self.len();
let trimmed_len = self.trim_end().len();
self.truncate(trimmed_len);
orig_len - trimmed_len
}
}
#[test]
fn smartstring_multibyte() {
let mut string = SmartString::from(" aé");
assert_eq!(string.trim_in_place(), 1);
assert_eq!(string, "aé");
assert_eq!(string.trim_in_place(), 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment