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::{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"))]
22pub struct Str<'a>(#[serde(borrow)] Inner<'a>);
23
24#[derive(Debug, 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(state: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: &&str) => s,
66 Inner::Borrowed(s: &&str) => s,
67 Inner::Owned(s: &Arc) => 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(op: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 /// 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
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: EncodingFormat) -> 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: String) => value.into(),
167 Cow::Borrowed(value: &str) => 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: &str) => s.into(),
176 Inner::Borrowed(s: &str) => s.into(),
177 Inner::Owned(s: Arc) => s.to_string(),
178 }
179 }
180}
181
182impl<'a> From<&'a Str<'a>> for &'a str {
183 fn from(value: &'a Str<'a>) -> &'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::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)]
215mod 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