Skip to main content

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