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 assert!(len < usize::MAX);
46 CowRcStr {
47 ptr: unsafe { ptr::NonNull::new_unchecked(s.as_ptr() as *mut ()) },
48 borrowed_len_or_max: len,
49 phantom: marker::PhantomData,
50 }
51 }
52}
53
54impl From<String> for CowRcStr<'_> {
55 #[inline]
56 fn from(s: String) -> Self {
57 CowRcStr::from_rc(Rc::new(s))
58 }
59}
60
61impl<'a> CowRcStr<'a> {
62 #[inline]
63 fn from_rc(s: Rc<String>) -> Self {
64 let ptr = unsafe { ptr::NonNull::new_unchecked(Rc::into_raw(s) as *mut ()) };
65 CowRcStr {
66 ptr,
67 borrowed_len_or_max: usize::MAX,
68 phantom: marker::PhantomData,
69 }
70 }
71
72 #[inline]
73 fn unpack(&self) -> Result<&'a str, *const String> {
74 if self.borrowed_len_or_max == usize::MAX {
75 Err(self.ptr.as_ptr() as *const String)
76 } else {
77 unsafe {
78 Ok(str::from_utf8_unchecked(slice::from_raw_parts(
79 self.ptr.as_ptr() as *const u8,
80 self.borrowed_len_or_max,
81 )))
82 }
83 }
84 }
85}
86
87impl Clone for CowRcStr<'_> {
88 #[inline]
89 fn clone(&self) -> Self {
90 match self.unpack() {
91 Err(ptr) => {
92 let rc = unsafe { Rc::from_raw(ptr) };
93 let new_rc = rc.clone();
94 mem::forget(rc); CowRcStr::from_rc(new_rc)
96 }
97 Ok(_) => CowRcStr { ..*self },
98 }
99 }
100}
101
102impl Drop for CowRcStr<'_> {
103 #[inline]
104 fn drop(&mut self) {
105 if let Err(ptr) = self.unpack() {
106 mem::drop(unsafe { Rc::from_raw(ptr) })
107 }
108 }
109}
110
111impl ops::Deref for CowRcStr<'_> {
112 type Target = str;
113
114 #[inline]
115 fn deref(&self) -> &str {
116 self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr })
117 }
118}
119
120impl AsRef<str> for CowRcStr<'_> {
123 #[inline]
124 fn as_ref(&self) -> &str {
125 self
126 }
127}
128
129impl Borrow<str> for CowRcStr<'_> {
130 #[inline]
131 fn borrow(&self) -> &str {
132 self
133 }
134}
135
136impl Default for CowRcStr<'_> {
137 #[inline]
138 fn default() -> Self {
139 Self::from("")
140 }
141}
142
143impl hash::Hash for CowRcStr<'_> {
144 #[inline]
145 fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
146 str::hash(self, hasher)
147 }
148}
149
150impl<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
157impl<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
164impl Eq for CowRcStr<'_> {}
165
166impl Ord for CowRcStr<'_> {
167 #[inline]
168 fn cmp(&self, other: &Self) -> cmp::Ordering {
169 str::cmp(self, other)
170 }
171}
172
173impl fmt::Display for CowRcStr<'_> {
174 #[inline]
175 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
176 str::fmt(self, formatter)
177 }
178}
179
180impl fmt::Debug for CowRcStr<'_> {
181 #[inline]
182 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
183 str::fmt(self, formatter)
184 }
185}