-
-
Save rust-play/2932a1418a564562e219597484669e1a to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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