Skip to content

Commit bbb9b6e

Browse files
committed
avoid iterating from LenT::MAX down for truncation
1 parent 08e6257 commit bbb9b6e

File tree

1 file changed

+37
-3
lines changed

1 file changed

+37
-3
lines changed

src/string.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use alloc::{
22
borrow::{Cow, ToOwned},
33
boxed::Box,
4-
string::{String},
4+
string::String,
55
sync::Arc,
66
};
77
use core::{borrow::Borrow, hash::Hash, str::FromStr};
@@ -29,13 +29,17 @@ fn truncate_string(err: InvalidStrLength, max_len: usize) -> String {
2929

3030
#[cold]
3131
fn truncate_str(string: &str, max_len: usize) -> &str {
32+
if string.len() <= max_len {
33+
return string;
34+
}
35+
3236
for len in (0..=max_len).rev() {
3337
if string.is_char_boundary(len) {
3438
return &string[..len];
3539
}
3640
}
3741

38-
unreachable!("Len 0 is a char boundary")
42+
unreachable!("Len 0 is a char boundary");
3943
}
4044

4145
/// A fixed size String with length provided at creation denoted in [`ValidLength`], by default [`u32`].
@@ -93,7 +97,7 @@ impl<LenT: ValidLength> FixedString<LenT> {
9397
/// For lossless fallible conversion, convert to [`Box<str>`] using [`String::into_boxed_str`] and use [`TryFrom`].
9498
#[must_use]
9599
pub fn from_string_trunc(str: String) -> Self {
96-
match str.into_boxed_str().try_into() {
100+
match str.try_into() {
97101
Ok(val) => val,
98102
Err(err) => Self::from_string_trunc(truncate_string(err, LenT::MAX.to_usize())),
99103
}
@@ -438,6 +442,21 @@ mod test {
438442
}
439443
}
440444

445+
// primarily intended to ensure no hangs occur
446+
fn check_u32_partial_roundtrip_generic(to_fixed: fn(String) -> FixedString<u32>) {
447+
for i in 0..=400u32 {
448+
let original = "a".repeat(i as usize);
449+
let fixed = to_fixed(original);
450+
451+
assert!(fixed.bytes().all(|c| c == b'a'));
452+
assert_eq!(fixed.len(), i);
453+
454+
if !fixed.is_static() {
455+
assert_eq!(fixed.is_inline(), fixed.len() <= 12);
456+
}
457+
}
458+
}
459+
441460
#[test]
442461
fn test_truncating_behaviour() {
443462
const STR: &str = "______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________🦀";
@@ -482,6 +501,21 @@ mod test {
482501
});
483502
}
484503

504+
#[test]
505+
fn check_u32_partial_roundtrip() {
506+
check_u32_partial_roundtrip_generic(|original| {
507+
FixedString::<u32>::try_from(original).unwrap()
508+
});
509+
}
510+
511+
#[test]
512+
fn check_u32_partial_roundtrip_static() {
513+
check_u32_partial_roundtrip_generic(|original| {
514+
let static_str = Box::leak(original.into_boxed_str());
515+
FixedString::from_static_trunc(static_str)
516+
});
517+
}
518+
485519
#[test]
486520
#[cfg(feature = "serde")]
487521
fn check_u8_roundtrip_serde() {

0 commit comments

Comments
 (0)