summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cssparser/src/cow_rc_str.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/cssparser/src/cow_rc_str.rs')
-rw-r--r--third_party/rust/cssparser/src/cow_rc_str.rs199
1 files changed, 199 insertions, 0 deletions
diff --git a/third_party/rust/cssparser/src/cow_rc_str.rs b/third_party/rust/cssparser/src/cow_rc_str.rs
new file mode 100644
index 0000000000..f89f4cdacf
--- /dev/null
+++ b/third_party/rust/cssparser/src/cow_rc_str.rs
@@ -0,0 +1,199 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::borrow::{Borrow, Cow};
+use std::cmp;
+use std::fmt;
+use std::hash;
+use std::marker::PhantomData;
+use std::mem;
+use std::ops::Deref;
+use std::rc::Rc;
+use std::slice;
+use std::str;
+use std::usize;
+
+/// A string that is either shared (heap-allocated and reference-counted) or borrowed.
+///
+/// Equivalent to `enum { Borrowed(&'a str), Shared(Rc<String>) }`, but stored more compactly.
+///
+/// FIXME(https://github.com/rust-lang/rfcs/issues/1230): use an actual enum if/when
+/// the compiler can do this layout optimization.
+pub struct CowRcStr<'a> {
+ /// FIXME: https://github.com/rust-lang/rust/issues/27730 use NonZero or Shared.
+ /// In the meantime we abuse `&'static _` to get the effect of `NonZero<*const _>`.
+ /// `ptr` doesn’t really have the 'static lifetime!
+ ptr: &'static (),
+
+ /// * If `borrowed_len_or_max == usize::MAX`, then `ptr` represents `NonZero<*const String>`
+ /// from `Rc::into_raw`.
+ /// The lifetime parameter `'a` is irrelevant in this case.
+ ///
+ /// * Otherwise, `ptr` represents the `NonZero<*const u8>` data component of `&'a str`,
+ /// and `borrowed_len_or_max` its length.
+ borrowed_len_or_max: usize,
+
+ phantom: PhantomData<Result<&'a str, Rc<String>>>,
+}
+
+fn _static_assert_same_size<'a>() {
+ // "Instantiate" the generic function without calling it.
+ let _ = mem::transmute::<CowRcStr<'a>, Option<CowRcStr<'a>>>;
+}
+
+impl<'a> From<Cow<'a, str>> for CowRcStr<'a> {
+ #[inline]
+ fn from(s: Cow<'a, str>) -> Self {
+ match s {
+ Cow::Borrowed(s) => CowRcStr::from(s),
+ Cow::Owned(s) => CowRcStr::from(s),
+ }
+ }
+}
+
+impl<'a> From<&'a str> for CowRcStr<'a> {
+ #[inline]
+ fn from(s: &'a str) -> Self {
+ let len = s.len();
+ assert!(len < usize::MAX);
+ CowRcStr {
+ ptr: unsafe { &*(s.as_ptr() as *const ()) },
+ borrowed_len_or_max: len,
+ phantom: PhantomData,
+ }
+ }
+}
+
+impl<'a> From<String> for CowRcStr<'a> {
+ #[inline]
+ fn from(s: String) -> Self {
+ CowRcStr::from_rc(Rc::new(s))
+ }
+}
+
+impl<'a> CowRcStr<'a> {
+ #[inline]
+ fn from_rc(s: Rc<String>) -> Self {
+ let ptr = unsafe { &*(Rc::into_raw(s) as *const ()) };
+ CowRcStr {
+ ptr: ptr,
+ borrowed_len_or_max: usize::MAX,
+ phantom: PhantomData,
+ }
+ }
+
+ #[inline]
+ fn unpack(&self) -> Result<&'a str, *const String> {
+ if self.borrowed_len_or_max == usize::MAX {
+ Err(self.ptr as *const () as *const String)
+ } else {
+ unsafe {
+ Ok(str::from_utf8_unchecked(slice::from_raw_parts(
+ self.ptr as *const () as *const u8,
+ self.borrowed_len_or_max,
+ )))
+ }
+ }
+ }
+}
+
+impl<'a> Clone for CowRcStr<'a> {
+ #[inline]
+ fn clone(&self) -> Self {
+ match self.unpack() {
+ Err(ptr) => {
+ let rc = unsafe { Rc::from_raw(ptr) };
+ let new_rc = rc.clone();
+ mem::forget(rc); // Don’t actually take ownership of this strong reference
+ CowRcStr::from_rc(new_rc)
+ }
+ Ok(_) => CowRcStr { ..*self },
+ }
+ }
+}
+
+impl<'a> Drop for CowRcStr<'a> {
+ #[inline]
+ fn drop(&mut self) {
+ if let Err(ptr) = self.unpack() {
+ mem::drop(unsafe { Rc::from_raw(ptr) })
+ }
+ }
+}
+
+impl<'a> Deref for CowRcStr<'a> {
+ type Target = str;
+
+ #[inline]
+ fn deref(&self) -> &str {
+ self.unpack().unwrap_or_else(|ptr| unsafe { &**ptr })
+ }
+}
+
+// Boilerplate / trivial impls below.
+
+impl<'a> AsRef<str> for CowRcStr<'a> {
+ #[inline]
+ fn as_ref(&self) -> &str {
+ self
+ }
+}
+
+impl<'a> Borrow<str> for CowRcStr<'a> {
+ #[inline]
+ fn borrow(&self) -> &str {
+ self
+ }
+}
+
+impl<'a> Default for CowRcStr<'a> {
+ #[inline]
+ fn default() -> Self {
+ Self::from("")
+ }
+}
+
+impl<'a> hash::Hash for CowRcStr<'a> {
+ #[inline]
+ fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
+ str::hash(self, hasher)
+ }
+}
+
+impl<'a, T: AsRef<str>> PartialEq<T> for CowRcStr<'a> {
+ #[inline]
+ fn eq(&self, other: &T) -> bool {
+ str::eq(self, other.as_ref())
+ }
+}
+
+impl<'a, T: AsRef<str>> PartialOrd<T> for CowRcStr<'a> {
+ #[inline]
+ fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
+ str::partial_cmp(self, other.as_ref())
+ }
+}
+
+impl<'a> Eq for CowRcStr<'a> {}
+
+impl<'a> Ord for CowRcStr<'a> {
+ #[inline]
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ str::cmp(self, other)
+ }
+}
+
+impl<'a> fmt::Display for CowRcStr<'a> {
+ #[inline]
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ str::fmt(self, formatter)
+ }
+}
+
+impl<'a> fmt::Debug for CowRcStr<'a> {
+ #[inline]
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ str::fmt(self, formatter)
+ }
+}