1use std::borrow::{Borrow, Cow};
6use std::rc::Rc;
7use std::{cmp, fmt, hash, marker, mem, ops, ptr, slice, str};
8
9pub 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
26fn _static_assert_same_size() {
27 let _ = mem::transmute::<CowRcStr<'_>, Option<CowRcStr<'_>>>;
29}
30
31impl<'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
41impl<'a> From<&'a str> for CowRcStr<'a> {
42 #[inline]
43 fn from(s: &'a str) -> Self {
44 let len = s.len();
45 debug_assert!(len < usize::MAX);
49 CowRcStr {
50 ptr: unsafe { ptr::NonNull::new_unchecked(s.as_ptr() as *mut ()) },
51 borrowed_len_or_max: len,
52 phantom: marker::PhantomData,
53 }
54 }
55}
56
57impl From<String> for CowRcStr<'_> {
58 #[inline]
59 fn from(s: String) -> Self {
60 CowRcStr::from_rc(Rc::new(s))
61 }
62}
63
64impl<'a> CowRcStr<'a> {
65 #[inline]
66 fn from_rc(s: Rc<String>) -> Self {
67 let ptr = unsafe { ptr::NonNull::new_unchecked(Rc::into_raw(s) as *mut ()) };
68 CowRcStr {
69 ptr,
70 borrowed_len_or_max: usize::MAX,
71 phantom: marker::PhantomData,
72 }
73 }
74
75 #[inline]
76 fn unpack(&self) -> Result<&'a str, *const String> {
77 if self.borrowed_len_or_max == usize::MAX {
78 Err(self.ptr.as_ptr() as *const String)
79 } else {
80 unsafe {
81 Ok(str::from_utf8_unchecked(slice::from_raw_parts(
82 self.ptr.as_ptr() as *const u8,
83 self.borrowed_len_or_max,
84 )))
85 }
86 }
87 }
88}
89
90impl 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); CowRcStr::from_rc(new_rc)
99 }
100 Ok(_) => CowRcStr { ..*self },
101 }
102 }
103}
104
105#[cold]
106#[inline(never)]
107unsafe fn drop_slow(ptr: *const String) {
108 unsafe { mem::drop(Rc::from_raw(ptr)) }
109}
110
111impl Drop for CowRcStr<'_> {
112 #[inline]
113 fn drop(&mut self) {
114 if let Err(ptr) = self.unpack() {
115 unsafe { drop_slow(ptr) }
116 }
117 }
118}
119
120impl ops::Deref for CowRcStr<'_> {
121 type Target = str;
122
123 #[inline]
124 fn deref(&self) -> &str {
125 self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr })
126 }
127}
128
129impl AsRef<str> for CowRcStr<'_> {
132 #[inline]
133 fn as_ref(&self) -> &str {
134 self
135 }
136}
137
138impl Borrow<str> for CowRcStr<'_> {
139 #[inline]
140 fn borrow(&self) -> &str {
141 self
142 }
143}
144
145impl Default for CowRcStr<'_> {
146 #[inline]
147 fn default() -> Self {
148 Self::from("")
149 }
150}
151
152impl hash::Hash for CowRcStr<'_> {
153 #[inline]
154 fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
155 str::hash(self, hasher)
156 }
157}
158
159impl<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
166impl<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
173impl Eq for CowRcStr<'_> {}
174
175impl Ord for CowRcStr<'_> {
176 #[inline]
177 fn cmp(&self, other: &Self) -> cmp::Ordering {
178 str::cmp(self, other)
179 }
180}
181
182impl fmt::Display for CowRcStr<'_> {
183 #[inline]
184 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
185 str::fmt(self, formatter)
186 }
187}
188
189impl fmt::Debug for CowRcStr<'_> {
190 #[inline]
191 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
192 str::fmt(self, formatter)
193 }
194}