1#[cfg(test)]
6mod tests;
7
8use std::borrow::{Borrow, Cow};
9use std::cmp;
10use std::fmt;
11use std::hash;
12use std::marker::PhantomData;
13use std::mem;
14use std::ops::Deref;
15use std::rc::Rc;
16use std::slice;
17use std::str;
18use std::usize;
19
20pub struct CowRcStr<'a> {
27 ptr: &'static (),
31
32 borrowed_len_or_max: usize,
39
40 phantom: PhantomData<Result<&'a str, Rc<String>>>,
41}
42
43fn _static_assert_same_size<'a>() {
44 let _ = mem::transmute::<CowRcStr<'a>, Option<CowRcStr<'a>>>;
46}
47
48impl<'a> From<Cow<'a, str>> for CowRcStr<'a> {
49 #[inline]
50 fn from(s: Cow<'a, str>) -> Self {
51 match s {
52 Cow::Borrowed(s) => CowRcStr::from(s),
53 Cow::Owned(s) => CowRcStr::from(s),
54 }
55 }
56}
57
58impl<'a> From<&'a str> for CowRcStr<'a> {
59 #[inline]
60 fn from(s: &'a str) -> Self {
61 let len = s.len();
62 assert!(len < usize::MAX);
63 CowRcStr {
64 ptr: unsafe { &*(s.as_ptr() as *const ()) },
65 borrowed_len_or_max: len,
66 phantom: PhantomData,
67 }
68 }
69}
70
71impl<'a> From<String> for CowRcStr<'a> {
72 #[inline]
73 fn from(s: String) -> Self {
74 CowRcStr::from_rc(Rc::new(s))
75 }
76}
77
78impl<'a> CowRcStr<'a> {
79 #[inline]
80 fn from_rc(s: Rc<String>) -> Self {
81 let ptr = unsafe { &*(Rc::into_raw(s) as *const ()) };
82 CowRcStr {
83 ptr: ptr,
84 borrowed_len_or_max: usize::MAX,
85 phantom: PhantomData,
86 }
87 }
88
89 #[inline]
90 fn unpack(&self) -> Result<&'a str, *const String> {
91 if self.borrowed_len_or_max == usize::MAX {
92 Err(self.ptr as *const () as *const String)
93 } else {
94 unsafe {
95 Ok(str::from_utf8_unchecked(slice::from_raw_parts(
96 self.ptr as *const () as *const u8,
97 self.borrowed_len_or_max,
98 )))
99 }
100 }
101 }
102}
103
104impl<'a> Clone for CowRcStr<'a> {
105 #[inline]
106 fn clone(&self) -> Self {
107 match self.unpack() {
108 Err(ptr) => {
109 let rc = unsafe { Rc::from_raw(ptr) };
110 let new_rc = rc.clone();
111 mem::forget(rc); CowRcStr::from_rc(new_rc)
113 }
114 Ok(_) => CowRcStr { ..*self },
115 }
116 }
117}
118
119impl<'a> Drop for CowRcStr<'a> {
120 #[inline]
121 fn drop(&mut self) {
122 if let Err(ptr) = self.unpack() {
123 mem::drop(unsafe { Rc::from_raw(ptr) })
124 }
125 }
126}
127
128impl<'a> Deref for CowRcStr<'a> {
129 type Target = str;
130
131 #[inline]
132 fn deref(&self) -> &str {
133 self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr })
134 }
135}
136
137impl<'a> AsRef<str> for CowRcStr<'a> {
140 #[inline]
141 fn as_ref(&self) -> &str {
142 self
143 }
144}
145
146impl<'a> Borrow<str> for CowRcStr<'a> {
147 #[inline]
148 fn borrow(&self) -> &str {
149 self
150 }
151}
152
153impl<'a> Default for CowRcStr<'a> {
154 #[inline]
155 fn default() -> Self {
156 Self::from("")
157 }
158}
159
160impl<'a> hash::Hash for CowRcStr<'a> {
161 #[inline]
162 fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
163 str::hash(self, hasher)
164 }
165}
166
167impl<'a, T: AsRef<str>> PartialEq<T> for CowRcStr<'a> {
168 #[inline]
169 fn eq(&self, other: &T) -> bool {
170 str::eq(self, other.as_ref())
171 }
172}
173
174impl<'a, T: AsRef<str>> PartialOrd<T> for CowRcStr<'a> {
175 #[inline]
176 fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
177 str::partial_cmp(self, other.as_ref())
178 }
179}
180
181impl<'a> Eq for CowRcStr<'a> {}
182
183impl<'a> Ord for CowRcStr<'a> {
184 #[inline]
185 fn cmp(&self, other: &Self) -> cmp::Ordering {
186 str::cmp(self, other)
187 }
188}
189
190impl<'a> fmt::Display for CowRcStr<'a> {
191 #[inline]
192 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
193 str::fmt(self, formatter)
194 }
195}
196
197impl<'a> fmt::Debug for CowRcStr<'a> {
198 #[inline]
199 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
200 str::fmt(self, formatter)
201 }
202}