@@ -66,23 +66,33 @@ pub struct StuffedStr<'a> {
6666unsafe impl < ' a > Send for StuffedStr < ' a > { }
6767unsafe impl < ' a > Sync for StuffedStr < ' a > { }
6868
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+
6985impl < ' a > StuffedStr < ' a > {
7086 const DATA_MASK : usize = !Self :: LEN_MASK ;
7187 const LEN_MASK : usize = !0 << 16 ;
7288
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 {
8290 // Make sure there's enough room to store the data.
8391 if str. len ( ) . leading_zeros ( ) < 16 {
84- panic ( ) ;
92+ str = truncate ( str, Self :: LEN_MASK >> 16 ) ;
93+ debug_assert ! ( str . len( ) . leading_zeros( ) < 16 ) ;
8594 }
95+ let ptr = str. as_ptr ( ) ;
8696 let meta = data as usize | str. len ( ) << 16 ;
8797 Self {
8898 ptr,
@@ -202,3 +212,18 @@ macro_rules! define_label {
202212 }
203213 } ;
204214}
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