Skip to main content

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        // SAFETY: `new_unchecked` requires the same precondition
56        // as `new_always_unchecked`.
57        unsafe { Self::new_always_unchecked(s) }
58    }
59
60    /// Creates a new string without any validation.
61    ///
62    /// This does not validate the given string at any time.
63    ///
64    /// Intended for internal use.
65    ///
66    /// # Safety
67    ///
68    /// The given string must be syntactically valid as `Self` type.
69    /// If not, any use of the returned value or the call of this
70    /// function itself may result in undefined behavior.
71    #[inline]
72    #[must_use]
73    pub(super) unsafe fn new_always_unchecked(s: alloc::string::String) -> Self {
74        // The construction itself can be written in safe Rust, but
75        // every other place including unsafe functions expects
76        // `self.inner` to be syntactically valid as `Self`. In order to
77        // make them safe, the construction should validate the value
78        // or at least should require users to validate the value by
79        // making the function `unsafe`.
80        Self { inner: s }
81    }
82
83    /// Checks if the given string content is valid as `Self`.
84    pub(super) fn validate(s: &str) -> Result<(), Error> {
85        validate_template_str(s)
86    }
87
88    /// Shrinks the capacity of the inner buffer to match its length.
89    #[inline]
90    pub fn shrink_to_fit(&mut self) {
91        self.inner.shrink_to_fit()
92    }
93
94    /// Returns the internal buffer capacity in bytes.
95    #[inline]
96    #[must_use]
97    pub fn capacity(&self) -> usize {
98        self.inner.capacity()
99    }
100
101    /// Returns the borrowed IRI string slice.
102    ///
103    /// This is equivalent to `&*self`.
104    #[inline]
105    #[must_use]
106    pub fn as_slice(&self) -> &UriTemplateStr {
107        self.as_ref()
108    }
109
110    /// Appends the template string.
111    #[inline]
112    pub fn append(&mut self, other: &UriTemplateStr) {
113        self.inner.push_str(other.as_str());
114        debug_assert_eq!(Self::validate(self.as_str()), Ok(()));
115    }
116}
117
118impl AsRef<str> for UriTemplateString {
119    #[inline]
120    fn as_ref(&self) -> &str {
121        &self.inner
122    }
123}
124
125impl AsRef<UriTemplateStr> for UriTemplateString {
126    #[inline]
127    fn as_ref(&self) -> &UriTemplateStr {
128        // SAFETY: `UriTemplateString and `UriTemplateStr` requires same validation,
129        // so the content of `self: &UriTemplateString` must be valid as `UriTemplateStr`.
130        unsafe { UriTemplateStr::new_always_unchecked(AsRef::<str>::as_ref(self)) }
131    }
132}
133
134impl core::borrow::Borrow<str> for UriTemplateString {
135    #[inline]
136    fn borrow(&self) -> &str {
137        self.as_ref()
138    }
139}
140
141impl core::borrow::Borrow<UriTemplateStr> for UriTemplateString {
142    #[inline]
143    fn borrow(&self) -> &UriTemplateStr {
144        self.as_ref()
145    }
146}
147
148impl ToOwned for UriTemplateStr {
149    type Owned = UriTemplateString;
150
151    #[inline]
152    fn to_owned(&self) -> Self::Owned {
153        self.into()
154    }
155}
156
157impl From<&'_ UriTemplateStr> for UriTemplateString {
158    #[inline]
159    fn from(s: &UriTemplateStr) -> Self {
160        // This is safe because `s` must be valid.
161        Self {
162            inner: alloc::string::String::from(s.as_str()),
163        }
164    }
165}
166
167impl From<UriTemplateString> for alloc::string::String {
168    #[inline]
169    fn from(s: UriTemplateString) -> Self {
170        s.inner
171    }
172}
173
174impl<'a> From<UriTemplateString> for Cow<'a, UriTemplateStr> {
175    #[inline]
176    fn from(s: UriTemplateString) -> Cow<'a, UriTemplateStr> {
177        Cow::Owned(s)
178    }
179}
180
181impl From<UriTemplateString> for Box<UriTemplateStr> {
182    #[inline]
183    fn from(s: UriTemplateString) -> Box<UriTemplateStr> {
184        let inner: String = s.into();
185        let buf = Box::<str>::from(inner);
186        // SAFETY: `UriTemplateStr` has `repr(transparent)` attribute, so
187        // the memory layouts of `Box<str>` and `Box<UriTemplateStr>` are
188        // compatible. Additionally, `UriTemplateString` and `UriTemplateStr`
189        // require the same syntax.
190        unsafe {
191            let raw: *mut str = Box::into_raw(buf);
192            Box::<UriTemplateStr>::from_raw(raw as *mut UriTemplateStr)
193        }
194    }
195}
196
197impl TryFrom<&'_ str> for UriTemplateString {
198    type Error = Error;
199
200    #[inline]
201    fn try_from(s: &str) -> Result<Self, Self::Error> {
202        <&UriTemplateStr>::try_from(s).map(Into::into)
203    }
204}
205
206impl TryFrom<&'_ [u8]> for UriTemplateString {
207    type Error = Error;
208
209    #[inline]
210    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
211        let s = core::str::from_utf8(bytes)
212            .map_err(|e| Error::new(ErrorKind::InvalidUtf8, e.valid_up_to()))?;
213        <&UriTemplateStr>::try_from(s).map(Into::into)
214    }
215}
216
217impl core::convert::TryFrom<alloc::string::String> for UriTemplateString {
218    type Error = CreationError<String>;
219
220    #[inline]
221    fn try_from(s: alloc::string::String) -> Result<Self, Self::Error> {
222        match <&UriTemplateStr>::try_from(s.as_str()) {
223            Ok(_) => {
224                // This is safe because `<&UriTemplateStr>::try_from(s)?` ensures
225                // that the string `s` is valid.
226                Ok(Self { inner: s })
227            }
228            Err(e) => Err(CreationError::new(e, s)),
229        }
230    }
231}
232
233impl alloc::str::FromStr for UriTemplateString {
234    type Err = Error;
235
236    #[inline]
237    fn from_str(s: &str) -> Result<Self, Self::Err> {
238        TryFrom::try_from(s)
239    }
240}
241
242impl core::ops::Deref for UriTemplateString {
243    type Target = UriTemplateStr;
244
245    #[inline]
246    fn deref(&self) -> &UriTemplateStr {
247        self.as_ref()
248    }
249}
250
251impl_cmp!(str, UriTemplateStr, Cow<'_, str>);
252impl_cmp!(str, &UriTemplateStr, Cow<'_, str>);
253
254impl_cmp!(str, str, UriTemplateString);
255impl_cmp!(str, &str, UriTemplateString);
256impl_cmp!(str, Cow<'_, str>, UriTemplateString);
257impl_cmp!(str, String, UriTemplateString);
258
259impl fmt::Display for UriTemplateString {
260    #[inline]
261    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262        f.write_str(self.as_str())
263    }
264}
265
266/// Serde deserializer implementation.
267#[cfg(feature = "serde")]
268mod __serde_owned {
269    use super::UriTemplateString;
270
271    use core::fmt;
272
273    #[cfg(all(feature = "alloc", feature = "serde", not(feature = "std")))]
274    use alloc::string::String;
275
276    use serde::{
277        de::{self, Visitor},
278        Deserialize, Deserializer,
279    };
280
281    /// Custom owned string visitor.
282    #[derive(Debug, Clone, Copy)]
283    struct CustomStringVisitor;
284
285    impl Visitor<'_> for CustomStringVisitor {
286        type Value = UriTemplateString;
287
288        #[inline]
289        fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290            f.write_str("URI template string")
291        }
292
293        #[inline]
294        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
295        where
296            E: de::Error,
297        {
298            <UriTemplateString as TryFrom<&str>>::try_from(v).map_err(E::custom)
299        }
300
301        #[cfg(feature = "serde")]
302        #[inline]
303        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
304        where
305            E: de::Error,
306        {
307            <UriTemplateString as TryFrom<String>>::try_from(v).map_err(E::custom)
308        }
309    }
310
311    impl<'de> Deserialize<'de> for UriTemplateString {
312        #[inline]
313        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
314        where
315            D: Deserializer<'de>,
316        {
317            deserializer.deserialize_str(CustomStringVisitor)
318        }
319    }
320}