spo_rhai/types/
immutable_string.rs

1//! The `ImmutableString` type.
2
3use crate::func::{shared_get_mut, shared_make_mut, shared_take};
4use crate::{Shared, SmartString};
5#[cfg(feature = "no_std")]
6use std::prelude::v1::*;
7use std::{
8    borrow::Borrow,
9    cmp::Ordering,
10    fmt,
11    hash::Hash,
12    iter::FromIterator,
13    ops::{Add, AddAssign, Deref, Sub, SubAssign},
14    str::FromStr,
15};
16
17/// The system immutable string type.
18///
19/// An [`ImmutableString`] wraps an `Rc<SmartString>` (or `Arc<SmartString>` under the `sync` feature)
20/// so that it can be simply shared and not cloned.
21///
22/// # Example
23///
24/// ```
25/// use rhai::ImmutableString;
26///
27/// let s1: ImmutableString = "hello".into();
28///
29/// // No actual cloning of the string is involved below.
30/// let s2 = s1.clone();
31/// let s3 = s2.clone();
32///
33/// assert_eq!(s1, s2);
34///
35/// // Clones the underlying string (because it is already shared) and extracts it.
36/// let mut s: String = s1.into_owned();
37///
38/// // Changing the clone has no impact on the previously shared version.
39/// s.push_str(", world!");
40///
41/// // The old version still exists.
42/// assert_eq!(s2, s3);
43/// assert_eq!(s2.as_str(), "hello");
44///
45/// // Not equals!
46/// assert_ne!(s2.as_str(), s.as_str());
47/// assert_eq!(s, "hello, world!");
48/// ```
49#[derive(Clone, Eq, Ord, Hash, Default)]
50pub struct ImmutableString(Shared<SmartString>);
51
52impl Deref for ImmutableString {
53    type Target = str;
54
55    #[inline(always)]
56    fn deref(&self) -> &Self::Target {
57        &self.0
58    }
59}
60
61impl AsRef<str> for ImmutableString {
62    #[inline(always)]
63    #[must_use]
64    fn as_ref(&self) -> &str {
65        &self.0
66    }
67}
68
69impl AsRef<SmartString> for ImmutableString {
70    #[inline(always)]
71    #[must_use]
72    fn as_ref(&self) -> &SmartString {
73        &self.0
74    }
75}
76
77impl Borrow<str> for ImmutableString {
78    #[inline(always)]
79    #[must_use]
80    fn borrow(&self) -> &str {
81        &self.0
82    }
83}
84
85impl Borrow<SmartString> for ImmutableString {
86    #[inline(always)]
87    #[must_use]
88    fn borrow(&self) -> &SmartString {
89        &self.0
90    }
91}
92
93impl From<&Self> for ImmutableString {
94    #[inline(always)]
95    fn from(value: &Self) -> Self {
96        Self(value.0.clone())
97    }
98}
99
100impl From<&str> for ImmutableString {
101    #[inline(always)]
102    fn from(value: &str) -> Self {
103        let value: SmartString = value.into();
104        Self(value.into())
105    }
106}
107
108impl From<Box<str>> for ImmutableString {
109    #[inline(always)]
110    fn from(value: Box<str>) -> Self {
111        let value: SmartString = value.into();
112        Self(value.into())
113    }
114}
115impl From<&String> for ImmutableString {
116    #[inline(always)]
117    fn from(value: &String) -> Self {
118        let value: SmartString = value.into();
119        Self(value.into())
120    }
121}
122impl From<String> for ImmutableString {
123    #[inline(always)]
124    fn from(value: String) -> Self {
125        let value: SmartString = value.into();
126        Self(value.into())
127    }
128}
129impl From<&SmartString> for ImmutableString {
130    #[inline(always)]
131    fn from(value: &SmartString) -> Self {
132        Self(value.clone().into())
133    }
134}
135impl From<SmartString> for ImmutableString {
136    #[inline(always)]
137    fn from(value: SmartString) -> Self {
138        Self(value.into())
139    }
140}
141impl From<&ImmutableString> for SmartString {
142    #[inline(always)]
143    fn from(value: &ImmutableString) -> Self {
144        value.0.as_ref().clone()
145    }
146}
147impl From<ImmutableString> for SmartString {
148    #[inline(always)]
149    fn from(mut value: ImmutableString) -> Self {
150        let _ = value.make_mut(); // Make sure it is unique reference
151        shared_take(value.0) // Should succeed
152    }
153}
154impl From<&ImmutableString> for String {
155    #[inline(always)]
156    fn from(value: &ImmutableString) -> Self {
157        value.0.as_ref().to_string()
158    }
159}
160impl From<ImmutableString> for String {
161    #[inline(always)]
162    fn from(value: ImmutableString) -> Self {
163        value.into_owned()
164    }
165}
166impl From<&ImmutableString> for Box<str> {
167    #[inline(always)]
168    fn from(value: &ImmutableString) -> Self {
169        value.0.as_str().into()
170    }
171}
172impl From<ImmutableString> for Box<str> {
173    #[inline(always)]
174    fn from(value: ImmutableString) -> Self {
175        value.0.as_str().into()
176    }
177}
178
179impl FromStr for ImmutableString {
180    type Err = ();
181
182    #[inline(always)]
183    fn from_str(s: &str) -> Result<Self, Self::Err> {
184        let s: SmartString = s.into();
185        Ok(Self(s.into()))
186    }
187}
188
189impl FromIterator<char> for ImmutableString {
190    #[inline]
191    #[must_use]
192    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
193        Self(iter.into_iter().collect::<SmartString>().into())
194    }
195}
196
197impl<'a> FromIterator<&'a char> for ImmutableString {
198    #[inline]
199    #[must_use]
200    fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
201        Self(iter.into_iter().copied().collect::<SmartString>().into())
202    }
203}
204
205impl<'a> FromIterator<&'a str> for ImmutableString {
206    #[inline]
207    #[must_use]
208    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
209        Self(iter.into_iter().collect::<SmartString>().into())
210    }
211}
212
213impl FromIterator<String> for ImmutableString {
214    #[inline]
215    #[must_use]
216    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
217        Self(iter.into_iter().collect::<SmartString>().into())
218    }
219}
220
221impl FromIterator<SmartString> for ImmutableString {
222    #[inline]
223    #[must_use]
224    fn from_iter<T: IntoIterator<Item = SmartString>>(iter: T) -> Self {
225        Self(iter.into_iter().collect::<SmartString>().into())
226    }
227}
228
229impl fmt::Display for ImmutableString {
230    #[inline(always)]
231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232        fmt::Display::fmt(self.as_str(), f)
233    }
234}
235
236impl fmt::Debug for ImmutableString {
237    #[cold]
238    #[inline(never)]
239    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240        fmt::Debug::fmt(self.as_str(), f)
241    }
242}
243
244impl Add for ImmutableString {
245    type Output = Self;
246
247    #[inline]
248    fn add(mut self, rhs: Self) -> Self::Output {
249        if rhs.is_empty() {
250            self
251        } else if self.is_empty() {
252            rhs
253        } else {
254            self.make_mut().push_str(rhs.as_str());
255            self
256        }
257    }
258}
259
260impl Add for &ImmutableString {
261    type Output = ImmutableString;
262
263    #[inline]
264    fn add(self, rhs: Self) -> Self::Output {
265        if rhs.is_empty() {
266            self.clone()
267        } else if self.is_empty() {
268            rhs.clone()
269        } else {
270            let mut s = self.clone();
271            s.make_mut().push_str(rhs.as_str());
272            s
273        }
274    }
275}
276
277impl Add<&Self> for ImmutableString {
278    type Output = Self;
279
280    #[inline]
281    fn add(mut self, rhs: &Self) -> Self::Output {
282        if rhs.is_empty() {
283            self
284        } else if self.is_empty() {
285            rhs.clone()
286        } else {
287            self.make_mut().push_str(rhs.as_str());
288            self
289        }
290    }
291}
292
293impl Add<ImmutableString> for &ImmutableString {
294    type Output = ImmutableString;
295
296    #[inline]
297    fn add(self, rhs: ImmutableString) -> Self::Output {
298        if rhs.is_empty() {
299            self.clone()
300        } else if self.is_empty() {
301            rhs
302        } else {
303            let mut s = self.clone();
304            s.make_mut().push_str(rhs.as_str());
305            s
306        }
307    }
308}
309
310impl AddAssign<Self> for ImmutableString {
311    #[inline]
312    fn add_assign(&mut self, rhs: Self) {
313        if !rhs.is_empty() {
314            if self.is_empty() {
315                self.0 = rhs.0;
316            } else {
317                self.make_mut().push_str(&rhs);
318            }
319        }
320    }
321}
322
323impl AddAssign<&Self> for ImmutableString {
324    #[inline]
325    fn add_assign(&mut self, rhs: &Self) {
326        if !rhs.is_empty() {
327            if self.is_empty() {
328                self.0 = rhs.0.clone();
329            } else {
330                self.make_mut().push_str(rhs.as_str());
331            }
332        }
333    }
334}
335
336impl Add<&str> for ImmutableString {
337    type Output = Self;
338
339    #[inline]
340    fn add(mut self, rhs: &str) -> Self::Output {
341        if !rhs.is_empty() {
342            self.make_mut().push_str(rhs);
343        }
344        self
345    }
346}
347
348impl Add<&str> for &ImmutableString {
349    type Output = ImmutableString;
350
351    #[inline]
352    fn add(self, rhs: &str) -> Self::Output {
353        if rhs.is_empty() {
354            self.clone()
355        } else {
356            let mut s = self.clone();
357            s.make_mut().push_str(rhs);
358            s
359        }
360    }
361}
362
363impl AddAssign<&str> for ImmutableString {
364    #[inline]
365    fn add_assign(&mut self, rhs: &str) {
366        if !rhs.is_empty() {
367            self.make_mut().push_str(rhs);
368        }
369    }
370}
371
372impl Add<String> for ImmutableString {
373    type Output = Self;
374
375    #[inline]
376    fn add(mut self, rhs: String) -> Self::Output {
377        if rhs.is_empty() {
378            self
379        } else if self.is_empty() {
380            rhs.into()
381        } else {
382            self.make_mut().push_str(&rhs);
383            self
384        }
385    }
386}
387
388impl Add<String> for &ImmutableString {
389    type Output = ImmutableString;
390
391    #[inline]
392    fn add(self, rhs: String) -> Self::Output {
393        if rhs.is_empty() {
394            self.clone()
395        } else if self.is_empty() {
396            rhs.into()
397        } else {
398            let mut s = self.clone();
399            s.make_mut().push_str(&rhs);
400            s
401        }
402    }
403}
404
405impl AddAssign<String> for ImmutableString {
406    #[inline]
407    fn add_assign(&mut self, rhs: String) {
408        if !rhs.is_empty() {
409            if self.is_empty() {
410                let rhs: SmartString = rhs.into();
411                self.0 = rhs.into();
412            } else {
413                self.make_mut().push_str(&rhs);
414            }
415        }
416    }
417}
418
419impl Add<char> for ImmutableString {
420    type Output = Self;
421
422    #[inline]
423    fn add(mut self, rhs: char) -> Self::Output {
424        self.make_mut().push(rhs);
425        self
426    }
427}
428
429impl Add<char> for &ImmutableString {
430    type Output = ImmutableString;
431
432    #[inline]
433    fn add(self, rhs: char) -> Self::Output {
434        let mut s = self.clone();
435        s.make_mut().push(rhs);
436        s
437    }
438}
439
440impl AddAssign<char> for ImmutableString {
441    #[inline]
442    fn add_assign(&mut self, rhs: char) {
443        self.make_mut().push(rhs);
444    }
445}
446
447impl Sub for ImmutableString {
448    type Output = Self;
449
450    #[inline]
451    fn sub(self, rhs: Self) -> Self::Output {
452        if rhs.is_empty() {
453            self
454        } else if self.is_empty() {
455            rhs
456        } else {
457            self.replace(rhs.as_str(), "").into()
458        }
459    }
460}
461
462impl Sub for &ImmutableString {
463    type Output = ImmutableString;
464
465    #[inline]
466    fn sub(self, rhs: Self) -> Self::Output {
467        if rhs.is_empty() {
468            self.clone()
469        } else if self.is_empty() {
470            rhs.clone()
471        } else {
472            self.replace(rhs.as_str(), "").into()
473        }
474    }
475}
476
477impl SubAssign<Self> for ImmutableString {
478    #[inline]
479    fn sub_assign(&mut self, rhs: Self) {
480        if !rhs.is_empty() {
481            if self.is_empty() {
482                self.0 = rhs.0;
483            } else {
484                let rhs: SmartString = self.replace(rhs.as_str(), "").into();
485                self.0 = rhs.into();
486            }
487        }
488    }
489}
490
491impl SubAssign<&Self> for ImmutableString {
492    #[inline]
493    fn sub_assign(&mut self, rhs: &Self) {
494        if !rhs.is_empty() {
495            if self.is_empty() {
496                self.0 = rhs.0.clone();
497            } else {
498                let rhs: SmartString = self.replace(rhs.as_str(), "").into();
499                self.0 = rhs.into();
500            }
501        }
502    }
503}
504
505impl Sub<String> for ImmutableString {
506    type Output = Self;
507
508    #[inline]
509    fn sub(self, rhs: String) -> Self::Output {
510        if rhs.is_empty() {
511            self
512        } else if self.is_empty() {
513            rhs.into()
514        } else {
515            self.replace(&rhs, "").into()
516        }
517    }
518}
519
520impl Sub<String> for &ImmutableString {
521    type Output = ImmutableString;
522
523    #[inline]
524    fn sub(self, rhs: String) -> Self::Output {
525        if rhs.is_empty() {
526            self.clone()
527        } else if self.is_empty() {
528            rhs.into()
529        } else {
530            self.replace(&rhs, "").into()
531        }
532    }
533}
534
535impl SubAssign<String> for ImmutableString {
536    #[inline]
537    fn sub_assign(&mut self, rhs: String) {
538        if !rhs.is_empty() {
539            let rhs: SmartString = self.replace(&rhs, "").into();
540            self.0 = rhs.into();
541        }
542    }
543}
544
545impl Sub<&str> for ImmutableString {
546    type Output = Self;
547
548    #[inline]
549    fn sub(self, rhs: &str) -> Self::Output {
550        if rhs.is_empty() {
551            self
552        } else if self.is_empty() {
553            rhs.into()
554        } else {
555            self.replace(rhs, "").into()
556        }
557    }
558}
559
560impl Sub<&str> for &ImmutableString {
561    type Output = ImmutableString;
562
563    #[inline]
564    fn sub(self, rhs: &str) -> Self::Output {
565        if rhs.is_empty() {
566            self.clone()
567        } else if self.is_empty() {
568            rhs.into()
569        } else {
570            self.replace(rhs, "").into()
571        }
572    }
573}
574
575impl SubAssign<&str> for ImmutableString {
576    #[inline]
577    fn sub_assign(&mut self, rhs: &str) {
578        if !rhs.is_empty() {
579            let rhs: SmartString = self.replace(rhs, "").into();
580            self.0 = rhs.into();
581        }
582    }
583}
584
585impl Sub<char> for ImmutableString {
586    type Output = Self;
587
588    #[inline(always)]
589    fn sub(self, rhs: char) -> Self::Output {
590        self.replace(rhs, "").into()
591    }
592}
593
594impl Sub<char> for &ImmutableString {
595    type Output = ImmutableString;
596
597    #[inline(always)]
598    fn sub(self, rhs: char) -> Self::Output {
599        self.replace(rhs, "").into()
600    }
601}
602
603impl SubAssign<char> for ImmutableString {
604    #[inline]
605    fn sub_assign(&mut self, rhs: char) {
606        let rhs: SmartString = self.replace(rhs, "").into();
607        self.0 = rhs.into();
608    }
609}
610
611impl<S: AsRef<str> + ?Sized> PartialEq<S> for ImmutableString {
612    #[inline(always)]
613    fn eq(&self, other: &S) -> bool {
614        self.as_str().eq(other.as_ref())
615    }
616}
617
618impl PartialEq<str> for &ImmutableString {
619    #[inline(always)]
620    fn eq(&self, other: &str) -> bool {
621        self.as_str().eq(other)
622    }
623}
624
625impl PartialEq<String> for &ImmutableString {
626    #[inline(always)]
627    fn eq(&self, other: &String) -> bool {
628        self.as_str().eq(other.as_str())
629    }
630}
631
632impl PartialEq<ImmutableString> for str {
633    #[inline(always)]
634    fn eq(&self, other: &ImmutableString) -> bool {
635        self.eq(other.as_str())
636    }
637}
638
639impl PartialEq<ImmutableString> for &str {
640    #[inline(always)]
641    fn eq(&self, other: &ImmutableString) -> bool {
642        (*self).eq(other.as_str())
643    }
644}
645
646impl PartialEq<ImmutableString> for String {
647    #[inline(always)]
648    fn eq(&self, other: &ImmutableString) -> bool {
649        self.as_str().eq(other.as_str())
650    }
651}
652
653impl PartialEq<&ImmutableString> for String {
654    #[inline(always)]
655    fn eq(&self, other: &&ImmutableString) -> bool {
656        self.as_str().eq(other.as_str())
657    }
658}
659
660impl PartialEq<ImmutableString> for &String {
661    #[inline(always)]
662    fn eq(&self, other: &ImmutableString) -> bool {
663        self.as_str().eq(other.as_str())
664    }
665}
666
667impl<S: AsRef<str> + ?Sized> PartialOrd<S> for ImmutableString {
668    fn partial_cmp(&self, other: &S) -> Option<Ordering> {
669        self.as_str().partial_cmp(other.as_ref())
670    }
671}
672
673impl PartialOrd<str> for &ImmutableString {
674    fn partial_cmp(&self, other: &str) -> Option<Ordering> {
675        self.as_str().partial_cmp(other)
676    }
677}
678
679impl PartialOrd<String> for &ImmutableString {
680    fn partial_cmp(&self, other: &String) -> Option<Ordering> {
681        self.as_str().partial_cmp(other.as_str())
682    }
683}
684
685impl PartialOrd<ImmutableString> for str {
686    #[inline(always)]
687    fn partial_cmp(&self, other: &ImmutableString) -> Option<Ordering> {
688        self.partial_cmp(other.as_str())
689    }
690}
691
692impl PartialOrd<ImmutableString> for &str {
693    #[inline(always)]
694    fn partial_cmp(&self, other: &ImmutableString) -> Option<Ordering> {
695        (*self).partial_cmp(other.as_str())
696    }
697}
698
699impl PartialOrd<ImmutableString> for String {
700    #[inline(always)]
701    fn partial_cmp(&self, other: &ImmutableString) -> Option<Ordering> {
702        self.as_str().partial_cmp(other.as_str())
703    }
704}
705
706impl PartialOrd<&ImmutableString> for String {
707    #[inline(always)]
708    fn partial_cmp(&self, other: &&ImmutableString) -> Option<Ordering> {
709        self.as_str().partial_cmp(other.as_str())
710    }
711}
712
713impl PartialOrd<ImmutableString> for &String {
714    #[inline(always)]
715    fn partial_cmp(&self, other: &ImmutableString) -> Option<Ordering> {
716        self.as_str().partial_cmp(other.as_str())
717    }
718}
719
720impl ImmutableString {
721    /// Create a new [`ImmutableString`].
722    #[inline(always)]
723    #[must_use]
724    pub fn new() -> Self {
725        Self(SmartString::new_const().into())
726    }
727    /// Get the string slice.
728    #[inline(always)]
729    #[must_use]
730    pub fn as_str(&self) -> &str {
731        self.0.as_str()
732    }
733    /// Strong count of references to the underlying string.
734    #[inline(always)]
735    #[must_use]
736    pub fn strong_count(&self) -> usize {
737        Shared::strong_count(&self.0)
738    }
739    /// Consume the [`ImmutableString`] and convert it into a [`String`].
740    ///
741    /// If there are other references to the same string, a cloned copy is returned.
742    #[inline]
743    #[must_use]
744    pub fn into_owned(mut self) -> String {
745        let _ = self.make_mut(); // Make sure it is unique reference
746        shared_take(self.0).into() // Should succeed
747    }
748    /// Make sure that the [`ImmutableString`] is unique (i.e. no other outstanding references).
749    /// Then return a mutable reference to the [`SmartString`].
750    ///
751    /// If there are other references to the same string, a cloned copy is used.
752    #[inline(always)]
753    #[must_use]
754    pub fn make_mut(&mut self) -> &mut SmartString {
755        shared_make_mut(&mut self.0)
756    }
757    /// Return a mutable reference to the [` SmartString`] wrapped by the [`ImmutableString`]
758    /// if there are no other outstanding references to it.
759    #[inline(always)]
760    pub fn get_mut(&mut self) -> Option<&mut SmartString> {
761        shared_get_mut(&mut self.0)
762    }
763    /// Returns `true` if the two [`ImmutableString`]'s point to the same allocation.
764    ///
765    /// # Example
766    ///
767    /// ```
768    /// use rhai::ImmutableString;
769    ///
770    /// let s1: ImmutableString = "hello".into();
771    /// let s2 = s1.clone();
772    /// let s3: ImmutableString = "hello".into();
773    ///
774    /// assert_eq!(s1, s2);
775    /// assert_eq!(s1, s3);
776    /// assert_eq!(s2, s3);
777    ///
778    /// assert!(s1.ptr_eq(&s2));
779    /// assert!(!s1.ptr_eq(&s3));
780    /// assert!(!s2.ptr_eq(&s3));
781    /// ```
782    #[inline(always)]
783    #[must_use]
784    pub fn ptr_eq(&self, other: &Self) -> bool {
785        Shared::ptr_eq(&self.0, &other.0)
786    }
787}