diff --git a/benches/arraystring.rs b/benches/arraystring.rs index 5b986fa..8bf5786 100644 --- a/benches/arraystring.rs +++ b/benches/arraystring.rs @@ -12,7 +12,7 @@ fn try_push_c(b: &mut Bencher) { v.clear(); while v.try_push('c').is_ok() { } - v.len() + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } @@ -23,7 +23,7 @@ fn try_push_alpha(b: &mut Bencher) { v.clear(); while v.try_push('α').is_ok() { } - v.len() + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } @@ -39,7 +39,7 @@ fn try_push_string(b: &mut Bencher) { break; } } - v.len() + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } @@ -51,7 +51,7 @@ fn push_c(b: &mut Bencher) { while !v.is_full() { v.push('c'); } - v.len() + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } @@ -63,7 +63,7 @@ fn push_alpha(b: &mut Bencher) { while !v.is_full() { v.push('α'); } - v.len() + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } @@ -80,11 +80,37 @@ fn push_string(b: &mut Bencher) { break; } } - v.len() + std::hint::black_box(v) + }); + b.bytes = v.capacity() as u64; +} + +fn try_extend_bench(b: &mut Bencher) { + let mut v = ArrayString::<4096>::new(); + b.iter(|| { + v.clear(); + + v.try_extend(std::iter::repeat('a').take(v.capacity())).unwrap(); + + std::hint::black_box(v); + }); + b.bytes = v.capacity() as u64; +} + +fn try_push_loop(b: &mut Bencher) { + let mut v = ArrayString::<4096>::new(); + b.iter(|| { + v.clear(); + + for c in std::iter::repeat('a').take(v.capacity()) { + v.try_push(c).unwrap(); + } + + std::hint::black_box(v) }); b.bytes = v.capacity() as u64; } benchmark_group!(benches, try_push_c, try_push_alpha, try_push_string, push_c, - push_alpha, push_string); + push_alpha, push_string, try_extend_bench, try_push_loop); benchmark_main!(benches); diff --git a/src/array_string.rs b/src/array_string.rs index 227e01d..09784ee 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -295,6 +295,36 @@ impl ArrayString Ok(()) } + pub fn try_extend>(&mut self, value: I) -> Result<(), CapacityError<()>> { + let mut len = self.len(); + let value = value.into_iter(); + if value.size_hint().0 > self.capacity() - len { + return Err(CapacityError::new(())); + } + + unsafe { + let mut ptr = self.as_mut_ptr().add(self.len()); + for c in value { + let remaining_cap = self.capacity() - len; + match encode_utf8(c, ptr, remaining_cap) { + Ok(n) => { + len += n; + ptr = ptr.add(n); + } + Err(_) => return Err(CapacityError::new(())), + } + } + self.set_len(len); + Ok(()) + } + } + + pub fn try_from_iterator>(value: I) -> Result> { + let mut string = Self::new(); + string.try_extend(value)?; + Ok(string) + } + /// Removes the last character from the string and returns it. /// /// Returns `None` if this `ArrayString` is empty. diff --git a/tests/tests.rs b/tests/tests.rs index ff779ba..e979759 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -774,3 +774,28 @@ fn test_arraystring_zero_filled_has_some_sanity_checks() { assert_eq!(string.as_str(), "\0\0\0\0"); assert_eq!(string.len(), 4); } + +#[test] +fn test_string_collect() { + let text = "hello world"; + let u = ArrayString::<11>::try_from_iterator(text.chars()).unwrap(); + assert_eq!(u.as_str(), text); + assert_eq!(u.len(), text.len()); +} + +#[test] +fn test_string_collect_seveal_times() { + let text = "hello world"; + let mut u = ArrayString::<22>::try_from_iterator(text.chars()).unwrap(); + u.try_extend(text.chars()).unwrap(); + assert_eq!(u.as_str(), &format!("{}{}", text, text)); + assert_eq!(u.len(), text.len()*2); +} + + +#[test] +fn test_string_collect_error_on_overflow() { + let text = "hello world"; + ArrayString::<10>::try_from_iterator(text.chars()).unwrap_err(); +} +