/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 | 1.29M | fn from(s: &'a str) -> Self { |
44 | 1.29M | let len = s.len(); |
45 | 1.29M | assert!(len < usize::MAX); |
46 | 1.29M | CowRcStr { |
47 | 1.29M | ptr: unsafe { ptr::NonNull::new_unchecked(s.as_ptr() as *mut ()) }, |
48 | 1.29M | borrowed_len_or_max: len, |
49 | 1.29M | phantom: marker::PhantomData, |
50 | 1.29M | } |
51 | 1.29M | } |
52 | | } |
53 | | |
54 | | impl From<String> for CowRcStr<'_> { |
55 | | #[inline] |
56 | 495k | fn from(s: String) -> Self { |
57 | 495k | CowRcStr::from_rc(Rc::new(s)) |
58 | 495k | } |
59 | | } |
60 | | |
61 | | impl<'a> CowRcStr<'a> { |
62 | | #[inline] |
63 | 495k | fn from_rc(s: Rc<String>) -> Self { |
64 | 495k | let ptr = unsafe { ptr::NonNull::new_unchecked(Rc::into_raw(s) as *mut ()) }; |
65 | 495k | CowRcStr { |
66 | 495k | ptr, |
67 | 495k | borrowed_len_or_max: usize::MAX, |
68 | 495k | phantom: marker::PhantomData, |
69 | 495k | } |
70 | 495k | } <cssparser::cow_rc_str::CowRcStr>::from_rc Line | Count | Source | 63 | 2 | fn from_rc(s: Rc<String>) -> Self { | 64 | 2 | let ptr = unsafe { ptr::NonNull::new_unchecked(Rc::into_raw(s) as *mut ()) }; | 65 | 2 | CowRcStr { | 66 | 2 | ptr, | 67 | 2 | borrowed_len_or_max: usize::MAX, | 68 | 2 | phantom: marker::PhantomData, | 69 | 2 | } | 70 | 2 | } |
<cssparser::cow_rc_str::CowRcStr>::from_rc Line | Count | Source | 63 | 495k | fn from_rc(s: Rc<String>) -> Self { | 64 | 495k | let ptr = unsafe { ptr::NonNull::new_unchecked(Rc::into_raw(s) as *mut ()) }; | 65 | 495k | CowRcStr { | 66 | 495k | ptr, | 67 | 495k | borrowed_len_or_max: usize::MAX, | 68 | 495k | phantom: marker::PhantomData, | 69 | 495k | } | 70 | 495k | } |
|
71 | | |
72 | | #[inline] |
73 | 3.66M | fn unpack(&self) -> Result<&'a str, *const String> { |
74 | 3.66M | if self.borrowed_len_or_max == usize::MAX { |
75 | 1.09M | Err(self.ptr.as_ptr() as *const String) |
76 | | } else { |
77 | | unsafe { |
78 | 2.57M | Ok(str::from_utf8_unchecked(slice::from_raw_parts( |
79 | 2.57M | self.ptr.as_ptr() as *const u8, |
80 | 2.57M | self.borrowed_len_or_max, |
81 | 2.57M | ))) |
82 | | } |
83 | | } |
84 | 3.66M | } <cssparser::cow_rc_str::CowRcStr>::unpack Line | Count | Source | 73 | 1.69M | fn unpack(&self) -> Result<&'a str, *const String> { | 74 | 1.69M | if self.borrowed_len_or_max == usize::MAX { | 75 | 485k | Err(self.ptr.as_ptr() as *const String) | 76 | | } else { | 77 | | unsafe { | 78 | 1.21M | Ok(str::from_utf8_unchecked(slice::from_raw_parts( | 79 | 1.21M | self.ptr.as_ptr() as *const u8, | 80 | 1.21M | self.borrowed_len_or_max, | 81 | 1.21M | ))) | 82 | | } | 83 | | } | 84 | 1.69M | } |
<cssparser::cow_rc_str::CowRcStr>::unpack Line | Count | Source | 73 | 1.97M | fn unpack(&self) -> Result<&'a str, *const String> { | 74 | 1.97M | if self.borrowed_len_or_max == usize::MAX { | 75 | 613k | Err(self.ptr.as_ptr() as *const String) | 76 | | } else { | 77 | | unsafe { | 78 | 1.36M | Ok(str::from_utf8_unchecked(slice::from_raw_parts( | 79 | 1.36M | self.ptr.as_ptr() as *const u8, | 80 | 1.36M | self.borrowed_len_or_max, | 81 | 1.36M | ))) | 82 | | } | 83 | | } | 84 | 1.97M | } |
|
85 | | } |
86 | | |
87 | | impl Clone for CowRcStr<'_> { |
88 | | #[inline] |
89 | 311 | fn clone(&self) -> Self { |
90 | 311 | match self.unpack() { |
91 | 2 | Err(ptr) => { |
92 | 2 | let rc = unsafe { Rc::from_raw(ptr) }; |
93 | 2 | let new_rc = rc.clone(); |
94 | 2 | mem::forget(rc); // Don’t actually take ownership of this strong reference |
95 | 2 | CowRcStr::from_rc(new_rc) |
96 | | } |
97 | 309 | Ok(_) => CowRcStr { ..*self }, |
98 | | } |
99 | 311 | } <cssparser::cow_rc_str::CowRcStr as core::clone::Clone>::clone Line | Count | Source | 89 | 311 | fn clone(&self) -> Self { | 90 | 311 | match self.unpack() { | 91 | 2 | Err(ptr) => { | 92 | 2 | let rc = unsafe { Rc::from_raw(ptr) }; | 93 | 2 | let new_rc = rc.clone(); | 94 | 2 | mem::forget(rc); // Don’t actually take ownership of this strong reference | 95 | 2 | CowRcStr::from_rc(new_rc) | 96 | | } | 97 | 309 | Ok(_) => CowRcStr { ..*self }, | 98 | | } | 99 | 311 | } |
Unexecuted instantiation: <cssparser::cow_rc_str::CowRcStr as core::clone::Clone>::clone |
100 | | } |
101 | | |
102 | | impl Drop for CowRcStr<'_> { |
103 | | #[inline] |
104 | 1.79M | fn drop(&mut self) { |
105 | 1.79M | if let Err(ptr) = self.unpack() { |
106 | 495k | mem::drop(unsafe { Rc::from_raw(ptr) }) |
107 | 1.29M | } |
108 | 1.79M | } |
109 | | } |
110 | | |
111 | | impl ops::Deref for CowRcStr<'_> { |
112 | | type Target = str; |
113 | | |
114 | | #[inline] |
115 | 1.87M | fn deref(&self) -> &str { |
116 | 1.87M | self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr }) |
117 | 1.87M | } <cssparser::cow_rc_str::CowRcStr as core::ops::deref::Deref>::deref Line | Count | Source | 115 | 1.69M | fn deref(&self) -> &str { | 116 | 1.69M | self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr }) | 117 | 1.69M | } |
<cssparser::cow_rc_str::CowRcStr as core::ops::deref::Deref>::deref Line | Count | Source | 115 | 180k | fn deref(&self) -> &str { | 116 | 180k | self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr }) | 117 | 180k | } |
|
118 | | } |
119 | | |
120 | | // Boilerplate / trivial impls below. |
121 | | |
122 | | impl AsRef<str> for CowRcStr<'_> { |
123 | | #[inline] |
124 | | fn as_ref(&self) -> &str { |
125 | | self |
126 | | } |
127 | | } |
128 | | |
129 | | impl Borrow<str> for CowRcStr<'_> { |
130 | | #[inline] |
131 | | fn borrow(&self) -> &str { |
132 | | self |
133 | | } |
134 | | } |
135 | | |
136 | | impl Default for CowRcStr<'_> { |
137 | | #[inline] |
138 | | fn default() -> Self { |
139 | | Self::from("") |
140 | | } |
141 | | } |
142 | | |
143 | | impl hash::Hash for CowRcStr<'_> { |
144 | | #[inline] |
145 | | fn hash<H: hash::Hasher>(&self, hasher: &mut H) { |
146 | | str::hash(self, hasher) |
147 | | } |
148 | | } |
149 | | |
150 | | impl<T: AsRef<str>> PartialEq<T> for CowRcStr<'_> { |
151 | | #[inline] |
152 | | fn eq(&self, other: &T) -> bool { |
153 | | str::eq(self, other.as_ref()) |
154 | | } |
155 | | } |
156 | | |
157 | | impl<T: AsRef<str>> PartialOrd<T> for CowRcStr<'_> { |
158 | | #[inline] |
159 | | fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> { |
160 | | str::partial_cmp(self, other.as_ref()) |
161 | | } |
162 | | } |
163 | | |
164 | | impl Eq for CowRcStr<'_> {} |
165 | | |
166 | | impl Ord for CowRcStr<'_> { |
167 | | #[inline] |
168 | | fn cmp(&self, other: &Self) -> cmp::Ordering { |
169 | | str::cmp(self, other) |
170 | | } |
171 | | } |
172 | | |
173 | | impl fmt::Display for CowRcStr<'_> { |
174 | | #[inline] |
175 | 0 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
176 | 0 | str::fmt(self, formatter) |
177 | 0 | } |
178 | | } |
179 | | |
180 | | impl fmt::Debug for CowRcStr<'_> { |
181 | | #[inline] |
182 | 0 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
183 | 0 | str::fmt(self, formatter) |
184 | 0 | } |
185 | | } |