1use crate::traits::{Parse, ToCss};
4#[cfg(feature = "visitor")]
5use crate::visitor::{Visit, VisitTypes, Visitor};
6use cssparser::{serialize_string, CowRcStr};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Deserializer};
9#[cfg(any(feature = "serde", feature = "nodejs"))]
10use serde::{Serialize, Serializer};
11use std::borrow::{Borrow, Cow};
12use std::cmp;
13use std::fmt;
14use std::hash;
15use std::marker::PhantomData;
16use std::ops::Deref;
17use std::rc::Rc;
18use std::slice;
19use std::str;
20use std::sync::Arc;
21
22struct LocalCowRcStr<'a> {
31 ptr: &'static (),
32 borrowed_len_or_max: usize,
33 phantom: PhantomData<Result<&'a str, Rc<String>>>,
34}
35
36pub struct CowArcStr<'a> {
39 ptr: &'static (),
40 borrowed_len_or_max: usize,
41 phantom: PhantomData<Result<&'a str, Arc<String>>>,
42}
43
44impl<'a> From<CowRcStr<'a>> for CowArcStr<'a> {
45 #[inline]
46 fn from(s: CowRcStr<'a>) -> Self {
47 (&s).into()
48 }
49}
50
51impl<'a> From<&CowRcStr<'a>> for CowArcStr<'a> {
52 #[inline]
53 fn from(s: &CowRcStr<'a>) -> Self {
54 let local = unsafe { std::mem::transmute::<&CowRcStr<'a>, &LocalCowRcStr<'a>>(&s) };
55 if local.borrowed_len_or_max == usize::MAX {
56 let ptr = local.ptr as *const () as *mut String;
62 CowArcStr::from(unsafe { (*ptr).clone() })
63 } else {
64 let s = unsafe {
65 str::from_utf8_unchecked(slice::from_raw_parts(
66 local.ptr as *const () as *const u8,
67 local.borrowed_len_or_max,
68 ))
69 };
70
71 CowArcStr::from(s)
72 }
73 }
74}
75
76impl<'a> From<&'a str> for CowArcStr<'a> {
79 #[inline]
80 fn from(s: &'a str) -> Self {
81 let len = s.len();
82 assert!(len < usize::MAX);
83 CowArcStr {
84 ptr: unsafe { &*(s.as_ptr() as *const ()) },
85 borrowed_len_or_max: len,
86 phantom: PhantomData,
87 }
88 }
89}
90
91impl<'a> From<String> for CowArcStr<'a> {
92 #[inline]
93 fn from(s: String) -> Self {
94 CowArcStr::from_arc(Arc::new(s))
95 }
96}
97
98impl<'a> From<Cow<'a, str>> for CowArcStr<'a> {
99 #[inline]
100 fn from(s: Cow<'a, str>) -> Self {
101 match s {
102 Cow::Borrowed(s) => s.into(),
103 Cow::Owned(s) => s.into(),
104 }
105 }
106}
107
108impl<'a> CowArcStr<'a> {
109 #[inline]
110 fn from_arc(s: Arc<String>) -> Self {
111 let ptr = unsafe { &*(Arc::into_raw(s) as *const ()) };
112 CowArcStr {
113 ptr,
114 borrowed_len_or_max: usize::MAX,
115 phantom: PhantomData,
116 }
117 }
118
119 #[inline]
120 fn unpack(&self) -> Result<&'a str, *const String> {
121 if self.borrowed_len_or_max == usize::MAX {
122 Err(self.ptr as *const () as *const String)
123 } else {
124 unsafe {
125 Ok(str::from_utf8_unchecked(slice::from_raw_parts(
126 self.ptr as *const () as *const u8,
127 self.borrowed_len_or_max,
128 )))
129 }
130 }
131 }
132}
133
134#[cfg(feature = "into_owned")]
135impl<'any> static_self::IntoOwned<'any> for CowArcStr<'_> {
136 type Owned = CowArcStr<'any>;
137
138 fn into_owned(self) -> Self::Owned {
140 if self.borrowed_len_or_max != usize::MAX {
141 CowArcStr::from(self.as_ref().to_owned())
142 } else {
143 unsafe { std::mem::transmute(self) }
144 }
145 }
146}
147
148impl<'a> Clone for CowArcStr<'a> {
149 #[inline]
150 fn clone(&self) -> Self {
151 match self.unpack() {
152 Err(ptr) => {
153 let rc = unsafe { Arc::from_raw(ptr) };
154 let new_rc = rc.clone();
155 std::mem::forget(rc); CowArcStr::from_arc(new_rc)
157 }
158 Ok(_) => CowArcStr { ..*self },
159 }
160 }
161}
162
163impl<'a> Drop for CowArcStr<'a> {
164 #[inline]
165 fn drop(&mut self) {
166 if let Err(ptr) = self.unpack() {
167 std::mem::drop(unsafe { Arc::from_raw(ptr) })
168 }
169 }
170}
171
172impl<'a> Deref for CowArcStr<'a> {
173 type Target = str;
174
175 #[inline]
176 fn deref(&self) -> &str {
177 self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr })
178 }
179}
180
181impl<'a> AsRef<str> for CowArcStr<'a> {
184 #[inline]
185 fn as_ref(&self) -> &str {
186 self
187 }
188}
189
190impl<'a> Borrow<str> for CowArcStr<'a> {
191 #[inline]
192 fn borrow(&self) -> &str {
193 self
194 }
195}
196
197impl<'a> Default for CowArcStr<'a> {
198 #[inline]
199 fn default() -> Self {
200 Self::from("")
201 }
202}
203
204impl<'a> hash::Hash for CowArcStr<'a> {
205 #[inline]
206 fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
207 str::hash(self, hasher)
208 }
209}
210
211impl<'a, T: AsRef<str>> PartialEq<T> for CowArcStr<'a> {
212 #[inline]
213 fn eq(&self, other: &T) -> bool {
214 str::eq(self, other.as_ref())
215 }
216}
217
218impl<'a, T: AsRef<str>> PartialOrd<T> for CowArcStr<'a> {
219 #[inline]
220 fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
221 str::partial_cmp(self, other.as_ref())
222 }
223}
224
225impl<'a> Eq for CowArcStr<'a> {}
226
227impl<'a> Ord for CowArcStr<'a> {
228 #[inline]
229 fn cmp(&self, other: &Self) -> cmp::Ordering {
230 str::cmp(self, other)
231 }
232}
233
234impl<'a> fmt::Display for CowArcStr<'a> {
235 #[inline]
236 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
237 str::fmt(self, formatter)
238 }
239}
240
241impl<'a> fmt::Debug for CowArcStr<'a> {
242 #[inline]
243 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
244 str::fmt(self, formatter)
245 }
246}
247
248#[cfg(any(feature = "nodejs", feature = "serde"))]
249impl<'a> Serialize for CowArcStr<'a> {
250 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
251 self.as_ref().serialize(serializer)
252 }
253}
254
255#[cfg(feature = "serde")]
256#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
257impl<'a, 'de: 'a> Deserialize<'de> for CowArcStr<'a> {
258 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
259 where
260 D: Deserializer<'de>,
261 {
262 deserializer.deserialize_str(CowArcStrVisitor)
263 }
264}
265
266#[cfg(feature = "jsonschema")]
267#[cfg_attr(docsrs, doc(cfg(feature = "jsonschema")))]
268impl<'a> schemars::JsonSchema for CowArcStr<'a> {
269 fn is_referenceable() -> bool {
270 true
271 }
272
273 fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
274 String::json_schema(gen)
275 }
276
277 fn schema_name() -> String {
278 "String".into()
279 }
280}
281
282#[cfg(feature = "serde")]
283struct CowArcStrVisitor;
284
285#[cfg(feature = "serde")]
286impl<'de> serde::de::Visitor<'de> for CowArcStrVisitor {
287 type Value = CowArcStr<'de>;
288
289 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
290 formatter.write_str("a CowArcStr")
291 }
292
293 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
294 where
295 E: serde::de::Error,
296 {
297 Ok(v.into())
298 }
299
300 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
301 where
302 E: serde::de::Error,
303 {
304 Ok(v.to_owned().into())
305 }
306
307 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
308 where
309 E: serde::de::Error,
310 {
311 Ok(v.into())
312 }
313}
314
315#[cfg(feature = "visitor")]
316impl<'i, V: ?Sized + Visitor<'i, T>, T: Visit<'i, T, V>> Visit<'i, T, V> for CowArcStr<'i> {
317 const CHILD_TYPES: VisitTypes = VisitTypes::empty();
318 fn visit_children(&mut self, _: &mut V) -> Result<(), V::Error> {
319 Ok(())
320 }
321}
322
323#[derive(Clone, Eq, Ord, Hash, Debug)]
325#[cfg_attr(feature = "visitor", derive(Visit))]
326#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
327#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize), serde(transparent))]
328#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
329pub struct CSSString<'i>(#[cfg_attr(feature = "serde", serde(borrow))] pub CowArcStr<'i>);
330
331impl<'i> Parse<'i> for CSSString<'i> {
332 fn parse<'t>(
333 input: &mut cssparser::Parser<'i, 't>,
334 ) -> Result<Self, cssparser::ParseError<'i, crate::error::ParserError<'i>>> {
335 let s = input.expect_string()?;
336 Ok(CSSString(s.into()))
337 }
338}
339
340impl<'i> ToCss for CSSString<'i> {
341 fn to_css<W>(&self, dest: &mut crate::printer::Printer<W>) -> Result<(), crate::error::PrinterError>
342 where
343 W: std::fmt::Write,
344 {
345 serialize_string(&self.0, dest)?;
346 Ok(())
347 }
348}
349
350impl<'i> cssparser::ToCss for CSSString<'i> {
351 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
352 where
353 W: fmt::Write,
354 {
355 serialize_string(&self.0, dest)
356 }
357}
358
359macro_rules! impl_string_type {
360 ($t: ident) => {
361 impl<'i> From<CowRcStr<'i>> for $t<'i> {
362 fn from(s: CowRcStr<'i>) -> Self {
363 $t(s.into())
364 }
365 }
366
367 impl<'a> From<&CowRcStr<'a>> for $t<'a> {
368 fn from(s: &CowRcStr<'a>) -> Self {
369 $t(s.into())
370 }
371 }
372
373 impl<'i> From<String> for $t<'i> {
374 fn from(s: String) -> Self {
375 $t(s.into())
376 }
377 }
378
379 impl<'i> From<&'i str> for $t<'i> {
380 fn from(s: &'i str) -> Self {
381 $t(s.into())
382 }
383 }
384
385 impl<'a> From<std::borrow::Cow<'a, str>> for $t<'a> {
386 #[inline]
387 fn from(s: std::borrow::Cow<'a, str>) -> Self {
388 match s {
389 std::borrow::Cow::Borrowed(s) => s.into(),
390 std::borrow::Cow::Owned(s) => s.into(),
391 }
392 }
393 }
394
395 impl<'a> Deref for $t<'a> {
396 type Target = str;
397
398 #[inline]
399 fn deref(&self) -> &str {
400 self.0.deref()
401 }
402 }
403
404 impl<'a> AsRef<str> for $t<'a> {
405 #[inline]
406 fn as_ref(&self) -> &str {
407 self
408 }
409 }
410
411 impl<'a> Borrow<str> for $t<'a> {
412 #[inline]
413 fn borrow(&self) -> &str {
414 self
415 }
416 }
417
418 impl<'a> std::fmt::Display for $t<'a> {
419 #[inline]
420 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
421 str::fmt(self, formatter)
422 }
423 }
424
425 impl<'a, T: AsRef<str>> PartialEq<T> for $t<'a> {
426 #[inline]
427 fn eq(&self, other: &T) -> bool {
428 str::eq(self, other.as_ref())
429 }
430 }
431
432 impl<'a, T: AsRef<str>> PartialOrd<T> for $t<'a> {
433 #[inline]
434 fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
435 str::partial_cmp(self, other.as_ref())
436 }
437 }
438 };
439}
440
441impl_string_type!(CSSString);
442
443pub(crate) use impl_string_type;