varlen/
str.rs

1#![doc = crate::doc_macro::make_svgbobdoc!(
2    //! A string with inline storage. 
3    //! 
4    //! This consists of an integer `length` field, followed immediately by the utf8 string payload. 
5    //! For example, the [`VBox<String>`](crate::VBox) representation of `"hello"` is:
6    //! 
7    //! ```svgbob
8    //! "VBox"
9    //! +----------+
10    //! | ptr      |
11    //! +----------+
12    //!      |
13    //!      |   Str
14    //!      |   +-----------+-----------+
15    //!      '-> | 3: usize  | ""hello"" |
16    //!          +-----------+-----------+
17    //! ```
18    //!
19    //! Once allocated, the string size may not be modified.
20    //! 
21    //! # Examples
22    //! 
23    //! ```
24    //! use varlen::prelude::*;
25    //! use varlen::Layout;
26    //! let s = VBox::new(Str::copy("hello"));
27    //! assert_eq!(&s[..], "hello");
28    //! // Layout is as specified above:
29    //! assert_eq!(s.calculate_layout().size(), std::mem::size_of::<usize>() + 5)
30    //! ```
31)]
32
33use crate::array::{Array, ArrayCloner, ArrayLen};
34use crate::newtype::define_varlen_newtype;
35use crate::{impl_initializer_as_newtype, Initializer, VClone, VCopy};
36use core::pin::Pin;
37
38define_varlen_newtype! {
39    #[repr(transparent)]
40    #[doc = crate::doc_macro::make_svgbobdoc!(
41    /// A string with inline storage.
42    ///
43    /// This consists of an integer `length` field, followed immediately by the utf8 string payload.
44    /// For example, the [`VBox<String>`](crate::VBox) representation of `"hello"` is:
45    ///
46    /// ```svgbob
47    /// "VBox"
48    /// +----------+
49    /// | ptr      |
50    /// +----------+
51    ///      |
52    ///      |   Str
53    ///      |   +-----------+------+------+------+------+------+
54    ///      '-> | 3: usize  | "'h'"| "'e'"| "'l'"| "'l'"| "'o'"|
55    ///          +-----------+------+------+------+------+------+
56    /// ```
57    ///
58    /// Once allocated, the string size may not be modified.
59    ///
60    /// # Examples
61    ///
62    /// ```
63    /// use varlen::prelude::*;
64    /// use varlen::Layout;
65    /// let s = VBox::new(Str::copy("hello"));
66    /// assert_eq!(&s[..], "hello");
67    /// // Layout is as specified above:
68    /// assert_eq!(s.calculate_layout().size(), std::mem::size_of::<usize>() + 5)
69    /// ```
70    ///
71    /// # Smaller length field
72    ///
73    /// You may choose to store the length of the string in a smaller integer type than [`usize`],
74    /// just like in [`Array<T>`](crate::Array). Construction will fail if the string is too long for the
75    /// integer type to express:
76    ///
77    /// ```
78    /// use varlen::prelude::*;
79    /// // Short string fits:
80    /// let s: VBox<Str<u8>> = VBox::new(Str::try_copy("hello").unwrap());
81    /// // Long string doesn't fit:
82    /// assert!(Str::<u8>::try_copy(std::str::from_utf8(&[b'a'; 257]).unwrap()).is_none());
83    /// ```
84    )]
85    pub struct Str<(Len: ArrayLen = usize)>(Array<u8, Len>);
86
87    with signature: impl<(Len: ArrayLen)> Str<(Len)> { _ }
88
89    with init: struct StrInit<_>(_);
90    with inner_ref: fn inner(&self) -> &_;
91    with inner_mut: fn inner_mut(self: _) -> _;
92}
93
94impl<Len: ArrayLen> core::ops::Deref for Str<Len> {
95    type Target = str;
96    fn deref(&self) -> &Self::Target {
97        let slice: &[u8] = &self.inner();
98        unsafe {
99            // Safety: we only allow initialization from valid utf8
100            core::str::from_utf8_unchecked(slice)
101        }
102    }
103}
104
105#[allow(rustdoc::missing_doc_code_examples)]
106impl<Len: ArrayLen> Str<Len> {
107    /// Mutable access to the underlying string.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use varlen::prelude::*;
113    /// let mut s = VBox::new(Str::copy("hello"));
114    /// s.as_mut().mut_slice().make_ascii_uppercase();
115    /// assert_eq!(&s[..], "HELLO");
116    /// ```
117    pub fn mut_slice(self: Pin<&mut Self>) -> &mut str {
118        let slice = self.inner_mut().mut_slice();
119        unsafe {
120            // Safety: we only allow initialization from valid utf8
121            core::str::from_utf8_unchecked_mut(slice)
122        }
123    }
124}
125
126#[allow(rustdoc::missing_doc_code_examples)]
127impl Str {
128    /// Initializes a [`Str`] by copying from an existing [`&str`].
129    ///
130    /// # Examples
131    ///
132    /// ```
133    /// use varlen::prelude::*;
134    /// let s = VBox::new(Str::copy("hello"));
135    /// assert_eq!(&s[..], "hello");
136    /// ```
137    pub fn copy(s: &str) -> impl Initializer<Self> + '_ {
138        Str::try_copy(s).unwrap()
139    }
140}
141#[allow(rustdoc::missing_doc_code_examples)]
142impl<Len: ArrayLen> Str<Len> {
143    /// Initializes a [`Str`] from an existing [`&str`], or returns `None` if it doesn't fit in the length field.
144    ///
145    /// ```
146    /// use varlen::prelude::*;
147    /// // Short string fits:
148    /// let s: VBox<Str<u8>> = VBox::new(Str::try_copy("hello").unwrap());
149    /// // Long string doesn't fit:
150    /// assert!(Str::<u8>::try_copy(std::str::from_utf8(&[b'a'; 257]).unwrap()).is_none());
151    /// ```
152    pub fn try_copy(s: &str) -> Option<impl Initializer<Self> + '_> {
153        Some(StrInit(Array::try_copy(s.as_bytes())?))
154    }
155}
156
157/// Initializer type for cloning an array.
158///
159/// Prefer to use `Str::vcopy()` over `Str::vclone()` where possible.
160///
161/// # Examples
162///
163/// ```
164/// use varlen::prelude::*;
165/// let arr = VBox::new(Str::copy("hello"));
166/// let seq: Seq<Str> = seq![arr.vclone(), arr.vclone(), arr.vclone()];  // Clones the string
167/// for a in seq.iter() {
168///     assert_eq!(&a[..], "hello");
169/// }
170/// ```
171pub struct StrCloner<'a, Len: ArrayLen>(StrInit<ArrayCloner<'a, u8, Len>>);
172
173impl_initializer_as_newtype! {
174    impl<('a), (Len: ArrayLen)> Initializer<Str<Len>> for StrCloner<'a, Len> { _ }
175}
176
177impl<'a, Len: ArrayLen> VClone<'a> for Str<Len> {
178    type Cloner = StrCloner<'a, Len>;
179    fn vclone(&'a self) -> Self::Cloner {
180        StrCloner(StrInit(self.0.vclone()))
181    }
182}
183
184/// Strings can be copied with fast memcpy.
185///
186/// # Examples
187///
188/// ```
189/// use varlen::prelude::*;
190/// let arr = VBox::new(Str::copy("hello"));
191/// let seq: Seq<Str> = seq![arr.vcopy(), arr.vcopy(), arr.vcopy()];
192/// for a in seq.iter() {
193///     assert_eq!(&a[..], "hello");
194/// }
195/// ```
196// Safety: Len is Copy (because of ArrayLen), and so is the [u8] payload.
197unsafe impl<'a, Len: ArrayLen> VCopy<'a> for Str<Len> {}