| 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::{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" ))] |
| 22 | pub struct Str<'a>(#[serde(borrow)] Inner<'a>); |
| 23 | |
| 24 | #[derive (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: &&'static 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 | /// 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 | |
| 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: Format) -> 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: &'static 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<'_>> for &'a str { |
| 183 | fn from(value: &'a Str<'_>) -> &'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::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 | |
| 214 | impl<'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)] |
| 221 | mod 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 | } |
| 238 | |