1 use serde::{Deserialize, Deserializer, Serialize, Serializer}; 2 use static_assertions::assert_impl_all; 3 use std::hash::{Hash, Hasher}; 4 5 use crate::{Basic, EncodingFormat, Signature, Type}; 6 7 /// A string wrapper. 8 /// 9 /// This is used for keeping strings in a [`Value`]. API is provided to convert from, and to a 10 /// [`&str`] and [`String`]. 11 /// 12 /// [`Value`]: enum.Value.html#variant.Str 13 /// [`&str`]: https://doc.rust-lang.org/std/str/index.html 14 /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html 15 #[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)] 16 #[serde(rename(serialize = "zvariant::Str", deserialize = "zvariant::Str"))] 17 pub struct Str<'a>(#[serde(borrow)] Inner<'a>); 18 19 #[derive(Debug, Eq, Clone)] 20 enum Inner<'a> { 21 Static(&'static str), 22 Borrowed(&'a str), 23 Owned(Box<str>), 24 } 25 26 impl<'a> Default for Inner<'a> { default() -> Self27 fn default() -> Self { 28 Self::Static("") 29 } 30 } 31 32 impl<'a> PartialEq for Inner<'a> { eq(&self, other: &Inner<'a>) -> bool33 fn eq(&self, other: &Inner<'a>) -> bool { 34 self.as_str() == other.as_str() 35 } 36 } 37 38 impl<'a> Hash for Inner<'a> { hash<H: Hasher>(&self, h: &mut H)39 fn hash<H: Hasher>(&self, h: &mut H) { 40 self.as_str().hash(h) 41 } 42 } 43 44 impl<'a> Inner<'a> { 45 /// The underlying string. as_str(&self) -> &str46 pub fn as_str(&self) -> &str { 47 match self { 48 Inner::Static(s) => s, 49 Inner::Borrowed(s) => s, 50 Inner::Owned(s) => s, 51 } 52 } 53 } 54 55 impl<'a> Serialize for Inner<'a> { serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error>56 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> { 57 s.serialize_str(self.as_str()) 58 } 59 } 60 61 impl<'de: 'a, 'a> Deserialize<'de> for Inner<'a> { deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,62 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 63 where 64 D: Deserializer<'de>, 65 { 66 <&'a str>::deserialize(deserializer).map(Inner::Borrowed) 67 } 68 } 69 70 assert_impl_all!(Str<'_>: Send, Sync, Unpin); 71 72 impl<'a> Str<'a> { 73 /// An owned string without allocations from_static(s: &'static str) -> Self74 pub fn from_static(s: &'static str) -> Self { 75 Str(Inner::Static(s)) 76 } 77 78 /// A borrowed clone (this never allocates, unlike clone). as_ref(&self) -> Str<'_>79 pub fn as_ref(&self) -> Str<'_> { 80 match &self.0 { 81 Inner::Static(s) => Str(Inner::Static(s)), 82 Inner::Borrowed(s) => Str(Inner::Borrowed(s)), 83 Inner::Owned(s) => Str(Inner::Borrowed(s)), 84 } 85 } 86 87 /// The underlying string. as_str(&self) -> &str88 pub fn as_str(&self) -> &str { 89 self.0.as_str() 90 } 91 92 /// Creates an owned clone of `self`. to_owned(&self) -> Str<'static>93 pub fn to_owned(&self) -> Str<'static> { 94 self.clone().into_owned() 95 } 96 97 /// Creates an owned clone of `self`. into_owned(self) -> Str<'static>98 pub fn into_owned(self) -> Str<'static> { 99 match self.0 { 100 Inner::Static(s) => Str(Inner::Static(s)), 101 Inner::Borrowed(s) => Str(Inner::Owned(s.into())), 102 Inner::Owned(s) => Str(Inner::Owned(s)), 103 } 104 } 105 } 106 107 impl<'a> Basic for Str<'a> { 108 const SIGNATURE_CHAR: char = <&str>::SIGNATURE_CHAR; 109 const SIGNATURE_STR: &'static str = <&str>::SIGNATURE_STR; 110 alignment(format: EncodingFormat) -> usize111 fn alignment(format: EncodingFormat) -> usize { 112 <&str>::alignment(format) 113 } 114 } 115 116 impl<'a> Type for Str<'a> { signature() -> Signature<'static>117 fn signature() -> Signature<'static> { 118 Signature::from_static_str_unchecked(Self::SIGNATURE_STR) 119 } 120 } 121 122 impl<'a> From<&'a str> for Str<'a> { from(value: &'a str) -> Self123 fn from(value: &'a str) -> Self { 124 Self(Inner::Borrowed(value)) 125 } 126 } 127 128 impl<'a> From<&'a String> for Str<'a> { from(value: &'a String) -> Self129 fn from(value: &'a String) -> Self { 130 Self(Inner::Borrowed(value)) 131 } 132 } 133 134 impl<'a> From<String> for Str<'a> { from(value: String) -> Self135 fn from(value: String) -> Self { 136 Self(Inner::Owned(value.into())) 137 } 138 } 139 140 impl<'a> From<Str<'a>> for String { from(value: Str<'a>) -> String141 fn from(value: Str<'a>) -> String { 142 match value.0 { 143 Inner::Static(s) => s.into(), 144 Inner::Borrowed(s) => s.into(), 145 Inner::Owned(s) => s.into(), 146 } 147 } 148 } 149 150 impl<'a> From<&'a Str<'a>> for &'a str { from(value: &'a Str<'a>) -> &'a str151 fn from(value: &'a Str<'a>) -> &'a str { 152 value.as_str() 153 } 154 } 155 156 impl<'a> std::ops::Deref for Str<'a> { 157 type Target = str; 158 deref(&self) -> &Self::Target159 fn deref(&self) -> &Self::Target { 160 self.as_str() 161 } 162 } 163 164 impl<'a> PartialEq<str> for Str<'a> { eq(&self, other: &str) -> bool165 fn eq(&self, other: &str) -> bool { 166 self.as_str() == other 167 } 168 } 169 170 impl<'a> PartialEq<&str> for Str<'a> { eq(&self, other: &&str) -> bool171 fn eq(&self, other: &&str) -> bool { 172 self.as_str() == *other 173 } 174 } 175 176 impl<'a> std::fmt::Display for Str<'a> { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 178 self.as_str().fmt(f) 179 } 180 } 181 182 #[cfg(test)] 183 mod tests { 184 use super::Str; 185 186 #[test] from_string()187 fn from_string() { 188 let string = String::from("value"); 189 let v = Str::from(&string); 190 assert_eq!(v.as_str(), "value"); 191 } 192 } 193