/src/rust-cssparser/src/cow_rc_str.rs
Line | Count | Source |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | use std::borrow::{Borrow, Cow}; |
6 | | use std::rc::Rc; |
7 | | use std::{cmp, fmt, hash, marker, mem, ops, ptr, slice, str}; |
8 | | |
9 | | /// A string that is either shared (heap-allocated and reference-counted) or borrowed. |
10 | | /// |
11 | | /// Equivalent to `enum { Borrowed(&'a str), Shared(Rc<String>) }`, but stored more compactly. |
12 | | /// |
13 | | /// * If `borrowed_len_or_max == usize::MAX`, then `ptr` represents `NonZero<*const String>` |
14 | | /// from `Rc::into_raw`. |
15 | | /// The lifetime parameter `'a` is irrelevant in this case. |
16 | | /// |
17 | | /// * Otherwise, `ptr` represents the `NonZero<*const u8>` data component of `&'a str`, |
18 | | /// and `borrowed_len_or_max` its length. |
19 | | pub struct CowRcStr<'a> { |
20 | | ptr: ptr::NonNull<()>, |
21 | | borrowed_len_or_max: usize, |
22 | | |
23 | | phantom: marker::PhantomData<Result<&'a str, Rc<String>>>, |
24 | | } |
25 | | |
26 | | fn _static_assert_same_size() { |
27 | | // "Instantiate" the generic function without calling it. |
28 | | let _ = mem::transmute::<CowRcStr<'_>, Option<CowRcStr<'_>>>; |
29 | | } |
30 | | |
31 | | impl<'a> From<Cow<'a, str>> for CowRcStr<'a> { |
32 | | #[inline] |
33 | | fn from(s: Cow<'a, str>) -> Self { |
34 | | match s { |
35 | | Cow::Borrowed(s) => CowRcStr::from(s), |
36 | | Cow::Owned(s) => CowRcStr::from(s), |
37 | | } |
38 | | } |
39 | | } |
40 | | |
41 | | impl<'a> From<&'a str> for CowRcStr<'a> { |
42 | | #[inline] |
43 | 832k | fn from(s: &'a str) -> Self { |
44 | 832k | let len = s.len(); |
45 | | // Guaranteed by https://doc.rust-lang.org/stable/reference/types/numeric.html: |
46 | | // The theoretical upper bound on object and array size is the maximum isize value |
47 | | // (which by definition is smaller than usize::MAX). |
48 | 832k | debug_assert!(len < usize::MAX); |
49 | 832k | CowRcStr { |
50 | 832k | ptr: unsafe { ptr::NonNull::new_unchecked(s.as_ptr() as *mut ()) }, |
51 | 832k | borrowed_len_or_max: len, |
52 | 832k | phantom: marker::PhantomData, |
53 | 832k | } |
54 | 832k | } |
55 | | } |
56 | | |
57 | | impl From<String> for CowRcStr<'_> { |
58 | | #[inline] |
59 | 158k | fn from(s: String) -> Self { |
60 | 158k | CowRcStr::from_rc(Rc::new(s)) |
61 | 158k | } |
62 | | } |
63 | | |
64 | | impl<'a> CowRcStr<'a> { |
65 | | #[inline] |
66 | 158k | fn from_rc(s: Rc<String>) -> Self { |
67 | 158k | let ptr = unsafe { ptr::NonNull::new_unchecked(Rc::into_raw(s) as *mut ()) }; |
68 | 158k | CowRcStr { |
69 | 158k | ptr, |
70 | 158k | borrowed_len_or_max: usize::MAX, |
71 | 158k | phantom: marker::PhantomData, |
72 | 158k | } |
73 | 158k | } |
74 | | |
75 | | #[inline] |
76 | 1.96M | fn unpack(&self) -> Result<&'a str, *const String> { |
77 | 1.96M | if self.borrowed_len_or_max == usize::MAX { |
78 | 310k | Err(self.ptr.as_ptr() as *const String) |
79 | | } else { |
80 | | unsafe { |
81 | 1.65M | Ok(str::from_utf8_unchecked(slice::from_raw_parts( |
82 | 1.65M | self.ptr.as_ptr() as *const u8, |
83 | 1.65M | self.borrowed_len_or_max, |
84 | 1.65M | ))) |
85 | | } |
86 | | } |
87 | 1.96M | } <cssparser::cow_rc_str::CowRcStr>::unpack Line | Count | Source | 76 | 928k | fn unpack(&self) -> Result<&'a str, *const String> { | 77 | 928k | if self.borrowed_len_or_max == usize::MAX { | 78 | 144k | Err(self.ptr.as_ptr() as *const String) | 79 | | } else { | 80 | | unsafe { | 81 | 783k | Ok(str::from_utf8_unchecked(slice::from_raw_parts( | 82 | 783k | self.ptr.as_ptr() as *const u8, | 83 | 783k | self.borrowed_len_or_max, | 84 | 783k | ))) | 85 | | } | 86 | | } | 87 | 928k | } |
<cssparser::cow_rc_str::CowRcStr>::unpack Line | Count | Source | 76 | 1.03M | fn unpack(&self) -> Result<&'a str, *const String> { | 77 | 1.03M | if self.borrowed_len_or_max == usize::MAX { | 78 | 166k | Err(self.ptr.as_ptr() as *const String) | 79 | | } else { | 80 | | unsafe { | 81 | 873k | Ok(str::from_utf8_unchecked(slice::from_raw_parts( | 82 | 873k | self.ptr.as_ptr() as *const u8, | 83 | 873k | self.borrowed_len_or_max, | 84 | 873k | ))) | 85 | | } | 86 | | } | 87 | 1.03M | } |
|
88 | | } |
89 | | |
90 | | impl Clone for CowRcStr<'_> { |
91 | | #[inline] |
92 | | fn clone(&self) -> Self { |
93 | | match self.unpack() { |
94 | | Err(ptr) => { |
95 | | let rc = unsafe { Rc::from_raw(ptr) }; |
96 | | let new_rc = rc.clone(); |
97 | | mem::forget(rc); // Don’t actually take ownership of this strong reference |
98 | | CowRcStr::from_rc(new_rc) |
99 | | } |
100 | | Ok(_) => CowRcStr { ..*self }, |
101 | | } |
102 | | } |
103 | | } |
104 | | |
105 | | #[cold] |
106 | | #[inline(never)] |
107 | 158k | unsafe fn drop_slow(ptr: *const String) { |
108 | 158k | unsafe { mem::drop(Rc::from_raw(ptr)) } |
109 | 158k | } |
110 | | |
111 | | impl Drop for CowRcStr<'_> { |
112 | | #[inline] |
113 | 990k | fn drop(&mut self) { |
114 | 990k | if let Err(ptr) = self.unpack() { |
115 | 158k | unsafe { drop_slow(ptr) } |
116 | 832k | } |
117 | 990k | } |
118 | | } |
119 | | |
120 | | impl ops::Deref for CowRcStr<'_> { |
121 | | type Target = str; |
122 | | |
123 | | #[inline] |
124 | 977k | fn deref(&self) -> &str { |
125 | 977k | self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr }) |
126 | 977k | } <cssparser::cow_rc_str::CowRcStr as core::ops::deref::Deref>::deref Line | Count | Source | 124 | 928k | fn deref(&self) -> &str { | 125 | 928k | self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr }) | 126 | 928k | } |
<cssparser::cow_rc_str::CowRcStr as core::ops::deref::Deref>::deref Line | Count | Source | 124 | 49.4k | fn deref(&self) -> &str { | 125 | 49.4k | self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr }) | 126 | 49.4k | } |
|
127 | | } |
128 | | |
129 | | // Boilerplate / trivial impls below. |
130 | | |
131 | | impl AsRef<str> for CowRcStr<'_> { |
132 | | #[inline] |
133 | | fn as_ref(&self) -> &str { |
134 | | self |
135 | | } |
136 | | } |
137 | | |
138 | | impl Borrow<str> for CowRcStr<'_> { |
139 | | #[inline] |
140 | | fn borrow(&self) -> &str { |
141 | | self |
142 | | } |
143 | | } |
144 | | |
145 | | impl Default for CowRcStr<'_> { |
146 | | #[inline] |
147 | | fn default() -> Self { |
148 | | Self::from("") |
149 | | } |
150 | | } |
151 | | |
152 | | impl hash::Hash for CowRcStr<'_> { |
153 | | #[inline] |
154 | | fn hash<H: hash::Hasher>(&self, hasher: &mut H) { |
155 | | str::hash(self, hasher) |
156 | | } |
157 | | } |
158 | | |
159 | | impl<T: AsRef<str>> PartialEq<T> for CowRcStr<'_> { |
160 | | #[inline] |
161 | | fn eq(&self, other: &T) -> bool { |
162 | | str::eq(self, other.as_ref()) |
163 | | } |
164 | | } |
165 | | |
166 | | impl<T: AsRef<str>> PartialOrd<T> for CowRcStr<'_> { |
167 | | #[inline] |
168 | | fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> { |
169 | | str::partial_cmp(self, other.as_ref()) |
170 | | } |
171 | | } |
172 | | |
173 | | impl Eq for CowRcStr<'_> {} |
174 | | |
175 | | impl Ord for CowRcStr<'_> { |
176 | | #[inline] |
177 | | fn cmp(&self, other: &Self) -> cmp::Ordering { |
178 | | str::cmp(self, other) |
179 | | } |
180 | | } |
181 | | |
182 | | impl fmt::Display for CowRcStr<'_> { |
183 | | #[inline] |
184 | | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
185 | | str::fmt(self, formatter) |
186 | | } |
187 | | } |
188 | | |
189 | | impl fmt::Debug for CowRcStr<'_> { |
190 | | #[inline] |
191 | | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
192 | | str::fmt(self, formatter) |
193 | | } |
194 | | } |