repo_description: Rhai - An embedded scripting language for Rust.
repo_topics: embedded embedded-scripting-language no-std rhai scripting-engine scripting-language wasm webassembly
code: //! The `ImmutableString` type.
  
  use crate::func::{shared_get_mut, shared_make_mut, shared_take};
  use crate::{Shared, SmartString};
  #[cfg(feature = "no_std")]
  use std::prelude::v1::*;
  use std::{
      borrow::Borrow,
      cmp::Ordering,
      fmt,
      hash::Hash,
      iter::FromIterator,
      ops::{Add, AddAssign, Deref, Sub, SubAssign},
      str::FromStr,
  };
  
  /// The system immutable string type.
  ///
  /// An [`ImmutableString`] wraps an `Rc<SmartString>` (or `Arc<SmartString>` under the `sync` feature)
  /// so that it can be simply shared and not cloned.
  ///
  /// # Example
  ///
  /// ```
  /// use rhai::ImmutableString;
  ///
  /// let s1: ImmutableString = "hello".into();
  ///
  /// // No actual cloning of the string is involved below.
  /// let s2 = s1.clone();
  /// let s3 = s2.clone();
  ///
  /// assert_eq!(s1, s2);
  ///
  /// // Clones the underlying string (because it is already shared) and extracts it.
  /// let mut s: String = s1.into_owned();
  ///
  /// // Changing the clone has no impact on the previously shared version.
  /// s += ", world!";
  ///
  /// // The old version still exists.
  /// assert_eq!(s2, s3);
  /// assert_eq!(s2.as_str(), "hello");
  ///
  /// // Not equals!
  /// assert_ne!(s2.as_str(), s.as_str());
  /// assert_eq!(s, "hello, world!");
  /// ```
  #[derive(Clone, Eq, Ord, Hash, Default)]
  pub struct ImmutableString(Shared<SmartString>);
  
  impl Deref for ImmutableString {
      type Target = str;
  
      #[inline(always)]
      fn deref(&self) -> &Self::Target {
          &self.0
      }
  }
  
  impl AsRef<str> for ImmutableString {
      #[inline(always)]
      fn as_ref(&self) -> &str {
          &self.0
      }
  }
  
  impl AsRef<SmartString> for ImmutableString {
      #[inline(always)]
      fn as_ref(&self) -> &SmartString {
          &self.0
      }
  }
  
  impl Borrow<str> for ImmutableString {
      #[inline(always)]
      fn borrow(&self) -> &str {
          &self.0
      }
  }
  
  impl Borrow<SmartString> for ImmutableString {
      #[inline(always)]
      fn borrow(&self) -> &SmartString {
          &self.0
      }
  }
  
  impl From<&Self> for ImmutableString {
      #[inline(always)]
      fn from(value: &Self) -> Self {
          Self(value.0.clone())
      }
  }
  
  impl From<&str> for ImmutableString {
      #[inline(always)]
      fn from(value: &str) -> Self {
          let value: SmartString = value.into();
          Self(value.into())
      }
  }
  
  impl From<Box<str>> for ImmutableString {
      #[inline(always)]
      fn from(value: Box<str>) -> Self {
          let value: SmartString = value.into();
          Self(value.into())
      }
  }
  impl From<&String> for ImmutableString {
      #[inline(always)]
      fn from(value: &String) -> Self {
          let value: SmartString = value.into();
          Self(value.into())
      }
  }
  impl From<String> for ImmutableString {
      #[inline(always)]
      fn from(value: String) -> Self {
          let value: SmartString = value.into();
          Self(value.into())
      }
  }
  impl From<&SmartString> for ImmutableString {
      #[inline(always)]
      fn from(value: &SmartString) -> Self {
          Self(value.clone().into())
      }
  }
  impl From<SmartString> for ImmutableString {
      #[inline(always)]
      fn from(value: SmartString) -> Self {
          Self(value.into())
      }
  }
  impl From<&ImmutableString> for SmartString {
      #[inline(always)]
      fn from(value: &ImmutableString) -> Self {
          value.0.as_ref().clone()
      }
  }
  impl From<ImmutableString> for SmartString {
      #[inline(always)]
      fn from(mut value: ImmutableString) -> Self {
          let _ = value.make_mut(); // Make sure it is unique reference
          shared_take(value.0) // Should succeed
      }
  }
  impl From<&ImmutableString> for String {
      #[inline(always)]
      fn from(value: &ImmutableString) -> Self {
          value.0.as_ref().to_string()
      }
  }
  impl From<ImmutableString> for String {
      #[inline(always)]
      fn from(value: ImmutableString) -> Self {
          value.into_owned()
      }
  }
  impl From<&ImmutableString> for Box<str> {
      #[inline(always)]
      fn from(value: &ImmutableString) -> Self {
          value.0.as_str().into()
      }
  }
  impl From<ImmutableString> for Box<str> {
      #[inline(always)]
      fn from(value: ImmutableString) -> Self {
          value.0.as_str().into()
      }
  }
  
  impl FromStr for ImmutableString {
      type Err = ();
  
      #[inline(always)]
      fn from_str(s: &str) -> Result<Self, Self::Err> {
          let s: SmartString = s.into();
          Ok(Self(s.into()))
      }
  }
  
  impl FromIterator<char> for ImmutableString {
      #[inline]
      fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
          Self(iter.into_iter().collect::<SmartString>().into())
      }
  }
  
  impl<'a> FromIterator<&'a char> for ImmutableString {
      #[inline]
      fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
          Self(iter.into_iter().copied().collect::<SmartString>().into())
      }
  }
  
  impl<'a> FromIterator<&'a str> for ImmutableString {
      #[inline]
      fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
          Self(iter.into_iter().collect::<SmartString>().into())
      }
  }
  
  impl FromIterator<String> for ImmutableString {
      #[inline]
      fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
          Self(iter.into_iter().collect::<SmartString>().into())
      }
  }
  
  impl FromIterator<SmartString> for ImmutableString {
      #[inline]
      fn from_iter<T: IntoIterator<Item = SmartString>>(iter: T) -> Self {
          Self(iter.into_iter().collect::<SmartString>().into())
      }
  }
  
  impl fmt::Display for ImmutableString {
      #[inline(always)]
      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
          fmt::Display::fmt(self.as_str(), f)
      }
  }
  
  impl fmt::Debug for ImmutableString {
      #[cold]
      #[inline(never)]
      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
          fmt::Debug::fmt(self.as_str(), f)
      }
  }
  
  impl Add for ImmutableString {
      type Output = Self;
  
      #[inline]
      fn add(mut self, rhs: Self) -> Self::Output {
          if rhs.is_empty() {
              self
          } else if self.is_empty() {
              rhs
          } else {
              self.make_mut().push_str(rhs.as_str());
              self
          }
      }
  }
  
  impl Add for &ImmutableString {
      type Output = ImmutableString;
  
      #[inline]
      fn add(self, rhs: Self) -> Self::Output {
          if rhs.is_empty() {
              self.clone()
          } else if self.is_empty() {
              rhs.clone()
          } else {
              let mut s = self.clone();
              s.make_mut().push_str(rhs.as_str());
              s
          }
      }
  }
  
  impl Add<&Self> for ImmutableString {
      type Output = Self;
  
      #[inline]
      fn add(mut self, rhs: &Self) -> Self::Output {
          if rhs.is_empty() {
              self
          } else if self.is_empty() {
              rhs.clone()
          } else {
              self.make_mut().push_str(rhs.as_str());
              self
          }
      }
  }
  
  impl Add<ImmutableString> for &ImmutableString {
      type Output = ImmutableString;
  
      #[inline]
      fn add(self, rhs: ImmutableString) -> Self::Output {
          if rhs.is_empty() {
              self.clone()
          } else if self.is_empty() {
              rhs
          } else {
              let mut s = self.clone();
              s.make_mut().push_str(rhs.as_str());
              s
          }
      }
  }
  
  impl AddAssign<Self> for ImmutableString {
      #[inline]
      fn add_assign(&mut self, rhs: Self) {
          if !rhs.is_empty() {
              if self.is_empty() {
                  self.0 = rhs.0;
              } else {
                  self.make_mut().push_str(&rhs);
              }
          }
      }
  }
  
  impl AddAssign<&Self> for ImmutableString {
      #[inline]
      fn add_assign(&mut self, rhs: &Self) {
          if !rhs.is_empty() {
              if self.is_empty() {
                  self.0 = rhs.0.clone();
              } else {
                  self.make_mut().push_str(rhs.as_str());
              }
          }
      }
  }
  
  impl Add<&str> for ImmutableString {
      type Output = Self;
  
      #[inline]
      fn add(mut self, rhs: &str) -> Self::Output {
          if !rhs.is_empty() {
              self.make_mut().push_str(rhs);
          }
          self
      }
  }
  
  impl Add<&str> for &ImmutableString {
      type Output = ImmutableString;
  
      #[inline]
      fn add(self, rhs: &str) -> Self::Output {
          if rhs.is_empty() {
              self.clone()
          } else {
              let mut s = self.clone();
              s.make_mut().push_str(rhs);
              s
          }
      }
  }
  
  impl AddAssign<&str> for ImmutableString {
      #[inline]
      fn add_assign(&mut self, rhs: &str) {
          if !rhs.is_empty() {
              self.make_mut().push_str(rhs);
          }
      }
  }
  
  impl Add<String> for ImmutableString {
      type Output = Self;
  
      #[inline]
      fn add(mut self, rhs: String) -> Self::Output {
          if rhs.is_empty() {
              self
          } else if self.is_empty() {
              rhs.into()
          } else {
              self.make_mut().push_str(&rhs);
              self
          }
      }
  }
  
  impl Add<String> for &ImmutableString {
      type Output = ImmutableString;
  
      #[inline]
      fn add(self, rhs: String) -> Self::Output {
          if rhs.is_empty() {
              self.clone()
          } else if self.is_empty() {
              rhs.into()
          } else {
              let mut s = self.clone();
              s.make_mut().push_str(&rhs);
              s
          }
      }
  }
  
  impl AddAssign<String> for ImmutableString {
      #[inline]
      fn add_assign(&mut self, rhs: String) {
          if !rhs.is_empty() {
              if self.is_empty() {
                  let rhs: SmartString = rhs.into();
                  self.0 = rhs.into();
              } else {
                  self.make_mut().push_str(&rhs);
              }
          }
      }
  }
  
  impl Add<char> for ImmutableString {
      type Output = Self;
  
      #[inline]
      fn add(mut self, rhs: char) -> Self::Output {
          self.make_mut().push(rhs);
          self
      }
  }
  
  impl Add<char> for &ImmutableString {
      type Output = ImmutableString;
  
      #[inline]
      fn add(self, rhs: char) -> Self::Output {
          let mut s = self.clone();
          s.make_mut().push(rhs);
          s
      }
  }
  
  impl AddAssign<char> for ImmutableString {
      #[inline]
      fn add_assign(&mut self, rhs: char) {
          self.make_mut().push(rhs);
      }
  }
  
  impl Sub for ImmutableString {
      type Output = Self;
  
      #[inline]
      fn sub(self, rhs: Self) -> Self::Output {
          if rhs.is_empty() {
              self
          } else if self.is_empty() {
              rhs
          } else {
              self.replace(rhs.as_str(), "").into()
          }
      }
  }
  
  impl Sub for &ImmutableString {
      type Output = ImmutableString;
  
      #[inline]
      fn sub(self, rhs: Self) -> Self::Output {
          if rhs.is_empty() {
              self.clone()
          } else if self.is_empty() {
              rhs.clone()
          } else {
              self.replace(rhs.as_str(), "").into()
          }
      }
  }
  
  impl SubAssign<Self> for ImmutableString {
      #[inline]
      fn sub_assign(&mut self, rhs: Self) {
          if !rhs.is_empty() {
              if self.is_empty() {
                  self.0 = rhs.0;
              } else {
                  let rhs: SmartString = self.replace(rhs.as_str(), "").into();
                  self.0 = rhs.into();
              }
          }
      }
  }
  
  impl SubAssign<&Self> for ImmutableString {
      #[inline]
      fn sub_assign(&mut self, rhs: &Self) {
          if !rhs.is_empty() {
              if self.is_empty() {
                  self.0 = rhs.0.clone();
              } else {
                  let rhs: SmartString = self.replace(rhs.as_str(), "").into();
                  self.0 = rhs.into();
              }
          }
      }
  }
  
  impl Sub<String> for ImmutableString {
      type Output = Self;
  
      #[inline]
      fn sub(self, rhs: String) -> Self::Output {
          if rhs.is_empty() {
              self
          } else if self.is_empty() {
              rhs.into()
          } else {
              self.replace(&rhs, "").into()
          }
      }
  }
  
  impl Sub<String> for &ImmutableString {
      type Output = ImmutableString;
  
      #[inline]
      fn sub(self, rhs: String) -> Self::Output {
          if rhs.is_empty() {
              self.clone()
          } else if self.is_empty() {
              rhs.into()
          } else {
              self.replace(&rhs, "").into()
          }
      }
  }
  
  impl SubAssign<String> for ImmutableString {
      #[inline]
      fn sub_assign(&mut self, rhs: String) {
          if !rhs.is_empty() {
              let rhs: SmartString = self.replace(&rhs, "").into();
              self.0 = rhs.into();
          }
      }
  }
  
  impl Sub<&str> for ImmutableString {
      type Output = Self;
  
      #[inline]
      fn sub(self, rhs: &str) -> Self::Output {
          if rhs.is_empty() {
              self
          } else if self.is_empty() {
              rhs.into()
          } else {
              self.replace(rhs, "").into()
          }
      }
  }
  
  impl Sub<&str> for &ImmutableString {
      type Output = ImmutableString;
  
      #[inline]
      fn sub(self, rhs: &str) -> Self::Output {
          if rhs.is_empty() {
              self.clone()
          } else if self.is_empty() {
              rhs.into()
          } else {
              self.replace(rhs, "").into()
          }
      }
  }
  
  impl SubAssign<&str> for ImmutableString {
      #[inline]
      fn sub_assign(&mut self, rhs: &str) {
          if !rhs.is_empty() {
              let rhs: SmartString = self.replace(rhs, "").into();
              self.0 = rhs.into();
          }
      }
  }
  
  impl Sub<char> for ImmutableString {
      type Output = Self;
  
      #[inline(always)]
      fn sub(self, rhs: char) -> Self::Output {
          self.replace(rhs, "").into()
      }
  }
  
  impl Sub<char> for &ImmutableString {
      type Output = ImmutableString;
  
      #[inline(always)]
      fn sub(self, rhs: char) -> Self::Output {
          self.replace(rhs, "").into()
      }
  }
  
  impl SubAssign<char> for ImmutableString {
      #[inline]
      fn sub_assign(&mut self, rhs: char) {
          let rhs: SmartString = self.replace(rhs, "").into();
          self.0 = rhs.into();
      }
  }
  
  impl<S: AsRef<str> + ?Sized> PartialEq<S> for ImmutableString {
      #[inline(always)]
      fn eq(&self, other: &S) -> bool {
          self.as_str().eq(other.as_ref())
      }
  }
  
  impl PartialEq<str> for &ImmutableString {
      #[inline(always)]
      fn eq(&self, other: &str) -> bool {
          self.as_str().eq(other)
      }
  }
  
  impl PartialEq<String> for &ImmutableString {
      #[inline(always)]
      fn eq(&self, other: &String) -> bool {
          self.as_str().eq(other.as_str())
      }
  }
  
  impl PartialEq<ImmutableString> for str {
      #[inline(always)]
      fn eq(&self, other: &ImmutableString) -> bool {
          self.eq(other.as_str())
      }
  }
  
  impl PartialEq<ImmutableString> for &str {
      #[inline(always)]
      fn eq(&self, other: &ImmutableString) -> bool {
          (*self).eq(other.as_str())
      }
  }
  
  impl PartialEq<ImmutableString> for String {
      #[inline(always)]
      fn eq(&self, other: &ImmutableString) -> bool {
          self.as_str().eq(other.as_str())
      }
  }
  
  impl PartialEq<&ImmutableString> for String {
      #[inline(always)]
      fn eq(&self, other: &&ImmutableString) -> bool {
          self.as_str().eq(other.as_str())
      }
  }
  
  impl PartialEq<ImmutableString> for &String {
      #[inline(always)]
      fn eq(&self, other: &ImmutableString) -> bool {
          self.as_str().eq(other.as_str())
      }
  }
  
  impl<S: AsRef<str> + ?Sized> PartialOrd<S> for ImmutableString {
      fn partial_cmp(&self, other: &S) -> Option<Ordering> {
          self.as_str().partial_cmp(other.as_ref())
      }
  }
  
  impl PartialOrd<str> for &ImmutableString {
      fn partial_cmp(&self, other: &str) -> Option<Ordering> {
          self.as_str().partial_cmp(other)
      }
  }
  
  impl PartialOrd<String> for &ImmutableString {
      fn partial_cmp(&self, other: &String) -> Option<Ordering> {
          self.as_str().partial_cmp(other.as_str())
      }
  }
  
  impl PartialOrd<ImmutableString> for str {
      #[inline(always)]
      fn partial_cmp(&self, other: &ImmutableString) -> Option<Ordering> {
          self.partial_cmp(other.as_str())
      }
  }
  
  impl PartialOrd<ImmutableString> for &str {
      #[inline(always)]
      fn partial_cmp(&self, other: &ImmutableString) -> Option<Ordering> {
          (*self).partial_cmp(other.as_str())
      }
  }
  
  impl PartialOrd<ImmutableString> for String {
      #[inline(always)]
      fn partial_cmp(&self, other: &ImmutableString) -> Option<Ordering> {
          self.as_str().partial_cmp(other.as_str())
      }
  }
  
  impl PartialOrd<&ImmutableString> for String {
      #[inline(always)]
      fn partial_cmp(&self, other: &&ImmutableString) -> Option<Ordering> {
          self.as_str().partial_cmp(other.as_str())
      }
  }
  
  impl PartialOrd<ImmutableString> for &String {
      #[inline(always)]
      fn partial_cmp(&self, other: &ImmutableString) -> Option<Ordering> {
          self.as_str().partial_cmp(other.as_str())
      }
  }
  
  impl ImmutableString {
      /// Create a new [`ImmutableString`].
      #[inline(always)]
      #[must_use]
      pub fn new() -> Self {
          Self(SmartString::new_const().into())
      }
      /// Get the string slice.
      #[inline(always)]
      #[must_use]
      pub fn as_str(&self) -> &str {
          self.0.as_str()
      }
      /// Strong count of references to the underlying string.
      #[inline(always)]
      #[must_use]
      pub fn strong_count(&self) -> usize {
          Shared::strong_count(&self.0)
      }
      /// Consume the [`ImmutableString`] and convert it into a [`String`].
      ///
      /// If there are other references to the same string, a cloned copy is returned.
      #[inline]
      #[must_use]
      pub fn into_owned(mut self) -> String {
          let _ = self.make_mut(); // Make sure it is unique reference
          shared_take(self.0).into() // Should succeed
      }
      /// Make sure that the [`ImmutableString`] is unique (i.e. no other outstanding references).
      /// Then return a mutable reference to the `SmartString`.
      ///
      /// If there are other references to the same string, a cloned copy is used.
      #[inline(always)]
      #[must_use]
      pub fn make_mut(&mut self) -> &mut SmartString {
          shared_make_mut(&mut self.0)
      }
      /// Return a mutable reference to the `SmartString` wrapped by the [`ImmutableString`]
      /// if there are no other outstanding references to it.
      #[inline(always)]
      pub fn get_mut(&mut self) -> Option<&mut SmartString> {
          shared_get_mut(&mut self.0)
      }
      /// Returns `true` if the two [`ImmutableString`]'s point to the same allocation.
      ///
      /// # Example
      ///
      /// ```
      /// use rhai::ImmutableString;
      ///
      /// let s1: ImmutableString = "hello".into();
      /// let s2 = s1.clone();
      /// let s3: ImmutableString = "hello".into();
      ///
      /// assert_eq!(s1, s2);
      /// assert_eq!(s1, s3);
      /// assert_eq!(s2, s3);
      ///
      /// assert!(s1.ptr_eq(&s2));
      /// assert!(!s1.ptr_eq(&s3));
      /// assert!(!s2.ptr_eq(&s3));
      /// ```
      #[inline(always)]
      #[must_use]
      pub fn ptr_eq(&self, other: &Self) -> bool {
          Shared::ptr_eq(&self.0, &other.0)
      }
  }
  