1 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; |
2 | use static_assertions::assert_impl_all; |
3 | use std::{ |
4 | borrow::Cow, |
5 | cmp::Ordering, |
6 | hash::{Hash, Hasher}, |
7 | sync::Arc, |
8 | }; |
9 | |
10 | use crate::{Basic, EncodingFormat, 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 (Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)] |
21 | #[serde(rename(serialize = "zvariant::Str" , deserialize = "zvariant::Str" ))] |
22 | pub struct Str<'a>(#[serde(borrow)] Inner<'a>); |
23 | |
24 | #[derive (Debug, Eq, Clone)] |
25 | enum Inner<'a> { |
26 | Static(&'static str), |
27 | Borrowed(&'a str), |
28 | Owned(Arc<str>), |
29 | } |
30 | |
31 | impl<'a> Default for Inner<'a> { |
32 | fn default() -> Self { |
33 | Self::Static("" ) |
34 | } |
35 | } |
36 | |
37 | impl<'a> PartialEq for Inner<'a> { |
38 | fn eq(&self, other: &Inner<'a>) -> bool { |
39 | self.as_str() == other.as_str() |
40 | } |
41 | } |
42 | |
43 | impl<'a> Ord for Inner<'a> { |
44 | fn cmp(&self, other: &Inner<'a>) -> Ordering { |
45 | self.as_str().cmp(other.as_str()) |
46 | } |
47 | } |
48 | |
49 | impl<'a> PartialOrd for Inner<'a> { |
50 | fn partial_cmp(&self, other: &Inner<'a>) -> Option<Ordering> { |
51 | Some(self.cmp(other)) |
52 | } |
53 | } |
54 | |
55 | impl<'a> Hash for Inner<'a> { |
56 | fn hash<H: Hasher>(&self, h: &mut H) { |
57 | self.as_str().hash(state:h) |
58 | } |
59 | } |
60 | |
61 | impl<'a> Inner<'a> { |
62 | /// The underlying string. |
63 | pub fn as_str(&self) -> &str { |
64 | match self { |
65 | Inner::Static(s: &&str) => s, |
66 | Inner::Borrowed(s: &&str) => s, |
67 | Inner::Owned(s: &Arc) => s, |
68 | } |
69 | } |
70 | } |
71 | |
72 | impl<'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 | |
78 | impl<'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(op:Inner::Borrowed) |
84 | } |
85 | } |
86 | |
87 | assert_impl_all!(Str<'_>: Send, Sync, Unpin); |
88 | |
89 | impl<'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 | /// A borrowed clone (this never allocates, unlike clone). |
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 | |
124 | impl<'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: EncodingFormat) -> usize { |
129 | <&str>::alignment(format) |
130 | } |
131 | } |
132 | |
133 | impl<'a> Type for Str<'a> { |
134 | fn signature() -> Signature<'static> { |
135 | Signature::from_static_str_unchecked(Self::SIGNATURE_STR) |
136 | } |
137 | } |
138 | |
139 | impl<'a> From<&'a str> for Str<'a> { |
140 | fn from(value: &'a str) -> Self { |
141 | Self(Inner::Borrowed(value)) |
142 | } |
143 | } |
144 | |
145 | impl<'a> From<&'a String> for Str<'a> { |
146 | fn from(value: &'a String) -> Self { |
147 | Self(Inner::Borrowed(value)) |
148 | } |
149 | } |
150 | |
151 | impl<'a> From<String> for Str<'a> { |
152 | fn from(value: String) -> Self { |
153 | Self(Inner::Owned(value.into())) |
154 | } |
155 | } |
156 | |
157 | impl<'a> From<Arc<str>> for Str<'a> { |
158 | fn from(value: Arc<str>) -> Self { |
159 | Self(Inner::Owned(value)) |
160 | } |
161 | } |
162 | |
163 | impl<'a> From<Cow<'a, str>> for Str<'a> { |
164 | fn from(value: Cow<'a, str>) -> Self { |
165 | match value { |
166 | Cow::Owned(value: String) => value.into(), |
167 | Cow::Borrowed(value: &str) => value.into(), |
168 | } |
169 | } |
170 | } |
171 | |
172 | impl<'a> From<Str<'a>> for String { |
173 | fn from(value: Str<'a>) -> String { |
174 | match value.0 { |
175 | Inner::Static(s: &str) => s.into(), |
176 | Inner::Borrowed(s: &str) => s.into(), |
177 | Inner::Owned(s: Arc) => s.to_string(), |
178 | } |
179 | } |
180 | } |
181 | |
182 | impl<'a> From<&'a Str<'a>> for &'a str { |
183 | fn from(value: &'a Str<'a>) -> &'a str { |
184 | value.as_str() |
185 | } |
186 | } |
187 | |
188 | impl<'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 | |
196 | impl<'a> PartialEq<str> for Str<'a> { |
197 | fn eq(&self, other: &str) -> bool { |
198 | self.as_str() == other |
199 | } |
200 | } |
201 | |
202 | impl<'a> PartialEq<&str> for Str<'a> { |
203 | fn eq(&self, other: &&str) -> bool { |
204 | self.as_str() == *other |
205 | } |
206 | } |
207 | |
208 | impl<'a> std::fmt::Display for Str<'a> { |
209 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
210 | self.as_str().fmt(f) |
211 | } |
212 | } |
213 | |
214 | #[cfg (test)] |
215 | mod tests { |
216 | use super::Str; |
217 | |
218 | #[test ] |
219 | fn from_string() { |
220 | let string = String::from("value" ); |
221 | let v = Str::from(&string); |
222 | assert_eq!(v.as_str(), "value" ); |
223 | } |
224 | |
225 | #[test ] |
226 | fn test_ordering() { |
227 | let first = Str::from("a" .to_string()); |
228 | let second = Str::from_static("b" ); |
229 | assert!(first < second); |
230 | } |
231 | } |
232 | |