zvariant/
str.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2use static_assertions::assert_impl_all;
3use std::{
4    borrow::Cow,
5    cmp::Ordering,
6    hash::{Hash, Hasher},
7    sync::Arc,
8};
9
10use crate::{serialized::Format, Basic, Signature, Type};
11
12/// A string wrapper.
13///
14/// This is used for keeping strings in a [`Value`]. API is provided to convert from, and to a
15/// [`&str`] and [`String`].
16///
17/// [`Value`]: enum.Value.html#variant.Str
18/// [`&str`]: https://doc.rust-lang.org/std/str/index.html
19/// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html
20#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)]
21#[serde(rename(serialize = "zvariant::Str", deserialize = "zvariant::Str"))]
22pub struct Str<'a>(#[serde(borrow)] Inner<'a>);
23
24#[derive(Eq, Clone)]
25enum Inner<'a> {
26    Static(&'static str),
27    Borrowed(&'a str),
28    Owned(Arc<str>),
29}
30
31impl<'a> Default for Inner<'a> {
32    fn default() -> Self {
33        Self::Static("")
34    }
35}
36
37impl<'a> PartialEq for Inner<'a> {
38    fn eq(&self, other: &Inner<'a>) -> bool {
39        self.as_str() == other.as_str()
40    }
41}
42
43impl<'a> Ord for Inner<'a> {
44    fn cmp(&self, other: &Inner<'a>) -> Ordering {
45        self.as_str().cmp(other.as_str())
46    }
47}
48
49impl<'a> PartialOrd for Inner<'a> {
50    fn partial_cmp(&self, other: &Inner<'a>) -> Option<Ordering> {
51        Some(self.cmp(other))
52    }
53}
54
55impl<'a> Hash for Inner<'a> {
56    fn hash<H: Hasher>(&self, h: &mut H) {
57        self.as_str().hash(h)
58    }
59}
60
61impl<'a> Inner<'a> {
62    /// The underlying string.
63    pub fn as_str(&self) -> &str {
64        match self {
65            Inner::Static(s) => s,
66            Inner::Borrowed(s) => s,
67            Inner::Owned(s) => s,
68        }
69    }
70}
71
72impl<'a> Serialize for Inner<'a> {
73    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
74        s.serialize_str(self.as_str())
75    }
76}
77
78impl<'de: 'a, 'a> Deserialize<'de> for Inner<'a> {
79    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
80    where
81        D: Deserializer<'de>,
82    {
83        <&'a str>::deserialize(deserializer).map(Inner::Borrowed)
84    }
85}
86
87assert_impl_all!(Str<'_>: Send, Sync, Unpin);
88
89impl<'a> Str<'a> {
90    /// An owned string without allocations
91    pub const fn from_static(s: &'static str) -> Self {
92        Str(Inner::Static(s))
93    }
94
95    /// This is faster than `Clone::clone` when `self` contains owned data.
96    pub fn as_ref(&self) -> Str<'_> {
97        match &self.0 {
98            Inner::Static(s) => Str(Inner::Static(s)),
99            Inner::Borrowed(s) => Str(Inner::Borrowed(s)),
100            Inner::Owned(s) => Str(Inner::Borrowed(s)),
101        }
102    }
103
104    /// The underlying string.
105    pub fn as_str(&self) -> &str {
106        self.0.as_str()
107    }
108
109    /// Creates an owned clone of `self`.
110    pub fn to_owned(&self) -> Str<'static> {
111        self.clone().into_owned()
112    }
113
114    /// Creates an owned clone of `self`.
115    pub fn into_owned(self) -> Str<'static> {
116        match self.0 {
117            Inner::Static(s) => Str(Inner::Static(s)),
118            Inner::Borrowed(s) => Str(Inner::Owned(s.to_owned().into())),
119            Inner::Owned(s) => Str(Inner::Owned(s)),
120        }
121    }
122}
123
124impl<'a> Basic for Str<'a> {
125    const SIGNATURE_CHAR: char = <&str>::SIGNATURE_CHAR;
126    const SIGNATURE_STR: &'static str = <&str>::SIGNATURE_STR;
127
128    fn alignment(format: Format) -> usize {
129        <&str>::alignment(format)
130    }
131}
132
133impl<'a> Type for Str<'a> {
134    fn signature() -> Signature<'static> {
135        Signature::from_static_str_unchecked(Self::SIGNATURE_STR)
136    }
137}
138
139impl<'a> From<&'a str> for Str<'a> {
140    fn from(value: &'a str) -> Self {
141        Self(Inner::Borrowed(value))
142    }
143}
144
145impl<'a> From<&'a String> for Str<'a> {
146    fn from(value: &'a String) -> Self {
147        Self(Inner::Borrowed(value))
148    }
149}
150
151impl<'a> From<String> for Str<'a> {
152    fn from(value: String) -> Self {
153        Self(Inner::Owned(value.into()))
154    }
155}
156
157impl<'a> From<Arc<str>> for Str<'a> {
158    fn from(value: Arc<str>) -> Self {
159        Self(Inner::Owned(value))
160    }
161}
162
163impl<'a> From<Cow<'a, str>> for Str<'a> {
164    fn from(value: Cow<'a, str>) -> Self {
165        match value {
166            Cow::Owned(value) => value.into(),
167            Cow::Borrowed(value) => value.into(),
168        }
169    }
170}
171
172impl<'a> From<Str<'a>> for String {
173    fn from(value: Str<'a>) -> String {
174        match value.0 {
175            Inner::Static(s) => s.into(),
176            Inner::Borrowed(s) => s.into(),
177            Inner::Owned(s) => s.to_string(),
178        }
179    }
180}
181
182impl<'a> From<&'a Str<'_>> for &'a str {
183    fn from(value: &'a Str<'_>) -> &'a str {
184        value.as_str()
185    }
186}
187
188impl<'a> std::ops::Deref for Str<'a> {
189    type Target = str;
190
191    fn deref(&self) -> &Self::Target {
192        self.as_str()
193    }
194}
195
196impl<'a> PartialEq<str> for Str<'a> {
197    fn eq(&self, other: &str) -> bool {
198        self.as_str() == other
199    }
200}
201
202impl<'a> PartialEq<&str> for Str<'a> {
203    fn eq(&self, other: &&str) -> bool {
204        self.as_str() == *other
205    }
206}
207
208impl<'a> std::fmt::Debug for Str<'a> {
209    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210        std::fmt::Debug::fmt(self.as_str(), f)
211    }
212}
213
214impl<'a> std::fmt::Display for Str<'a> {
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        std::fmt::Display::fmt(self.as_str(), f)
217    }
218}
219
220#[cfg(test)]
221mod tests {
222    use super::Str;
223
224    #[test]
225    fn from_string() {
226        let string = String::from("value");
227        let v = Str::from(&string);
228        assert_eq!(v.as_str(), "value");
229    }
230
231    #[test]
232    fn test_ordering() {
233        let first = Str::from("a".to_string());
234        let second = Str::from_static("b");
235        assert!(first < second);
236    }
237}