Skip to content

Commit 04256e4

Browse files
authored
impl From<char> for FixedString (#9)
1 parent fc8b925 commit 04256e4

File tree

2 files changed

+97
-5
lines changed

2 files changed

+97
-5
lines changed

src/inline.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,35 @@ impl<StrRepr: Copy + AsRef<[u8]> + AsMut<[u8]> + Default + TypeSize> InlineStrin
6363
StrRepr::default().as_ref().len()
6464
}
6565

66-
pub fn from_str(val: &str) -> Option<Self> {
66+
#[inline]
67+
fn from_len_and_write(len: usize, write: impl FnOnce(&mut [u8])) -> Option<Self> {
6768
let mut arr = StrRepr::default();
68-
if val.len() > size_of::<Self>() {
69+
if len > size_of::<Self>() {
6970
return None;
7071
}
7172

72-
arr.as_mut()[..val.len()].copy_from_slice(val.as_bytes());
73+
write(arr.as_mut());
7374

74-
if val.len() != Self::max_len() {
75+
if len != Self::max_len() {
7576
// 0xFF terminate the string, to gain an extra inline character
76-
arr.as_mut()[val.len()] = Self::TERMINATOR;
77+
arr.as_mut()[len] = Self::TERMINATOR;
7778
}
7879

7980
Some(Self { arr })
8081
}
8182

83+
pub fn from_str(val: &str) -> Option<Self> {
84+
Self::from_len_and_write(val.len(), |arr| {
85+
arr[..val.len()].copy_from_slice(val.as_bytes());
86+
})
87+
}
88+
89+
pub fn from_char(val: char) -> Option<Self> {
90+
Self::from_len_and_write(val.len_utf8(), |arr| {
91+
val.encode_utf8(arr);
92+
})
93+
}
94+
8295
pub fn len(&self) -> u8 {
8396
// Copy to a temporary, 16 byte array to allow for SIMD impl.
8497
let mut buf = [0_u8; 16];

src/string.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,26 @@ impl<LenT: ValidLength> TryFrom<String> for FixedString<LenT> {
294294
}
295295
}
296296

297+
impl<LenT: ValidLength> From<char> for FixedString<LenT> {
298+
fn from(value: char) -> Self {
299+
use alloc::vec;
300+
301+
if let Some(value) = InlineString::from_char(value) {
302+
return Self(FixedStringRepr::Inline(value));
303+
}
304+
305+
let mut bytes = vec![0; value.len_utf8()].into_boxed_slice();
306+
307+
value.encode_utf8(&mut bytes);
308+
309+
let bytes = bytes
310+
.try_into()
311+
.expect("len_utf8 is at most 4, so it will fit in u8");
312+
313+
Self(FixedStringRepr::Heap(bytes))
314+
}
315+
}
316+
297317
impl<LenT: ValidLength> From<FixedString<LenT>> for String {
298318
fn from(value: FixedString<LenT>) -> Self {
299319
match value.0 {
@@ -474,4 +494,63 @@ mod test {
474494
assert_eq!(core::mem::size_of::<FixedStringRepr<u32>>(), 13);
475495
assert_eq!(core::mem::align_of::<FixedStringRepr<u32>>(), 1);
476496
}
497+
498+
#[test]
499+
fn from_char_u8() {
500+
let s: FixedString<u8> = 'a'.into();
501+
assert_eq!(s.len(), 1);
502+
assert!(s.is_inline());
503+
504+
let s: FixedString<u8> = '¼'.into();
505+
assert_eq!(s.len(), 2);
506+
assert!(s.is_inline());
507+
508+
let s: FixedString<u8> = '⚡'.into();
509+
assert_eq!(s.len(), 3);
510+
assert!(s.is_inline());
511+
512+
let s: FixedString<u8> = '🦀'.into();
513+
assert_eq!(s.len(), 4);
514+
#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
515+
assert!(s.is_inline());
516+
}
517+
518+
#[test]
519+
fn from_char_u16() {
520+
let s: FixedString<u16> = 'a'.into();
521+
assert_eq!(s.len(), 1);
522+
assert!(s.is_inline());
523+
524+
let s: FixedString<u16> = '¼'.into();
525+
assert_eq!(s.len(), 2);
526+
assert!(s.is_inline());
527+
528+
let s: FixedString<u16> = '⚡'.into();
529+
assert_eq!(s.len(), 3);
530+
assert!(s.is_inline());
531+
532+
let s: FixedString<u16> = '🦀'.into();
533+
assert_eq!(s.len(), 4);
534+
assert!(s.is_inline());
535+
}
536+
537+
#[test]
538+
#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
539+
fn from_char_u32() {
540+
let s: FixedString<u32> = 'a'.into();
541+
assert_eq!(s.len(), 1);
542+
assert!(s.is_inline());
543+
544+
let s: FixedString<u32> = '¼'.into();
545+
assert_eq!(s.len(), 2);
546+
assert!(s.is_inline());
547+
548+
let s: FixedString<u32> = '⚡'.into();
549+
assert_eq!(s.len(), 3);
550+
assert!(s.is_inline());
551+
552+
let s: FixedString<u32> = '🦀'.into();
553+
assert_eq!(s.len(), 4);
554+
assert!(s.is_inline());
555+
}
477556
}

0 commit comments

Comments
 (0)