mail_headers/data/
inner_item.rs1use std::ops::Deref;
2use std::sync::Arc;
3use std::borrow::ToOwned;
4
5use owning_ref::OwningRef;
6use soft_ascii_string::{SoftAsciiString, SoftAsciiStr};
7
8#[cfg(feature="serde")]
9use serde::{Serialize, Deserialize, Serializer, Deserializer, de::Error as __Error};
10
11
12#[derive(Debug, Clone, Hash, Eq)]
16pub enum InnerAscii {
17 Owned(SoftAsciiString),
18 Shared(OwningRef<Arc<String>, SoftAsciiStr>)
20}
21
22impl InnerAscii {
23
24 pub fn into_shared(self) -> Self {
37 match self {
38 InnerAscii::Owned(value) => {
39 let buffer: Arc<String> = Arc::new(value.into());
40 let orf = OwningRef::new(buffer).map(|data: &String| {
41 SoftAsciiStr::from_unchecked(&**data)
43 });
44 InnerAscii::Shared(orf)
45 }
46 v => v
47 }
48 }
49}
50
51#[derive(Debug, Clone, Hash, Eq)]
55pub enum InnerUtf8 {
56 Owned(String),
57 Shared(OwningRef<Arc<String>, str>)
59}
60
61impl InnerUtf8 {
62
63 pub fn into_shared(self) -> Self {
69 match self {
70 InnerUtf8::Owned(value) => {
71 let buffer = Arc::new(value);
72 let orf = OwningRef::new(buffer)
73 .map(|rced| &**rced);
74 InnerUtf8::Shared(orf)
75 }
76 v => v
77 }
78 }
79}
80
81
82macro_rules! inner_impl {
83 ($name:ident, $owned_form:ty, $borrowed_form:ty) => (
84 impl $name {
85 pub fn new<S: Into<$owned_form>>( data: S ) -> Self {
86 $name::Owned( data.into() )
87 }
88 }
89 impl From<$owned_form> for $name {
90 fn from( data: $owned_form ) -> Self {
91 Self::new( data )
92 }
93 }
94
95 impl Into<$owned_form> for $name {
96 fn into(self) -> $owned_form {
97 match self {
98 $name::Owned( owned ) => owned,
99 $name::Shared( shared ) => {
100 let as_ref: &$borrowed_form = &*shared;
101 as_ref.to_owned()
102 }
103 }
104 }
105 }
106
107 impl Deref for $name {
108 type Target = $borrowed_form;
109
110 fn deref( &self ) -> &$borrowed_form{
111 match *self {
112 $name::Owned( ref string ) => &*string,
113 $name::Shared( ref owning_ref ) => &*owning_ref
114 }
115 }
116 }
117
118 #[cfg(feature="serde")]
119 impl Serialize for $name {
120 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
121 where S: Serializer
122 {
123 let borrowed: &$borrowed_form = &*self;
124 let as_ref: &str = borrowed.as_ref();
125 serializer.serialize_str( as_ref )
126 }
127 }
128
129 impl PartialEq for $name {
130 fn eq(&self, other: &$name) -> bool {
131 let me: &$borrowed_form = &*self;
132 let other: &$borrowed_form = &*other;
133 me == other
134 }
135 }
136
137 impl AsRef<str> for $name {
138 fn as_ref(&self) -> &str {
139 self.as_str()
140 }
141 }
142 );
143}
144
145inner_impl!{ InnerAscii, SoftAsciiString, SoftAsciiStr }
146inner_impl!{ InnerUtf8, String, str }
147impl InnerAscii {
150 pub fn as_str( &self ) -> &str {
151 match *self {
152 InnerAscii::Owned( ref owned ) => owned.as_str(),
153 InnerAscii::Shared( ref shared ) => shared.as_str()
154 }
155 }
156}
157
158#[cfg(feature="serde")]
159impl<'de> Deserialize<'de> for InnerAscii {
160 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
161 where D: Deserializer<'de>
162 {
163 let content = String::deserialize(deserializer)
164 .map_err(|err| D::Error::custom(err))?;
165 let content = SoftAsciiString::from_string(content)
166 .map_err(|err| D::Error::custom(err))?;
167 Ok(InnerAscii::from(content))
168 }
169}
170
171impl InnerUtf8 {
172 pub fn as_str( &self ) -> &str {
173 match *self {
174 InnerUtf8::Owned( ref owned ) => owned.as_str(),
175 InnerUtf8::Shared( ref shared ) => &**shared
176 }
177 }
178}
179
180#[cfg(feature="serde")]
181impl<'de> Deserialize<'de> for InnerUtf8 {
182 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
183 where D: Deserializer<'de>
184 {
185 let content = String::deserialize(deserializer)
186 .map_err(|err| D::Error::custom(err))?;
187 Ok(InnerUtf8::from(content))
188 }
189}
190
191
192#[cfg(test)]
193mod test {
194 use super::*;
195
196 #[test]
197 fn inner_ascii_item_eq() {
198 let a = InnerAscii::Owned( SoftAsciiString::from_string( "same" ).unwrap() );
199 let b = InnerAscii::Shared(
200 OwningRef::new(Arc::new("same".to_owned()))
201 .map(|v| SoftAsciiStr::from_unchecked(&**v))
202 );
203 assert_eq!( a, b );
204 }
205
206 #[test]
207 fn inner_ascii_item_neq() {
208 let a = InnerAscii::Owned( SoftAsciiString::from_string( "same" ).unwrap() );
209 let b = InnerAscii::Shared(
210 OwningRef::new(Arc::new("not same".to_owned()))
211 .map(|v| SoftAsciiStr::from_unchecked(&**v))
212 );
213 assert_ne!( a, b );
214 }
215
216 #[test]
217 fn inner_utf8_item_eq() {
218 let a = InnerUtf8::Owned( String::from( "same" ) );
219 let b = InnerUtf8::Shared(
220 OwningRef::new(
221 Arc::new( String::from( "same" ) ) )
222 .map(|v| &**v)
223 );
224 assert_eq!( a, b );
225 }
226
227 #[test]
228 fn inner_utf8_item_neq() {
229 let a = InnerUtf8::Owned( String::from( "same" ) );
230 let b = InnerUtf8::Shared(
231 OwningRef::new(
232 Arc::new( String::from( "not same" ) ) )
233 .map(|v| &**v)
234 );
235 assert_ne!( a, b );
236 }
237
238 #[test]
239 fn has_as_str() {
240 use std::borrow::ToOwned;
241
242 assert_eq!(
243 "hy",
244 InnerAscii::Owned( SoftAsciiStr::from_unchecked("hy").to_owned() ).as_str()
245 );
246 assert_eq!(
247 "hy",
248 InnerUtf8::Owned( "hy".into() ).as_str()
249 );
250 }
251}