iri_string/template/string/
owned.rs

1//! Owned `UriTemplateString`.
2
3use core::fmt;
4
5use alloc::borrow::Cow;
6#[cfg(all(feature = "alloc", not(feature = "std")))]
7use alloc::borrow::ToOwned;
8#[cfg(all(feature = "alloc", not(feature = "std")))]
9use alloc::boxed::Box;
10#[cfg(all(feature = "alloc", not(feature = "std")))]
11use alloc::string::String;
12
13use crate::template::error::{CreationError, Error, ErrorKind};
14use crate::template::parser::validate_template_str;
15use crate::template::string::UriTemplateStr;
16
17/// An owned slice of a URI template.
18///
19/// URI Template is defined by [RFC 6570].
20///
21/// Note that "URI Template" can also be used for IRI.
22///
23/// [RFC 6570]: https://www.rfc-editor.org/rfc/rfc6570.html
24///
25/// # Valid values
26///
27/// This type can have a URI template string.
28// Note that `From<$ty> for {Arc,Rc}<$slice>` is currently not implemented since
29// this won't reuse allocated memory and hides internal memory reallocation. See
30// <https://github.com/lo48576/iri-string/issues/20#issuecomment-1105207849>.
31// However, this is not decided with firm belief or opinion, so there would be
32// a chance that they are implemented in future.
33#[cfg_attr(feature = "serde", derive(serde::Serialize))]
34#[cfg_attr(feature = "serde", serde(transparent))]
35#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
36pub struct UriTemplateString {
37    /// Inner data.
38    inner: String,
39}
40
41impl UriTemplateString {
42    /// Creates a new string without validation.
43    ///
44    /// This does not validate the given string, so it is caller's
45    /// responsibility to ensure the given string is valid.
46    ///
47    /// # Safety
48    ///
49    /// The given string must be syntactically valid as `Self` type.
50    /// If not, any use of the returned value or the call of this
51    /// function itself may result in undefined behavior.
52    #[inline]
53    #[must_use]
54    pub unsafe fn new_unchecked(s: alloc::string::String) -> Self {
55        // The construction itself can be written in safe Rust, but
56        // every other place including unsafe functions expects
57        // `self.inner` to be syntactically valid as `Self`. In order to
58        // make them safe, the construction should validate the value
59        // or at least should require users to validate the value by
60        // making the function `unsafe`.
61        Self { inner: s }
62    }
63
64    /// Shrinks the capacity of the inner buffer to match its length.
65    #[inline]
66    pub fn shrink_to_fit(&mut self) {
67        self.inner.shrink_to_fit()
68    }
69
70    /// Returns the internal buffer capacity in bytes.
71    #[inline]
72    #[must_use]
73    pub fn capacity(&self) -> usize {
74        self.inner.capacity()
75    }
76
77    /// Returns the borrowed IRI string slice.
78    ///
79    /// This is equivalent to `&*self`.
80    #[inline]
81    #[must_use]
82    pub fn as_slice(&self) -> &UriTemplateStr {
83        self.as_ref()
84    }
85
86    /// Appends the template string.
87    #[inline]
88    pub fn append(&mut self, other: &UriTemplateStr) {
89        self.inner.push_str(other.as_str());
90        debug_assert!(validate_template_str(self.as_str()).is_ok());
91    }
92}
93
94impl AsRef<str> for UriTemplateString {
95    #[inline]
96    fn as_ref(&self) -> &str {
97        &self.inner
98    }
99}
100
101impl AsRef<UriTemplateStr> for UriTemplateString {
102    #[inline]
103    fn as_ref(&self) -> &UriTemplateStr {
104        // SAFETY: `UriTemplateString and `UriTemplateStr` requires same validation,
105        // so the content of `self: &UriTemplateString` must be valid as `UriTemplateStr`.
106        unsafe { UriTemplateStr::new_always_unchecked(AsRef::<str>::as_ref(self)) }
107    }
108}
109
110impl core::borrow::Borrow<str> for UriTemplateString {
111    #[inline]
112    fn borrow(&self) -> &str {
113        self.as_ref()
114    }
115}
116
117impl core::borrow::Borrow<UriTemplateStr> for UriTemplateString {
118    #[inline]
119    fn borrow(&self) -> &UriTemplateStr {
120        self.as_ref()
121    }
122}
123
124impl ToOwned for UriTemplateStr {
125    type Owned = UriTemplateString;
126
127    #[inline]
128    fn to_owned(&self) -> Self::Owned {
129        self.into()
130    }
131}
132
133impl From<&'_ UriTemplateStr> for UriTemplateString {
134    #[inline]
135    fn from(s: &UriTemplateStr) -> Self {
136        // This is safe because `s` must be valid.
137        Self {
138            inner: alloc::string::String::from(s.as_str()),
139        }
140    }
141}
142
143impl From<UriTemplateString> for alloc::string::String {
144    #[inline]
145    fn from(s: UriTemplateString) -> Self {
146        s.inner
147    }
148}
149
150impl<'a> From<UriTemplateString> for Cow<'a, UriTemplateStr> {
151    #[inline]
152    fn from(s: UriTemplateString) -> Cow<'a, UriTemplateStr> {
153        Cow::Owned(s)
154    }
155}
156
157impl From<UriTemplateString> for Box<UriTemplateStr> {
158    #[inline]
159    fn from(s: UriTemplateString) -> Box<UriTemplateStr> {
160        let inner: String = s.into();
161        let buf = Box::<str>::from(inner);
162        // SAFETY: `UriTemplateStr` has `repr(transparent)` attribute, so
163        // the memory layouts of `Box<str>` and `Box<UriTemplateStr>` are
164        // compatible. Additionally, `UriTemplateString` and `UriTemplateStr`
165        // require the same syntax.
166        unsafe {
167            let raw: *mut str = Box::into_raw(buf);
168            Box::<UriTemplateStr>::from_raw(raw as *mut UriTemplateStr)
169        }
170    }
171}
172
173impl TryFrom<&'_ str> for UriTemplateString {
174    type Error = Error;
175
176    #[inline]
177    fn try_from(s: &str) -> Result<Self, Self::Error> {
178        <&UriTemplateStr>::try_from(s).map(Into::into)
179    }
180}
181
182impl TryFrom<&'_ [u8]> for UriTemplateString {
183    type Error = Error;
184
185    #[inline]
186    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
187        let s = core::str::from_utf8(bytes)
188            .map_err(|e| Error::new(ErrorKind::InvalidUtf8, e.valid_up_to()))?;
189        <&UriTemplateStr>::try_from(s).map(Into::into)
190    }
191}
192
193impl core::convert::TryFrom<alloc::string::String> for UriTemplateString {
194    type Error = CreationError<String>;
195
196    #[inline]
197    fn try_from(s: alloc::string::String) -> Result<Self, Self::Error> {
198        match <&UriTemplateStr>::try_from(s.as_str()) {
199            Ok(_) => {
200                // This is safe because `<&UriTemplateStr>::try_from(s)?` ensures
201                // that the string `s` is valid.
202                Ok(Self { inner: s })
203            }
204            Err(e) => Err(CreationError::new(e, s)),
205        }
206    }
207}
208
209impl alloc::str::FromStr for UriTemplateString {
210    type Err = Error;
211
212    #[inline]
213    fn from_str(s: &str) -> Result<Self, Self::Err> {
214        TryFrom::try_from(s)
215    }
216}
217
218impl core::ops::Deref for UriTemplateString {
219    type Target = UriTemplateStr;
220
221    #[inline]
222    fn deref(&self) -> &UriTemplateStr {
223        self.as_ref()
224    }
225}
226
227impl_cmp!(str, UriTemplateStr, Cow<'_, str>);
228impl_cmp!(str, &UriTemplateStr, Cow<'_, str>);
229
230impl_cmp!(str, str, UriTemplateString);
231impl_cmp!(str, &str, UriTemplateString);
232impl_cmp!(str, Cow<'_, str>, UriTemplateString);
233impl_cmp!(str, String, UriTemplateString);
234
235impl fmt::Display for UriTemplateString {
236    #[inline]
237    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238        f.write_str(self.as_str())
239    }
240}
241
242/// Serde deserializer implementation.
243#[cfg(feature = "serde")]
244mod __serde_owned {
245    use super::UriTemplateString;
246
247    use core::fmt;
248
249    #[cfg(all(feature = "alloc", feature = "serde", not(feature = "std")))]
250    use alloc::string::String;
251
252    use serde::{
253        de::{self, Visitor},
254        Deserialize, Deserializer,
255    };
256
257    /// Custom owned string visitor.
258    #[derive(Debug, Clone, Copy)]
259    struct CustomStringVisitor;
260
261    impl Visitor<'_> for CustomStringVisitor {
262        type Value = UriTemplateString;
263
264        #[inline]
265        fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266            f.write_str("URI template string")
267        }
268
269        #[inline]
270        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
271        where
272            E: de::Error,
273        {
274            <UriTemplateString as TryFrom<&str>>::try_from(v).map_err(E::custom)
275        }
276
277        #[cfg(feature = "serde")]
278        #[inline]
279        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
280        where
281            E: de::Error,
282        {
283            <UriTemplateString as TryFrom<String>>::try_from(v).map_err(E::custom)
284        }
285    }
286
287    impl<'de> Deserialize<'de> for UriTemplateString {
288        #[inline]
289        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
290        where
291            D: Deserializer<'de>,
292        {
293            deserializer.deserialize_str(CustomStringVisitor)
294        }
295    }
296}