flexible_string/lib.rs
1//! A stack heap flexible string designed to improve performance.
2//!
3//! [`FlexibleString`] has a fixed stack buffer of the given bytes, and
4//! automatically upgrades to [`String`] when more space is needed. It provides
5//! APIs that are as consistent as possible with [`String`], but some APIs are
6//! not yet implemented or cannot be implemented.
7//!
8//! [`FlexibleString`] was first implemented in [spdlog-rs] crate, which
9//! improved performance for [spdlog-rs] by about double
10//! (see [benchmarks of spdlog-rs]). Now it is extracted to a separate crate for
11//! use by other crates.
12//!
13//! # Benchmarks
14//!
15//! See [section Benchmarks] of the README for this repository.
16//!
17//! # Examples
18//!
19//! ```
20//! use flexible_string::FlexibleString;
21//!
22//! let mut string = FlexibleString::<250>::from("hello");
23//! string.push(',');
24//! string.push_str("world");
25//! assert_eq!(string, "hello,world");
26//! ```
27//!
28//! [spdlog-rs]: https://crates.io/crates/spdlog-rs
29//! [benchmarks of spdlog-rs]: https://github.com/SpriteOvO/spdlog-rs#benchmarks
30//! [section Benchmarks]: https://github.com/SpriteOvO/flexible-string#benchmarks
31
32#![warn(missing_docs)]
33
34use std::{ffi::OsStr, fmt, mem::MaybeUninit, ops, ptr, slice, str, string};
35
36// The following implementations are referenced from :
37// https://github.com/rust-lang/rust/blob/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/alloc/src/string.rs
38
39/// A possible error value when converting a `FlexibleString` from a UTF-8 byte vector.
40///
41/// This type is the error type for the [`from_utf8`] method on [`FlexibleString`]. It
42/// is designed in such a way to carefully avoid reallocations: the
43/// [`into_bytes`] method will give back the byte vector that was used in the
44/// conversion attempt.
45///
46/// [`from_utf8`]: FlexibleString::from_utf8
47/// [`into_bytes`]: FromUtf8Error::into_bytes
48///
49/// The [`Utf8Error`] type provided by [`std::str`] represents an error that may
50/// occur when converting a slice of [`u8`]s to a [`&str`]. In this sense, it's
51/// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error`
52/// through the [`utf8_error`] method.
53///
54/// [`Utf8Error`]: str::Utf8Error "std::str::Utf8Error"
55/// [`std::str`]: core::str "std::str"
56/// [`&str`]: prim@str "&str"
57/// [`utf8_error`]: FromUtf8Error::utf8_error
58///
59/// # Examples
60///
61/// Basic usage:
62///
63/// ```
64/// use flexible_string::FlexibleString;
65///
66/// // some invalid bytes, in a vector
67/// let bytes = vec![0, 159];
68///
69/// let value = FlexibleString::<200>::from_utf8(bytes);
70///
71/// assert!(value.is_err());
72/// assert_eq!(vec![0, 159], value.unwrap_err().into_bytes());
73/// ```
74// We implement it manually because the fields in std are private.
75#[derive(Clone, Debug, PartialEq, Eq)]
76pub struct FromUtf8Error {
77 bytes: Vec<u8>,
78 error: str::Utf8Error,
79}
80
81/// A stack heap flexible string, which first uses a fixed size stack buffer of
82/// `CAPACITY` bytes and automatically upgrades to a heap buffer (`String`)
83/// when more space is needed.
84///
85/// It provides APIs that are as consistent as possible with `String`, but
86/// some APIs are not yet implemented or cannot be implemented. For implemented
87/// methods, the documentation and examples of standard `String` apply to it as
88/// well.
89#[derive(Clone)]
90pub struct FlexibleString<const CAPACITY: usize>(FlexibleStringInner<CAPACITY>);
91
92#[derive(Clone)]
93enum FlexibleStringInner<const CAPACITY: usize> {
94 Stack(StackString<CAPACITY>),
95 Heap(String),
96}
97
98macro_rules! common_methods_inner {
99 (NEVER_UPGRADE => fn_name:$fn_name:ident, generics:$(<$generics:tt>)?, self_qual:$([$($self_qual:tt)*])?, self:$self:ident, arg_name:[$($arg_name:ident),*]) => {
100 match $($($self_qual)*)? $self.0 {
101 FlexibleStringInner::Stack(s) => s.$fn_name $(::<$generics>)? ($($arg_name),*),
102 FlexibleStringInner::Heap(h) => h.$fn_name $(::<$generics>)? ($($arg_name),*),
103 }
104 };
105 (MAYBE_UPGRADE => fn_name:$fn_name:ident, generics:$(<$generics:tt>)?, self_qual:$([$($self_qual:tt)*])?, self:$self:ident, arg_name:[$($arg_name:ident),*]) => {
106 match $($($self_qual)*)? $self.0 {
107 FlexibleStringInner::Stack(s) => {
108 match s.$fn_name $(::<$generics>)? ($($arg_name),*) {
109 Err(capacity) => {
110 let mut heap = s.to_heap(capacity);
111 let res = heap.$fn_name($($arg_name),*);
112 *$self = Self(FlexibleStringInner::Heap(heap));
113 res
114 },
115 Ok(res) => res
116 }
117 },
118 FlexibleStringInner::Heap(h) => h.$fn_name $(::<$generics>)? ($($arg_name),*),
119 }
120 };
121}
122
123macro_rules! common_methods {
124 () => {};
125 ( $(#[$attr:meta])*
126 $upgrade:ident => $vis:vis $([$($qual:tt)*])? fn $fn_name:ident $(<$generics:tt>)? ( $([$($self_qual:tt)*])? $self:ident $(,)? $( $arg_name:ident: $arg_type:ty),* ) $(-> $ret:ty)?
127 $(where $($where_ty:ty: $where_bound:path)*)?; $($tail:tt)* ) => {
128 $(#[$attr])*
129 #[inline]
130 $vis $($($qual)*)? fn $fn_name $(<$generics>)? ($($($self_qual)*)? $self, $($arg_name: $arg_type),*) $(-> $ret)?
131 $(where $($where_ty: $where_bound)*)? {
132 common_methods_inner!($upgrade => fn_name:$fn_name, generics:$(<$generics>)?, self_qual:$([$($self_qual)*])?, self:$self, arg_name:[$($arg_name),*])
133 }
134 common_methods!($($tail)*);
135 };
136}
137
138impl<const CAPACITY: usize> FlexibleString<CAPACITY> {
139 /// Creates a new empty `FlexibleString`.
140 ///
141 /// # Examples
142 ///
143 /// Basic usage:
144 ///
145 /// ```
146 /// use flexible_string::FlexibleString;
147 ///
148 /// let s = FlexibleString::<200>::new();
149 /// ```
150 #[inline]
151 #[must_use]
152 pub fn new() -> Self {
153 Self(FlexibleStringInner::Stack(StackString::new()))
154 }
155
156 /// Creates a new empty `FlexibleString` with a particular capacity.
157 ///
158 /// # Examples
159 ///
160 /// Basic usage:
161 ///
162 /// ```
163 /// use flexible_string::FlexibleString;
164 ///
165 /// let mut s = FlexibleString::<200>::with_capacity(10);
166 ///
167 /// // The FlexibleString contains no chars, even though it has capacity for more
168 /// assert_eq!(s.len(), 0);
169 ///
170 /// // These are all done without reallocating...
171 /// let cap = s.capacity();
172 /// for _ in 0..10 {
173 /// s.push('a');
174 /// }
175 ///
176 /// assert_eq!(s.capacity(), cap);
177 ///
178 /// // ...but this may make the string reallocate
179 /// s.push('a');
180 /// ```
181 #[inline]
182 #[must_use]
183 pub fn with_capacity(capacity: usize) -> Self {
184 if capacity > CAPACITY {
185 Self(FlexibleStringInner::Heap(String::with_capacity(capacity)))
186 } else {
187 Self(FlexibleStringInner::Stack(StackString::new()))
188 }
189 }
190
191 /// Converts a vector of bytes to a `FlexibleString`.
192 ///
193 /// # Examples
194 ///
195 /// Basic usage:
196 ///
197 /// ```
198 /// use flexible_string::FlexibleString;
199 ///
200 /// // some bytes, in a vector
201 /// let sparkle_heart = vec![240, 159, 146, 150];
202 ///
203 /// // We know these bytes are valid, so we'll use `unwrap()`.
204 /// let sparkle_heart = FlexibleString::<200>::from_utf8(sparkle_heart).unwrap();
205 ///
206 /// assert_eq!("💖", sparkle_heart);
207 /// ```
208 ///
209 /// Incorrect bytes:
210 ///
211 /// ```
212 /// use flexible_string::FlexibleString;
213 ///
214 /// // some invalid bytes, in a vector
215 /// let sparkle_heart = vec![0, 159, 146, 150];
216 ///
217 /// assert!(FlexibleString::<200>::from_utf8(sparkle_heart).is_err());
218 /// ```
219 #[inline]
220 pub fn from_utf8(vec: Vec<u8>) -> Result<Self, FromUtf8Error> {
221 if vec.len() > CAPACITY {
222 String::from_utf8(vec)
223 .map(|s| Self(FlexibleStringInner::Heap(s)))
224 .map_err(|err| err.into())
225 } else {
226 unsafe { StackString::from_utf8_vec_only_len_unchecked(vec) }
227 .map(|s| Self(FlexibleStringInner::Stack(s)))
228 }
229 }
230
231 // Unimplemented.
232 // pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {}
233
234 // Unimplemented.
235 // pub fn from_utf16(v: &[u16]) -> Result<Self, FromUtf16Error> {}
236
237 // Unimplemented.
238 // pub fn from_utf16_lossy(v: &[u16]) -> Self {}
239
240 // Unimplemented since unstable.
241 // pub fn into_raw_parts(self) -> (*mut u8, usize, usize)
242
243 // Unimplemented since unstable.
244 // pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String
245
246 /// Converts a vector of bytes to a `FlexibleString` without checking that the
247 /// string contains valid UTF-8.
248 ///
249 /// # Safety
250 ///
251 /// See the documentation of [`String::from_utf8_unchecked`].
252 ///
253 /// # Examples
254 ///
255 /// Basic usage:
256 ///
257 /// ```
258 /// use flexible_string::FlexibleString;
259 ///
260 /// // some bytes, in a vector
261 /// let sparkle_heart = vec![240, 159, 146, 150];
262 ///
263 /// let sparkle_heart = unsafe {
264 /// FlexibleString::<200>::from_utf8_unchecked(sparkle_heart)
265 /// };
266 ///
267 /// assert_eq!("💖", sparkle_heart);
268 /// ```
269 #[inline]
270 #[must_use]
271 pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> Self {
272 if bytes.len() > CAPACITY {
273 Self(FlexibleStringInner::Heap(String::from_utf8_unchecked(
274 bytes,
275 )))
276 } else {
277 Self(FlexibleStringInner::Stack(
278 StackString::from_utf8_slice_unchecked(&bytes),
279 ))
280 }
281 }
282
283 common_methods! {
284 /// Converts a `FlexibleString` into a byte vector.
285 ///
286 /// # Examples
287 ///
288 /// Basic usage:
289 ///
290 /// ```
291 /// use flexible_string::FlexibleString;
292 ///
293 /// let s = FlexibleString::<200>::from("hello");
294 /// let bytes = s.into_bytes();
295 ///
296 /// assert_eq!(&[104, 101, 108, 108, 111][..], &bytes[..]);
297 /// ```
298 #[must_use = "`self` will be dropped if the result is not used"]
299 NEVER_UPGRADE => pub fn into_bytes(self) -> Vec<u8>;
300
301 /// Extracts a string slice containing the entire `FlexibleString`.
302 ///
303 /// # Examples
304 ///
305 /// Basic usage:
306 ///
307 /// ```
308 /// use flexible_string::FlexibleString;
309 ///
310 /// let s = FlexibleString::<200>::from("foo");
311 ///
312 /// assert_eq!("foo", s.as_str());
313 /// ```
314 #[must_use]
315 NEVER_UPGRADE => pub fn as_str([&]self) -> &str;
316
317 /// Converts a `FlexibleString` into a mutable string slice.
318 ///
319 /// # Examples
320 ///
321 /// Basic usage:
322 ///
323 /// ```
324 /// use flexible_string::FlexibleString;
325 ///
326 /// let mut s = FlexibleString::<200>::from("foobar");
327 /// let s_mut_str = s.as_mut_str();
328 ///
329 /// s_mut_str.make_ascii_uppercase();
330 ///
331 /// assert_eq!("FOOBAR", s_mut_str);
332 /// ```
333 #[must_use]
334 NEVER_UPGRADE => pub fn as_mut_str([&mut]self) -> &mut str;
335
336 /// Appends a given string slice onto the end of this `FlexibleString`.
337 ///
338 /// # Examples
339 ///
340 /// Basic usage:
341 ///
342 /// ```
343 /// use flexible_string::FlexibleString;
344 ///
345 /// let mut s = FlexibleString::<200>::from("foo");
346 ///
347 /// s.push_str("bar");
348 ///
349 /// assert_eq!("foobar", s);
350 /// ```
351 MAYBE_UPGRADE => pub fn push_str([&mut]self, string: &str);
352
353 // Unimplemented since unstable.
354 // pub fn extend_from_within<R>(&mut self, src: R)
355
356 /// Returns this `FlexibleString`'s capacity, in bytes.
357 ///
358 /// # Examples
359 ///
360 /// Basic usage:
361 ///
362 /// ```
363 /// use flexible_string::FlexibleString;
364 ///
365 /// let s = FlexibleString::<200>::with_capacity(10);
366 ///
367 /// assert!(s.capacity() >= 10);
368 /// ```
369 NEVER_UPGRADE => pub fn capacity([&]self) -> usize;
370
371 /// Ensures that this `FlexibleString`'s capacity is at least `additional` bytes
372 /// larger than its length.
373 ///
374 /// # Examples
375 ///
376 /// Basic usage:
377 ///
378 /// ```
379 /// use flexible_string::FlexibleString;
380 ///
381 /// let mut s = FlexibleString::<200>::new();
382 ///
383 /// s.reserve(10);
384 ///
385 /// assert!(s.capacity() >= 10);
386 /// ```
387 ///
388 /// This might not actually increase the capacity:
389 ///
390 /// ```
391 /// use flexible_string::FlexibleString;
392 ///
393 /// let mut s = FlexibleString::<200>::with_capacity(10);
394 /// s.push('a');
395 /// s.push('b');
396 ///
397 /// // s now has a length of 2 and a capacity of 10
398 /// assert_eq!(2, s.len());
399 /// assert!(s.capacity() >= 10);
400 ///
401 /// // Since we already have an extra 8 capacity, calling this...
402 /// s.reserve(8);
403 ///
404 /// // ... doesn't actually increase.
405 /// assert!(s.capacity() >= 10);
406 /// ```
407 MAYBE_UPGRADE => pub fn reserve([&mut]self, additional: usize);
408
409 /// Ensures that this `FlexibleString`'s capacity is `additional` bytes
410 /// larger than its length.
411 ///
412 /// # Examples
413 ///
414 /// Basic usage:
415 ///
416 /// ```
417 /// use flexible_string::FlexibleString;
418 ///
419 /// let mut s = FlexibleString::<200>::new();
420 ///
421 /// s.reserve_exact(10);
422 ///
423 /// assert!(s.capacity() >= 10);
424 /// ```
425 ///
426 /// This might not actually increase the capacity:
427 ///
428 /// ```
429 /// use flexible_string::FlexibleString;
430 ///
431 /// let mut s = FlexibleString::<200>::with_capacity(10);
432 /// s.push('a');
433 /// s.push('b');
434 ///
435 /// // s now has a length of 2 and a capacity of 10
436 /// assert_eq!(2, s.len());
437 /// assert!(s.capacity() >= 10);
438 ///
439 /// // Since we already have an extra 8 capacity, calling this...
440 /// s.reserve_exact(8);
441 ///
442 /// // ... doesn't actually increase.
443 /// assert!(s.capacity() >= 10);
444 /// ```
445 MAYBE_UPGRADE => pub fn reserve_exact([&mut]self, additional: usize);
446
447 // Unimplemented since `TryReserveErrorKind` is currently unstable.
448 //
449 // /// Tries to reserve capacity for at least `additional` more elements to be inserted
450 // /// in the given `FlexibleString`. The collection may reserve more space to avoid
451 // /// frequent reallocations. After calling `reserve`, capacity will be
452 // /// greater than or equal to `self.len() + additional`. Does nothing if
453 // /// capacity is already sufficient.
454 // ///
455 // /// # Examples
456 // ///
457 // /// ```
458 // /// use flexible_string::FlexibleString;
459 // ///
460 // /// use std::collections::TryReserveError;
461 // ///
462 // /// fn process_data(data: &str) -> Result<FlexibleString::<200>, TryReserveError> {
463 // /// let mut output = FlexibleString::<200>::new();
464 // ///
465 // /// // Pre-reserve the memory, exiting if we can't
466 // /// output.try_reserve(data.len())?;
467 // ///
468 // /// // Now we know this can't OOM in the middle of our complex work
469 // /// output.push_str(data);
470 // ///
471 // /// Ok(output)
472 // /// }
473 // /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?");
474 // /// ```
475 // MAYBE_UPGRADE => pub fn try_reserve([&mut]self, additional: usize) -> Result<(), TryReserveError>;
476 //
477 // /// Tries to reserve the minimum capacity for exactly `additional` more elements to
478 // /// be inserted in the given `FlexibleString`. After calling `reserve_exact`,
479 // /// capacity will be greater than or equal to `self.len() + additional`.
480 // /// Does nothing if the capacity is already sufficient.
481 // ///
482 // /// # Examples
483 // ///
484 // /// ```
485 // /// use flexible_string::FlexibleString;
486 // ///
487 // /// use std::collections::TryReserveError;
488 // ///
489 // /// fn process_data(data: &str) -> Result<FlexibleString::<200>, TryReserveError> {
490 // /// let mut output = FlexibleString::<200>::new();
491 // ///
492 // /// // Pre-reserve the memory, exiting if we can't
493 // /// output.try_reserve_exact(data.len())?;
494 // ///
495 // /// // Now we know this can't OOM in the middle of our complex work
496 // /// output.push_str(data);
497 // ///
498 // /// Ok(output)
499 // /// }
500 // /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?");
501 // /// ```
502 // MAYBE_UPGRADE => pub fn try_reserve_exact([&mut]self, additional: usize) -> Result<(), TryReserveError>;
503
504 // Cannot be implemented because the stack string cannot ensure the requirement.
505 // pub fn shrink_to_fit(&mut self);
506
507 /// Shrinks the capacity of this `FlexibleString` with a lower bound.
508 ///
509 /// # Examples
510 ///
511 /// ```
512 /// use flexible_string::FlexibleString;
513 ///
514 /// let mut s = FlexibleString::<200>::from("foo");
515 ///
516 /// s.reserve(100);
517 /// assert!(s.capacity() >= 100);
518 ///
519 /// s.shrink_to(10);
520 /// assert!(s.capacity() >= 10);
521 /// s.shrink_to(0);
522 /// assert!(s.capacity() >= 3);
523 /// ```
524 NEVER_UPGRADE => pub fn shrink_to([&mut]self, min_capacity: usize);
525
526 /// Appends the given [`char`] to the end of this `FlexibleString`.
527 ///
528 /// # Examples
529 ///
530 /// Basic usage:
531 ///
532 /// ```
533 /// use flexible_string::FlexibleString;
534 ///
535 /// let mut s = FlexibleString::<200>::from("abc");
536 ///
537 /// s.push('1');
538 /// s.push('2');
539 /// s.push('3');
540 ///
541 /// assert_eq!("abc123", s);
542 /// ```
543 MAYBE_UPGRADE => pub fn push([&mut]self, ch: char);
544
545 /// Returns a byte slice of this `FlexibleString`'s contents.
546 ///
547 /// # Examples
548 ///
549 /// Basic usage:
550 ///
551 /// ```
552 /// use flexible_string::FlexibleString;
553 ///
554 /// let s = FlexibleString::<200>::from("hello");
555 ///
556 /// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());
557 /// ```
558 #[must_use]
559 NEVER_UPGRADE => pub fn as_bytes([&]self) -> &[u8];
560
561 /// Shortens this `FlexibleString` to the specified length.
562 ///
563 /// If `new_len` is greater than the string's current length, this has no
564 /// effect.
565 ///
566 /// Note that this method has no effect on the allocated capacity
567 /// of the string
568 ///
569 /// # Panics
570 ///
571 /// Panics if `new_len` does not lie on a [`char`] boundary.
572 ///
573 /// # Examples
574 ///
575 /// Basic usage:
576 ///
577 /// ```
578 /// use flexible_string::FlexibleString;
579 ///
580 /// let mut s = FlexibleString::<200>::from("hello");
581 ///
582 /// s.truncate(2);
583 ///
584 /// assert_eq!("he", s);
585 /// ```
586 NEVER_UPGRADE => pub fn truncate([&mut]self, new_len: usize);
587
588 /// Removes the last character from the string buffer and returns it.
589 ///
590 /// Returns [`None`] if this `FlexibleString` is empty.
591 ///
592 /// # Examples
593 ///
594 /// Basic usage:
595 ///
596 /// ```
597 /// use flexible_string::FlexibleString;
598 ///
599 /// let mut s = FlexibleString::<200>::from("foo");
600 ///
601 /// assert_eq!(s.pop(), Some('o'));
602 /// assert_eq!(s.pop(), Some('o'));
603 /// assert_eq!(s.pop(), Some('f'));
604 ///
605 /// assert_eq!(s.pop(), None);
606 /// ```
607 NEVER_UPGRADE => pub fn pop([&mut]self) -> Option<char>;
608
609 /// Removes a [`char`] from this `FlexibleString` at a byte position and returns it.
610 ///
611 /// This is an *O*(*n*) operation, as it requires copying every element in the
612 /// buffer.
613 ///
614 /// # Panics
615 ///
616 /// Panics if `idx` is larger than or equal to the `FlexibleString`'s length,
617 /// or if it does not lie on a [`char`] boundary.
618 ///
619 /// # Examples
620 ///
621 /// Basic usage:
622 ///
623 /// ```
624 /// use flexible_string::FlexibleString;
625 ///
626 /// let mut s = FlexibleString::<200>::from("foo");
627 ///
628 /// assert_eq!(s.remove(0), 'f');
629 /// assert_eq!(s.remove(1), 'o');
630 /// assert_eq!(s.remove(0), 'o');
631 /// ```
632 NEVER_UPGRADE => pub fn remove([&mut]self, idx: usize) -> char;
633
634 // Unimplemented.
635 // ...
636
637 /// Inserts a character into this `FlexibleString` at a byte position.
638 ///
639 /// This is an *O*(*n*) operation as it requires copying every element in the
640 /// buffer.
641 ///
642 /// # Panics
643 ///
644 /// Panics if `idx` is larger than the `FlexibleString`'s length, or if it does not
645 /// lie on a [`char`] boundary.
646 ///
647 /// # Examples
648 ///
649 /// Basic usage:
650 ///
651 /// ```
652 /// use flexible_string::FlexibleString;
653 ///
654 /// let mut s = FlexibleString::<200>::with_capacity(3);
655 ///
656 /// s.insert(0, 'f');
657 /// s.insert(1, 'o');
658 /// s.insert(2, 'o');
659 ///
660 /// assert_eq!("foo", s);
661 /// ```
662 MAYBE_UPGRADE => pub fn insert([&mut]self, idx: usize, ch: char);
663
664 /// Inserts a string slice into this `FlexibleString` at a byte position.
665 ///
666 /// This is an *O*(*n*) operation as it requires copying every element in the
667 /// buffer.
668 ///
669 /// # Panics
670 ///
671 /// Panics if `idx` is larger than the `FlexibleString`'s length, or if it does not
672 /// lie on a [`char`] boundary.
673 ///
674 /// # Examples
675 ///
676 /// Basic usage:
677 ///
678 /// ```
679 /// use flexible_string::FlexibleString;
680 ///
681 /// let mut s = FlexibleString::<200>::from("bar");
682 ///
683 /// s.insert_str(0, "foo");
684 ///
685 /// assert_eq!("foobar", s);
686 /// ```
687 MAYBE_UPGRADE => pub fn insert_str([&mut]self, idx: usize, string: &str);
688
689 // Unimplemented.
690 // pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8>
691
692 /// Returns the length of this `FlexibleString`, in bytes, not [`char`]s or
693 /// graphemes. In other words, it might not be what a human considers the
694 /// length of the string.
695 ///
696 /// # Examples
697 ///
698 /// Basic usage:
699 ///
700 /// ```
701 /// use flexible_string::FlexibleString;
702 ///
703 /// let a = FlexibleString::<200>::from("foo");
704 /// assert_eq!(a.len(), 3);
705 ///
706 /// let fancy_f = FlexibleString::<200>::from("Æ’oo");
707 /// assert_eq!(fancy_f.len(), 4);
708 /// assert_eq!(fancy_f.chars().count(), 3);
709 /// ```
710 NEVER_UPGRADE => pub fn len([&]self) -> usize;
711
712 /// Returns `true` if this `FlexibleString` has a length of zero, and `false` otherwise.
713 ///
714 /// # Examples
715 ///
716 /// Basic usage:
717 ///
718 /// ```
719 /// use flexible_string::FlexibleString;
720 ///
721 /// let mut v = FlexibleString::<200>::new();
722 /// assert!(v.is_empty());
723 ///
724 /// v.push('a');
725 /// assert!(!v.is_empty());
726 /// ```
727 NEVER_UPGRADE => pub fn is_empty([&]self) -> bool;
728
729 // Unimplemented.
730 // pub fn split_off(&mut self, at: usize) -> String;
731
732 /// Truncates this `FlexibleString`, removing all contents.
733 ///
734 /// While this means the `FlexibleString` will have a length of zero, it does not
735 /// touch its capacity.
736 ///
737 /// # Examples
738 ///
739 /// Basic usage:
740 ///
741 /// ```
742 /// use flexible_string::FlexibleString;
743 ///
744 /// let mut s = FlexibleString::<200>::from("foo");
745 ///
746 /// s.clear();
747 ///
748 /// assert!(s.is_empty());
749 /// assert_eq!(0, s.len());
750 /// ```
751 NEVER_UPGRADE => pub fn clear([&mut]self);
752
753 // Unimplemented.
754 // pub fn drain<R>(&mut self, range: R) -> Drain<'_>;
755
756 // Unimplemented.
757 // ...
758 }
759}
760
761impl<const CAPACITY: usize> Default for FlexibleString<CAPACITY> {
762 #[inline]
763 fn default() -> Self {
764 Self::new()
765 }
766}
767
768macro_rules! impl_eq {
769 ($lhs:ty, $rhs:ty) => {
770 #[allow(unused_lifetimes)]
771 impl<'a, 'b, const CAPACITY: usize> PartialEq<$rhs> for $lhs {
772 #[inline]
773 fn eq(&self, other: &$rhs) -> bool {
774 PartialEq::eq(&self[..], &other[..])
775 }
776 }
777
778 #[allow(unused_lifetimes)]
779 impl<'a, 'b, const CAPACITY: usize> PartialEq<$lhs> for $rhs {
780 #[inline]
781 fn eq(&self, other: &$lhs) -> bool {
782 PartialEq::eq(&self[..], &other[..])
783 }
784 }
785 };
786}
787
788impl_eq! { FlexibleString<CAPACITY>, str }
789impl_eq! { FlexibleString<CAPACITY>, &'a str }
790impl_eq! { FlexibleString<CAPACITY>, String }
791
792impl<const CAPACITY_LHS: usize, const CAPACITY_RHS: usize> PartialEq<FlexibleString<CAPACITY_RHS>>
793 for FlexibleString<CAPACITY_LHS>
794{
795 #[inline]
796 fn eq(&self, other: &FlexibleString<CAPACITY_RHS>) -> bool {
797 PartialEq::eq(&self[..], &other[..])
798 }
799}
800
801impl<const CAPACITY: usize> AsRef<str> for FlexibleString<CAPACITY> {
802 #[inline]
803 fn as_ref(&self) -> &str {
804 self
805 }
806}
807
808impl<const CAPACITY: usize> AsMut<str> for FlexibleString<CAPACITY> {
809 #[inline]
810 fn as_mut(&mut self) -> &mut str {
811 self
812 }
813}
814
815impl<const CAPACITY: usize> AsRef<[u8]> for FlexibleString<CAPACITY> {
816 #[inline]
817 fn as_ref(&self) -> &[u8] {
818 self.as_bytes()
819 }
820}
821
822impl<const CAPACITY: usize> AsRef<OsStr> for FlexibleString<CAPACITY> {
823 #[inline]
824 fn as_ref(&self) -> &OsStr {
825 (&**self).as_ref()
826 }
827}
828
829impl<const CAPACITY: usize> From<char> for FlexibleString<CAPACITY> {
830 #[inline]
831 fn from(c: char) -> Self {
832 FlexibleString::from(c.encode_utf8(&mut [0; 4]))
833 }
834}
835
836impl<const CAPACITY: usize> From<&str> for FlexibleString<CAPACITY> {
837 #[inline]
838 fn from(s: &str) -> Self {
839 let bytes = s.as_bytes();
840 if bytes.len() > CAPACITY {
841 let owned_bytes = bytes.to_owned();
842 Self(FlexibleStringInner::Heap(unsafe {
843 String::from_utf8_unchecked(owned_bytes)
844 }))
845 } else {
846 Self(FlexibleStringInner::Stack(unsafe {
847 StackString::from_utf8_slice_unchecked(bytes)
848 }))
849 }
850 }
851}
852
853impl<const CAPACITY: usize> From<&mut str> for FlexibleString<CAPACITY> {
854 #[inline]
855 fn from(s: &mut str) -> Self {
856 (s as &str).into()
857 }
858}
859
860impl<const CAPACITY: usize> From<String> for FlexibleString<CAPACITY> {
861 #[inline]
862 fn from(s: String) -> Self {
863 s.as_str().into()
864 }
865}
866
867impl<'a, const CAPACITY: usize> FromIterator<&'a char> for FlexibleString<CAPACITY> {
868 fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> Self {
869 let mut buf = FlexibleString::new();
870 buf.extend(iter);
871 buf
872 }
873}
874
875impl<'a, const CAPACITY: usize> FromIterator<&'a str> for FlexibleString<CAPACITY> {
876 fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {
877 let mut buf = FlexibleString::new();
878 buf.extend(iter);
879 buf
880 }
881}
882
883impl<const CAPACITY_LHS: usize, const CAPACITY_RHS: usize>
884 FromIterator<FlexibleString<CAPACITY_RHS>> for FlexibleString<CAPACITY_LHS>
885{
886 fn from_iter<I: IntoIterator<Item = FlexibleString<CAPACITY_RHS>>>(
887 iter: I,
888 ) -> FlexibleString<CAPACITY_LHS> {
889 let mut buf = FlexibleString::new();
890 buf.extend(iter);
891 buf
892 }
893}
894
895impl<const CAPACITY: usize> FromIterator<char> for FlexibleString<CAPACITY> {
896 fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
897 let mut buf = FlexibleString::new();
898 buf.extend(iter);
899 buf
900 }
901}
902
903impl<const CAPACITY: usize> FromIterator<Box<str>> for FlexibleString<CAPACITY> {
904 fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> Self {
905 let mut buf = FlexibleString::new();
906 buf.extend(iter);
907 buf
908 }
909}
910
911impl<const CAPACITY: usize> Extend<char> for FlexibleString<CAPACITY> {
912 fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
913 let iterator = iter.into_iter();
914 let (lower_bound, _) = iterator.size_hint();
915 self.reserve(lower_bound);
916 iterator.for_each(move |c| self.push(c));
917 }
918
919 // comment out these 2 functions since they are currently unstable.
920
921 // #[inline]
922 // fn extend_one(&mut self, c: char) {
923 // self.push(c);
924 // }
925
926 // #[inline]
927 // fn extend_reserve(&mut self, additional: usize) {
928 // self.reserve(additional);
929 // }
930}
931
932impl<'a, const CAPACITY: usize> Extend<&'a char> for FlexibleString<CAPACITY> {
933 fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
934 self.extend(iter.into_iter().cloned());
935 }
936
937 // comment out these 2 functions since they are currently unstable.
938
939 // #[inline]
940 // fn extend_one(&mut self, &c: &'a char) {
941 // self.push(c);
942 // }
943
944 // #[inline]
945 // fn extend_reserve(&mut self, additional: usize) {
946 // self.reserve(additional);
947 // }
948}
949
950impl<'a, const CAPACITY: usize> Extend<&'a str> for FlexibleString<CAPACITY> {
951 fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
952 iter.into_iter().for_each(move |s| self.push_str(s));
953 }
954
955 // comment out this function since it is currently unstable.
956
957 // #[inline]
958 // fn extend_one(&mut self, s: &'a str) {
959 // self.push_str(s);
960 // }
961}
962
963impl<'a, const CAPACITY: usize> Extend<Box<str>> for FlexibleString<CAPACITY> {
964 fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
965 iter.into_iter().for_each(move |s| self.push_str(&s));
966 }
967}
968
969impl<const CAPACITY_LHS: usize, const CAPACITY_RHS: usize> Extend<FlexibleString<CAPACITY_RHS>>
970 for FlexibleString<CAPACITY_LHS>
971{
972 fn extend<I: IntoIterator<Item = FlexibleString<CAPACITY_RHS>>>(&mut self, iter: I) {
973 iter.into_iter().for_each(move |s| self.push_str(&s));
974 }
975
976 // comment out this function since it is currently unstable.
977
978 // #[inline]
979 // fn extend_one(&mut self, s: FlexibleString<CAPACITY_RHS>) {
980 // self.push_str(&s);
981 // }
982}
983
984impl<const CAPACITY: usize> str::FromStr for FlexibleString<CAPACITY> {
985 type Err = core::convert::Infallible;
986
987 #[inline]
988 fn from_str(s: &str) -> Result<FlexibleString<CAPACITY>, Self::Err> {
989 Ok(FlexibleString::from(s))
990 }
991}
992
993impl<const CAPACITY: usize> ops::Add<&str> for FlexibleString<CAPACITY> {
994 type Output = FlexibleString<CAPACITY>;
995
996 #[inline]
997 fn add(mut self, other: &str) -> Self {
998 self.push_str(other);
999 self
1000 }
1001}
1002
1003impl<const CAPACITY: usize> ops::AddAssign<&str> for FlexibleString<CAPACITY> {
1004 #[inline]
1005 fn add_assign(&mut self, other: &str) {
1006 self.push_str(other);
1007 }
1008}
1009
1010impl<const CAPACITY: usize> ops::Deref for FlexibleString<CAPACITY> {
1011 type Target = str;
1012
1013 common_methods! {
1014 NEVER_UPGRADE => fn deref([&]self) -> &str;
1015 }
1016}
1017
1018impl<const CAPACITY: usize> ops::DerefMut for FlexibleString<CAPACITY> {
1019 common_methods! {
1020 NEVER_UPGRADE => fn deref_mut([&mut]self) -> &mut str;
1021 }
1022}
1023
1024impl<const CAPACITY: usize> fmt::Write for FlexibleString<CAPACITY> {
1025 #[inline]
1026 fn write_str(&mut self, s: &str) -> fmt::Result {
1027 self.push_str(s);
1028 Ok(())
1029 }
1030
1031 #[inline]
1032 fn write_char(&mut self, c: char) -> fmt::Result {
1033 self.push(c);
1034 Ok(())
1035 }
1036}
1037
1038impl<const CAPACITY: usize> fmt::Display for FlexibleString<CAPACITY> {
1039 #[inline]
1040 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1041 fmt::Display::fmt(&**self, f)
1042 }
1043}
1044
1045impl<const CAPACITY: usize> fmt::Debug for FlexibleString<CAPACITY> {
1046 #[inline]
1047 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1048 fmt::Debug::fmt(&**self, f)
1049 }
1050}
1051
1052#[derive(Clone)]
1053struct StackString<const CAPACITY: usize> {
1054 data: [MaybeUninit<u8>; CAPACITY],
1055 len: usize,
1056}
1057
1058// Err(EstimatedCapacity) if the stack size is not enough, we must switch to use the heap.
1059type StackStringResult<T> = Result<T, Option<usize>>;
1060
1061impl<const CAPACITY: usize> StackString<CAPACITY> {
1062 #[inline]
1063 fn new() -> Self {
1064 Self {
1065 data: unsafe { MaybeUninit::uninit().assume_init() },
1066 len: 0,
1067 }
1068 }
1069
1070 #[inline]
1071 unsafe fn from_utf8_vec_only_len_unchecked(vec: Vec<u8>) -> Result<Self, FromUtf8Error> {
1072 match str::from_utf8(&vec) {
1073 Ok(..) => Ok(Self::from_utf8_slice_unchecked(&vec)),
1074 Err(e) => Err(FromUtf8Error {
1075 bytes: vec,
1076 error: e,
1077 }),
1078 }
1079 }
1080
1081 #[inline]
1082 unsafe fn from_utf8_slice_unchecked(bytes: &[u8]) -> Self {
1083 let mut res = Self::new();
1084 res.copy_append_unchecked(bytes.as_ptr(), bytes.len());
1085 res
1086 }
1087
1088 #[inline]
1089 fn into_bytes(self) -> Vec<u8> {
1090 self.as_bytes().into()
1091 }
1092
1093 #[inline]
1094 fn as_str(&self) -> &str {
1095 self
1096 }
1097
1098 #[inline]
1099 fn as_mut_str(&mut self) -> &mut str {
1100 self
1101 }
1102
1103 #[inline]
1104 fn push_str(&mut self, string: &str) -> StackStringResult<()> {
1105 let len_needed = self.len + string.len();
1106 if len_needed > CAPACITY {
1107 Err(Some(len_needed))
1108 } else {
1109 unsafe {
1110 self.copy_append_unchecked(string.as_ptr(), string.len());
1111 }
1112 Ok(())
1113 }
1114 }
1115
1116 #[inline]
1117 const fn capacity(&self) -> usize {
1118 CAPACITY
1119 }
1120
1121 #[inline]
1122 fn reserve(&mut self, additional: usize) -> StackStringResult<()> {
1123 let cap_at_least = self.len + additional;
1124 if cap_at_least > CAPACITY {
1125 Err(Some(cap_at_least))
1126 } else {
1127 Ok(())
1128 }
1129 }
1130
1131 #[inline]
1132 fn reserve_exact(&mut self, additional: usize) -> StackStringResult<()> {
1133 self.reserve(additional)
1134 }
1135
1136 // comment out these 2 functions since `TryReserveErrorKind` is currently unstable.
1137 //
1138 // fn try_reserve(&mut self, additional: usize) -> StackStringResult<Result<(), TryReserveError>> {
1139 // let cap_at_least = self.len + additional;
1140 // if cap_at_least > CAPACITY {
1141 // Err(Some(cap_at_least))
1142 // } else {
1143 // Ok(Ok(()))
1144 // }
1145 // }
1146 //
1147 // fn try_reserve_exact(
1148 // &mut self,
1149 // additional: usize,
1150 // ) -> StackStringResult<Result<(), TryReserveError>> {
1151 // self.try_reserve(additional)
1152 // }
1153
1154 #[inline]
1155 fn shrink_to(&mut self, _min_capacity: usize) {
1156 // just do nothing :)
1157 }
1158
1159 #[inline]
1160 fn push(&mut self, ch: char) -> StackStringResult<()> {
1161 let len_utf8 = ch.len_utf8();
1162 let len_needed = self.len + len_utf8;
1163
1164 if len_needed > CAPACITY {
1165 Err(Some(len_needed))
1166 } else {
1167 match len_utf8 {
1168 1 => {
1169 unsafe { *self.data[self.len].as_mut_ptr() = ch as u8 }
1170 self.len += 1;
1171 }
1172 test_len_utf8 => {
1173 let mut buf = [0; 4];
1174 let bytes = ch.encode_utf8(&mut buf).as_bytes();
1175 debug_assert_eq!(test_len_utf8, bytes.len());
1176 unsafe { self.copy_append_unchecked(bytes.as_ptr(), bytes.len()) }
1177 }
1178 }
1179 Ok(())
1180 }
1181 }
1182
1183 #[inline]
1184 fn as_bytes(&self) -> &[u8] {
1185 unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
1186 }
1187
1188 #[inline]
1189 fn as_bytes_mut(&mut self) -> &mut [u8] {
1190 unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
1191 }
1192
1193 #[inline]
1194 fn truncate(&mut self, new_len: usize) {
1195 if new_len <= self.len {
1196 assert!(self.is_char_boundary(new_len));
1197 unsafe {
1198 self.set_len(new_len);
1199 }
1200 }
1201 }
1202
1203 #[inline]
1204 fn pop(&mut self) -> Option<char> {
1205 let ch = self.chars().rev().next()?;
1206 let newlen = self.len() - ch.len_utf8();
1207 unsafe {
1208 self.set_len(newlen);
1209 }
1210 Some(ch)
1211 }
1212
1213 #[inline]
1214 fn remove(&mut self, idx: usize) -> char {
1215 let ch = match self[idx..].chars().next() {
1216 Some(ch) => ch,
1217 None => panic!("cannot remove a char from the end of a string"),
1218 };
1219
1220 let next = idx + ch.len_utf8();
1221 let len = self.len();
1222 unsafe {
1223 ptr::copy(
1224 self.as_ptr().add(next),
1225 self.as_mut_ptr().add(idx),
1226 len - next,
1227 );
1228 self.set_len(len - (next - idx));
1229 }
1230 ch
1231 }
1232
1233 #[inline]
1234 fn insert(&mut self, idx: usize, ch: char) -> StackStringResult<()> {
1235 assert!(self.is_char_boundary(idx));
1236 let mut bits = [0; 4];
1237 let bits = ch.encode_utf8(&mut bits).as_bytes();
1238
1239 unsafe { self.insert_bytes(idx, bits) }
1240 }
1241
1242 #[inline]
1243 fn insert_str(&mut self, idx: usize, string: &str) -> StackStringResult<()> {
1244 assert!(self.is_char_boundary(idx));
1245
1246 unsafe { self.insert_bytes(idx, string.as_bytes()) }
1247 }
1248
1249 #[inline]
1250 fn len(&self) -> usize {
1251 self.len
1252 }
1253
1254 #[inline]
1255 fn is_empty(&self) -> bool {
1256 self.len == 0
1257 }
1258
1259 #[inline]
1260 fn clear(&mut self) {
1261 self.truncate(0)
1262 }
1263
1264 #[inline]
1265 unsafe fn set_len(&mut self, new_len: usize) {
1266 debug_assert!(new_len <= CAPACITY);
1267 self.len = new_len;
1268 }
1269
1270 //////////
1271
1272 #[inline]
1273 fn as_ptr(&self) -> *const u8 {
1274 self.data.as_ptr() as *const u8
1275 }
1276
1277 #[inline]
1278 fn as_mut_ptr(&mut self) -> *mut u8 {
1279 self.data.as_mut_ptr() as *mut u8
1280 }
1281
1282 #[inline]
1283 unsafe fn copy_append_unchecked(&mut self, src: *const u8, len: usize) {
1284 let dst = self.as_mut_ptr().add(self.len);
1285 ptr::copy_nonoverlapping(src, dst, len);
1286 self.len += len;
1287 }
1288
1289 #[inline]
1290 fn to_heap(&self, estimated_capacity: Option<usize>) -> String {
1291 let bytes = self.as_bytes();
1292
1293 if let Some(capacity) = estimated_capacity {
1294 let mut vec = Vec::with_capacity(capacity);
1295 vec.extend_from_slice(bytes);
1296 unsafe { String::from_utf8_unchecked(vec) }
1297 } else {
1298 unsafe { String::from_utf8_unchecked(bytes.into()) }
1299 }
1300 }
1301
1302 #[inline]
1303 unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) -> StackStringResult<()> {
1304 let len = self.len();
1305 let amt = bytes.len();
1306
1307 let len_needed = len + amt;
1308 if len_needed > CAPACITY {
1309 return Err(Some(len_needed));
1310 }
1311
1312 ptr::copy(
1313 self.as_ptr().add(idx),
1314 self.as_mut_ptr().add(idx + amt),
1315 len - idx,
1316 );
1317 ptr::copy_nonoverlapping(bytes.as_ptr(), self.as_mut_ptr().add(idx), amt);
1318 self.set_len(len_needed);
1319
1320 Ok(())
1321 }
1322}
1323
1324impl<const CAPACITY: usize> ops::Deref for StackString<CAPACITY> {
1325 type Target = str;
1326
1327 #[inline]
1328 fn deref(&self) -> &str {
1329 let bytes = self.as_bytes();
1330 unsafe { str::from_utf8_unchecked(bytes) }
1331 }
1332}
1333
1334impl<const CAPACITY: usize> ops::DerefMut for StackString<CAPACITY> {
1335 #[inline]
1336 fn deref_mut(&mut self) -> &mut str {
1337 let bytes = self.as_bytes_mut();
1338 unsafe { str::from_utf8_unchecked_mut(bytes) }
1339 }
1340}
1341
1342impl<const CAPACITY: usize> fmt::Debug for StackString<CAPACITY> {
1343 #[inline]
1344 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1345 fmt::Debug::fmt(&**self, f)
1346 }
1347}
1348
1349//////////////////////////////////////////////////
1350
1351impl FromUtf8Error {
1352 /// Returns a slice of [`u8`]s bytes that were attempted to convert to a `FlexibleString`.
1353 ///
1354 /// # Examples
1355 ///
1356 /// Basic usage:
1357 ///
1358 /// ```
1359 /// use flexible_string::FlexibleString;
1360 ///
1361 /// // some invalid bytes, in a vector
1362 /// let bytes = vec![0, 159];
1363 ///
1364 /// let value = FlexibleString::<200>::from_utf8(bytes);
1365 ///
1366 /// assert_eq!(&[0, 159], value.unwrap_err().as_bytes());
1367 /// ```
1368 #[inline]
1369 pub fn as_bytes(&self) -> &[u8] {
1370 &self.bytes[..]
1371 }
1372
1373 /// Returns the bytes that were attempted to convert to a `FlexibleString`.
1374 ///
1375 /// This method is carefully constructed to avoid allocation. It will
1376 /// consume the error, moving out the bytes, so that a copy of the bytes
1377 /// does not need to be made.
1378 ///
1379 /// # Examples
1380 ///
1381 /// Basic usage:
1382 ///
1383 /// ```
1384 /// use flexible_string::FlexibleString;
1385 ///
1386 /// // some invalid bytes, in a vector
1387 /// let bytes = vec![0, 159];
1388 ///
1389 /// let value = FlexibleString::<200>::from_utf8(bytes);
1390 ///
1391 /// assert_eq!(vec![0, 159], value.unwrap_err().into_bytes());
1392 /// ```
1393 #[inline]
1394 pub fn into_bytes(self) -> Vec<u8> {
1395 self.bytes
1396 }
1397
1398 /// Fetch a `Utf8Error` to get more details about the conversion failure.
1399 ///
1400 /// The [`std::str::Utf8Error`] type represents an error that may
1401 /// occur when converting a slice of [`u8`]s to a [`&str`]. In this sense, it's
1402 /// an analogue to `FromUtf8Error`. See its documentation for more details
1403 /// on using it.
1404 ///
1405 /// [`std::str`]: core::str "std::str"
1406 /// [`&str`]: prim@str "&str"
1407 ///
1408 /// # Examples
1409 ///
1410 /// Basic usage:
1411 ///
1412 /// ```
1413 /// use flexible_string::FlexibleString;
1414 ///
1415 /// // some invalid bytes, in a vector
1416 /// let bytes = vec![0, 159];
1417 ///
1418 /// let error = FlexibleString::<200>::from_utf8(bytes).unwrap_err().utf8_error();
1419 ///
1420 /// // the first byte is invalid here
1421 /// assert_eq!(1, error.valid_up_to());
1422 /// ```
1423 #[inline]
1424 pub fn utf8_error(&self) -> str::Utf8Error {
1425 self.error
1426 }
1427}
1428
1429impl From<string::FromUtf8Error> for FromUtf8Error {
1430 fn from(std_err: string::FromUtf8Error) -> Self {
1431 let err = std_err.utf8_error();
1432 Self {
1433 bytes: std_err.into_bytes(),
1434 error: err,
1435 }
1436 }
1437}
1438
1439impl fmt::Display for FromUtf8Error {
1440 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1441 fmt::Display::fmt(&self.error, f)
1442 }
1443}
1444
1445#[cfg(test)]
1446mod tests {
1447 use super::*;
1448
1449 #[test]
1450 fn heterogeneous_cmp() {
1451 assert_eq!(
1452 FlexibleString::<100>::from("hello"),
1453 FlexibleString::<200>::from("hello")
1454 );
1455
1456 assert_eq!(FlexibleString::<100>::from("hello"), "hello");
1457 assert_eq!("hello", FlexibleString::<100>::from("hello"));
1458
1459 assert_eq!(FlexibleString::<100>::from("hello"), String::from("hello"));
1460 assert_eq!(String::from("hello"), FlexibleString::<100>::from("hello"));
1461 }
1462}