@@ -66,23 +66,33 @@ pub struct StuffedStr<'a> {
66
66
unsafe impl < ' a > Send for StuffedStr < ' a > { }
67
67
unsafe impl < ' a > Sync for StuffedStr < ' a > { }
68
68
69
+ /// Truncates the passed string slice to be of length `len`, or shorter.
70
+ #[ cold]
71
+ #[ inline( never) ]
72
+ fn truncate ( str : & str , mut len : usize ) -> & str {
73
+ // Just keep lowering the expected length until we hit a unicode boundary.
74
+ // This is messy but if the string is long enough that we need to truncate it,
75
+ // it's too long for anyone to notice what the end looks like.
76
+ loop {
77
+ if let Some ( str) = str. get ( ..len) {
78
+ break str;
79
+ }
80
+ // In practice this won't be able to underflow, since `str.get(..0)` will always succeed.
81
+ len -= 1 ;
82
+ }
83
+ }
84
+
69
85
impl < ' a > StuffedStr < ' a > {
70
86
const DATA_MASK : usize = !Self :: LEN_MASK ;
71
87
const LEN_MASK : usize = !0 << 16 ;
72
88
73
- pub fn new ( str : & ' a str , data : u16 ) -> Self {
74
- #[ cold]
75
- #[ inline( never) ]
76
- fn panic ( ) -> ! {
77
- // needs a better message but its late
78
- panic ! ( "string exceeds {} bytes" , StuffedStr :: LEN_MASK >> 16 ) ;
79
- }
80
-
81
- let ptr = str. as_ptr ( ) ;
89
+ pub fn new ( mut str : & ' a str , data : u16 ) -> Self {
82
90
// Make sure there's enough room to store the data.
83
91
if str. len ( ) . leading_zeros ( ) < 16 {
84
- panic ( ) ;
92
+ str = truncate ( str, Self :: LEN_MASK >> 16 ) ;
93
+ debug_assert ! ( str . len( ) . leading_zeros( ) < 16 ) ;
85
94
}
95
+ let ptr = str. as_ptr ( ) ;
86
96
let meta = data as usize | str. len ( ) << 16 ;
87
97
Self {
88
98
ptr,
@@ -202,3 +212,18 @@ macro_rules! define_label {
202
212
}
203
213
} ;
204
214
}
215
+
216
+ #[ cfg( test) ]
217
+ mod tests {
218
+ use super :: * ;
219
+
220
+ #[ test]
221
+ fn test_truncate ( ) {
222
+ // Slice at byte '4'
223
+ assert_eq ! ( truncate( "Hello, World!" , 4 ) , "Hell" ) ;
224
+
225
+ // Slicing off at byte '3' would be inside of the emoji,
226
+ // so instead the whole emoji gets sliced off.
227
+ assert_eq ! ( truncate( "x😂" , 3 ) , "x" ) ;
228
+ }
229
+ }
0 commit comments