mstr/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3#![deny(unsafe_op_in_unsafe_fn)]
4#![deny(elided_lifetimes_in_paths)]
5
6extern crate alloc;
7
8use alloc::borrow::Cow;
9use alloc::boxed::Box;
10use alloc::string::String;
11use core::borrow::Borrow;
12use core::cmp::Ordering;
13use core::fmt::{Debug, Display, Formatter, Pointer};
14use core::hash::{Hash, Hasher};
15use core::marker::PhantomData;
16use core::ops::Deref;
17use core::ptr::NonNull;
18use core::{fmt, mem, ptr, str};
19
20// the high bit of usize
21// if set (1), MStr is owned
22// if not (0), MStr is borrowed
23const TAG: usize = 1 << (usize::BITS - 1);
24// every bit except the tag bit
25const MASK: usize = !TAG;
26
27/// `MStr` is a 2-word, immutable version of `Cow<str>`.
28///
29/// See the [crate docs](crate) for more info.
30pub struct MStr<'a> {
31    ptr: NonNull<u8>,
32
33    // if high bit (TAG) is set, we are owned
34    // rust requires all allocations to be less than isize::MAX bytes,
35    // so the top bit is never used and thus available for tagging
36    len: usize,
37
38    // use the lifetime (also makes it covariant)
39    _marker: PhantomData<&'a str>,
40}
41
42unsafe impl Send for MStr<'_> {}
43unsafe impl Sync for MStr<'_> {}
44
45impl<'a> MStr<'a> {
46    // -- Constructors --
47
48    /// Creates a new `MStr<'a>` from an `&'a str`.
49    ///
50    /// The returned `MStr` is borrowed for the same lifetime as the input data.
51    ///
52    /// # Examples
53    ///
54    /// ```rust
55    /// # use mstr::MStr;
56    /// # use std::borrow::Cow;
57    /// let s = String::from("foo");
58    /// let mstr = MStr::new_borrowed(&s);
59    ///
60    /// assert!(mstr.is_borrowed());
61    /// assert_eq!(mstr, s);
62    /// assert_eq!(mstr.as_str(), "foo");
63    /// assert_eq!(mstr.as_ptr(), s.as_ptr());
64    /// assert!(matches!(mstr.into_cow(), Cow::Borrowed(_)));
65    /// ```
66    #[inline]
67    #[must_use]
68    pub const fn new_borrowed(s: &'a str) -> MStr<'a> {
69        MStr::_new(s.as_ptr(), s.len(), false)
70    }
71
72    /// Creates a new `MStr` from owned data.
73    /// The input type is anything that can be converted into a `Box<str>` (String, &str, etc).
74    ///
75    /// The returned `MStr` is owned.
76    /// The lifetime can be chosen to be anything, including `'static`.
77    ///
78    /// If `s` is `Box<str>`, it will not reallocate.  
79    /// If `s` is `String`, it [may reallocate](String::into_boxed_str) if there is excess capacity.  
80    /// If `s` is `&str`, it will be copied to a new heap allocation.
81    ///
82    /// # Examples
83    ///
84    /// ```rust
85    /// # use mstr::MStr;
86    /// # use std::borrow::Cow;
87    /// let s = Box::<str>::from("foo");
88    /// let ptr = s.as_ptr();
89    /// let mstr = MStr::new_owned(s);
90    ///
91    /// assert!(mstr.is_owned());
92    /// assert_eq!(mstr, "foo");
93    /// assert_eq!(mstr.as_ptr(), ptr); // the allocation is reused
94    /// assert!(matches!(mstr.into_cow(), Cow::Owned(_)));
95    /// ```
96    ///
97    /// Passing a string slice makes an owned copy:
98    /// ```rust
99    /// # use mstr::MStr;
100    /// let s = "bar";
101    /// let ptr = s.as_ptr();
102    /// let mstr = MStr::new_owned(s);
103    ///
104    /// assert!(mstr.is_owned());
105    /// assert_eq!(mstr, s);
106    /// assert_eq!(mstr, "bar");
107    ///
108    /// // a new allocation was created, and so the pointer are different
109    /// assert_ne!(mstr.as_ptr(), s.as_ptr());
110    /// ```
111    #[must_use]
112    pub fn new_owned(s: impl Into<Box<str>>) -> MStr<'a> {
113        let s = s.into();
114
115        let len = s.len();
116        let ptr = Box::into_raw(s).cast::<u8>();
117
118        MStr::_new(ptr, len, true)
119    }
120
121    /// Creates a new `MStr<'a>` from a `Cow<'a, str>`.
122    ///
123    /// The returned `MStr` will be borrowed if the cow is borrowed,
124    /// and owned if the cow is owned.  
125    /// If the cow is owned, and has excess capacity, it [may reallocate](String::into_boxed_str).
126    ///
127    /// # Examples
128    ///
129    /// Owned:
130    /// ```rust
131    /// # use mstr::MStr;
132    /// # use std::borrow::Cow;
133    /// let cow = Cow::Owned(String::from("foo"));
134    /// let mstr = MStr::new_cow(cow);
135    ///
136    /// assert!(mstr.is_owned());
137    /// assert_eq!(mstr, "foo");
138    /// assert!(matches!(mstr.into_cow(), Cow::Owned(_)));
139    /// ```
140    ///
141    /// Borrowed:
142    /// ```rust
143    /// # use mstr::MStr;
144    /// # type Cow<'a> = std::borrow::Cow<'a, str>; // fix inference
145    /// let s = String::from("bar");
146    /// let cow = Cow::Borrowed(&s);
147    /// let mstr = MStr::new_cow(cow);
148    ///
149    /// assert!(mstr.is_borrowed());
150    /// assert_eq!(mstr, s);
151    /// assert_eq!(mstr.as_ptr(), s.as_ptr());
152    /// assert!(matches!(mstr.into_cow(), Cow::Borrowed(_)));
153    /// ```
154    ///
155    /// Borrowed (static):
156    /// ```rust
157    /// # use mstr::MStr;
158    /// # use std::borrow::Cow;
159    /// let cow = Cow::Borrowed("qux");
160    /// let mstr = MStr::new_cow(cow);
161    ///
162    /// assert!(mstr.is_borrowed());
163    /// assert_eq!(mstr, "qux");
164    /// assert!(matches!(mstr.into_cow(), Cow::Borrowed("qux")));
165    /// ```
166    #[inline]
167    #[must_use]
168    pub fn new_cow(s: Cow<'a, str>) -> MStr<'a> {
169        match s {
170            Cow::Borrowed(s) => MStr::new_borrowed(s),
171            Cow::Owned(s) => MStr::new_owned(s),
172        }
173    }
174
175    #[inline]
176    #[must_use]
177    const fn _new(ptr: *const u8, len: usize, tag: bool) -> MStr<'a> {
178        MStr {
179            // SAFETY: always comes from a valid string
180            ptr: unsafe { NonNull::new_unchecked(ptr.cast_mut()) },
181            len: if tag { len | TAG } else { len },
182            _marker: PhantomData,
183        }
184    }
185
186    // -- Accessors --
187
188    /// Converts this `MStr` to a string slice.
189    ///
190    /// # Examples
191    ///
192    /// ```rust
193    /// # use mstr::MStr;
194    /// let mstr = MStr::new_borrowed("foo");
195    ///
196    /// assert_eq!(mstr.as_str(), "foo");
197    /// ```
198    #[inline]
199    #[must_use]
200    pub const fn as_str(&self) -> &str {
201        unsafe { &*self.as_str_ptr() }
202    }
203
204    /// Converts this `MStr` to a UTF-8 byte slice.
205    ///
206    /// # Examples
207    ///
208    /// ```rust
209    /// # use mstr::MStr;
210    /// let mstr = MStr::new_borrowed("foo");
211    ///
212    /// assert_eq!(mstr.as_bytes(), b"foo");
213    /// ```
214    #[inline]
215    #[must_use]
216    pub const fn as_bytes(&self) -> &[u8] {
217        self.as_str().as_bytes()
218    }
219
220    /// Converts this `MStr` into an owned `String`.
221    /// This will consume `self`.
222    ///
223    /// If `self` is owned, the allocation will be reused.  
224    /// If `self` is borrowed, it will be copied to the heap.
225    ///
226    /// # Examples
227    ///
228    /// ```rust
229    /// # use mstr::MStr;
230    /// let mstr = MStr::new_borrowed("foo");
231    /// let s: String = mstr.into_string();
232    ///
233    /// assert_eq!(s, "foo");
234    /// ```
235    ///
236    /// Reuses owned allocation:
237    /// ```rust
238    /// # use mstr::MStr;
239    /// let owned = Box::<str>::from("bar");
240    /// let ptr = owned.as_ptr();
241    /// let mstr = MStr::new_owned(owned);
242    /// let s = mstr.into_string();
243    ///
244    /// assert_eq!(s, "bar");
245    /// assert_eq!(s.as_ptr(), ptr);
246    /// ```
247    #[inline]
248    #[must_use]
249    pub fn into_string(self) -> String {
250        self.into_cow().into_owned()
251    }
252
253    /// Converts this `MStr` into an owned `Box<str>`.
254    /// This will consume `self`.
255    ///
256    /// If `self` is owned, the allocation will be reused.  
257    /// If `self` is borrowed, it will be copied to the heap.
258    ///
259    /// # Examples
260    ///
261    /// ```rust
262    /// # use mstr::MStr;
263    /// let mstr = MStr::new_borrowed("foo");
264    /// let s: Box<str> = mstr.into_boxed();
265    ///
266    /// assert_eq!(&*s, "foo");
267    /// ```
268    ///
269    /// Reuses owned allocation:
270    /// ```rust
271    /// # use mstr::MStr;
272    /// let owned = Box::<str>::from("bar");
273    /// let ptr = owned.as_ptr();
274    /// let mstr = MStr::new_owned(owned);
275    /// let s = mstr.into_boxed();
276    ///
277    /// assert_eq!(&*s, "bar");
278    /// assert_eq!(s.as_ptr(), ptr);
279    /// ```
280    #[inline]
281    #[must_use]
282    pub fn into_boxed(self) -> Box<str> {
283        self.into_string().into_boxed_str()
284    }
285
286    /// Converts this `MStr<'a>` into a `Cow<'a, str>`.
287    /// This will consume `self`.
288    ///
289    /// The returned cow will be owned if `self` is owned, and borrowed if `self` is borrowed.
290    ///
291    /// # Examples
292    ///
293    /// ```rust
294    /// # use mstr::MStr;
295    /// # use std::borrow::Cow;
296    /// let borrowed = MStr::new_borrowed("foo");
297    /// let owned = MStr::new_owned("bar");
298    ///
299    /// assert!(matches!(borrowed.into_cow(), Cow::Borrowed("foo")));
300    /// assert!(matches!(owned.into_cow(), Cow::Owned(_)));
301    /// ```
302    #[must_use]
303    pub fn into_cow(self) -> Cow<'a, str> {
304        let ptr = self.as_str_ptr();
305        let is_owned = self.is_owned();
306        mem::forget(self);
307
308        if is_owned {
309            let b = unsafe { Box::from_raw(ptr.cast_mut()) };
310            Cow::Owned(b.into_string())
311        } else {
312            Cow::Borrowed(unsafe { &*ptr })
313        }
314    }
315
316    /// Checks if this `MStr` is owned.
317    ///
318    /// The result of this function is mutually exclusive with [`is_borrowed`](MStr::is_borrowed).
319    /// Exactly one of `is_borrowed` and `is_owned` will be true for every `MStr`.
320    ///
321    /// # Examples
322    ///
323    /// ```rust
324    /// # use mstr::MStr;
325    /// let mstr = MStr::new_owned("bar");
326    ///
327    /// assert!(mstr.is_owned());
328    /// assert!(!mstr.is_borrowed());
329    /// ```
330    #[inline]
331    #[must_use]
332    pub const fn is_owned(&self) -> bool {
333        self.len & TAG == TAG
334    }
335
336    /// Checks if this `MStr` is borrowed.
337    ///
338    /// The result of this function is mutually exclusive with [`is_owned`](MStr::is_owned).
339    /// Exactly one of `is_borrowed` and `is_owned` will be true for every `MStr`.
340    ///
341    /// # Examples
342    ///
343    /// ```rust
344    /// # use mstr::MStr;
345    /// let mstr = MStr::new_borrowed("bar");
346    ///
347    /// assert!(mstr.is_borrowed());
348    /// assert!(!mstr.is_owned());
349    /// ```
350    #[inline]
351    #[must_use]
352    pub const fn is_borrowed(&self) -> bool {
353        self.len & TAG == 0
354    }
355
356    /// If this `MStr<'a>` is borrowed, get the underlying `&'a str`.
357    /// Useful if you want access to the borrowed data for longer than the borrow of `&self`.
358    ///
359    /// This will return `Some` if `self` is borrowed, and `None` if `self` is owned.
360    ///
361    /// # Examples
362    ///
363    /// ```rust
364    /// # use mstr::MStr;
365    /// let mstr: MStr<'static> = MStr::new_borrowed("abc");
366    /// let s: Option<&'static str> = mstr.as_borrowed();
367    ///
368    /// assert_eq!(s, Some("abc"));
369    /// ```
370    ///
371    /// If `self` is owned:
372    /// ```
373    /// # use mstr::MStr;
374    /// assert_eq!(MStr::new_owned("abc").as_borrowed(), None);
375    /// ```
376    #[inline]
377    #[must_use]
378    pub const fn as_borrowed(&self) -> Option<&'a str> {
379        if self.is_borrowed() {
380            // SAFETY: self is borrowed which means it is an &'a str
381            Some(unsafe { &*self.as_str_ptr() })
382        } else {
383            None
384        }
385    }
386
387    /// Gets the length of the underlying string slice.
388    ///
389    /// # Examples
390    ///
391    /// ```rust
392    /// # use mstr::MStr;
393    /// let mstr = MStr::new_borrowed("12345");
394    ///
395    /// assert_eq!(mstr.len(), 5);
396    /// ```
397    #[inline]
398    #[must_use]
399    pub const fn len(&self) -> usize {
400        self.len & MASK
401    }
402
403    /// Checks if the underlying string slice is empty (length of 0)
404    ///
405    /// # Examples
406    ///
407    /// ```rust
408    /// # use mstr::MStr;
409    /// let empty = MStr::new_borrowed("");
410    /// let mstr = MStr::new_borrowed("foo");
411    ///
412    /// assert!(empty.is_empty());
413    /// assert!(!mstr.is_empty());
414    /// ```
415    #[inline]
416    #[must_use]
417    pub const fn is_empty(&self) -> bool {
418        self.len() == 0
419    }
420
421    /// Gets a pointer (`*const u8`) to the underlying slice's buffer.
422    ///
423    /// Do **NOT** use the returned pointer mutably, as `self` may be borrowed.
424    ///
425    /// Use [`as_str_ptr`](MStr::as_str_ptr) if you want a `*const str` instead.
426    ///
427    /// # Examples
428    ///
429    /// ```rust
430    /// # use mstr::MStr;
431    /// let s = "foo";
432    /// let mstr = MStr::new_borrowed(s);
433    ///
434    /// assert_eq!(mstr.as_ptr(), s.as_ptr());
435    /// ```
436    #[inline]
437    #[must_use]
438    pub const fn as_ptr(&self) -> *const u8 {
439        self.ptr.as_ptr()
440    }
441
442    /// Gets a pointer (`*const str`) to the underlying slice's buffer.
443    ///
444    /// Do **NOT** use the returned pointer mutably, as `self` may be borrowed.
445    ///
446    /// Use [`as_ptr`](MStr::as_ptr) if you want a `*const u8` instead.
447    ///
448    /// # Examples
449    ///
450    /// ```rust
451    /// # use mstr::MStr;
452    /// let s = "foo";
453    /// let mstr = MStr::new_borrowed(s);
454    ///
455    /// assert_eq!(mstr.as_str_ptr(), s as *const str);
456    /// ```
457    #[inline]
458    #[must_use]
459    pub const fn as_str_ptr(&self) -> *const str {
460        ptr::slice_from_raw_parts::<u8>(self.as_ptr(), self.len()) as *const str
461    }
462}
463
464// ===== Trait Impls =====
465
466impl Clone for MStr<'_> {
467    /// Clones this `MStr`.
468    ///
469    /// The returned `MStr` will be owned if `self` is owned, and borrowed if `self` is borrowed.
470    ///
471    /// # Examples
472    ///
473    /// ```rust
474    /// # use mstr::MStr;
475    /// let mstr = MStr::new_owned("foo");
476    /// let mstr2 = mstr.clone();
477    ///
478    /// assert_eq!(mstr, mstr2);
479    /// ```
480    ///
481    /// Borrowed/Owned is preserved:
482    /// ```rust
483    /// # use mstr::MStr;
484    /// let borrowed = MStr::new_borrowed("bar");
485    /// let owned = MStr::new_owned("qux");
486    ///
487    /// assert!(borrowed.clone().is_borrowed());
488    /// assert!(owned.clone().is_owned());
489    /// ```
490    fn clone(&self) -> Self {
491        if self.is_borrowed() {
492            MStr::_new(self.as_ptr(), self.len(), false)
493        } else {
494            MStr::new_owned(self.as_str())
495        }
496    }
497}
498
499impl Drop for MStr<'_> {
500    fn drop(&mut self) {
501        if self.is_owned() {
502            let b = unsafe { Box::from_raw(self.as_str_ptr().cast_mut()) };
503            drop(b);
504        }
505    }
506}
507
508// -- Default --
509
510impl Default for MStr<'_> {
511    /// Creates a new, empty, borrowed `MStr`.
512    ///
513    /// The returned `MStr` can have any lifetime.
514    ///
515    /// # Examples
516    ///
517    /// ```rust
518    /// # use mstr::MStr;
519    /// let default = MStr::default();
520    ///
521    /// assert_eq!(default, "");
522    /// assert!(default.is_empty());
523    /// assert!(default.is_borrowed());
524    /// ```
525    fn default() -> Self {
526        // a dangling (suitably aligned) slice of length 0 is always valid
527        MStr::_new(NonNull::<u8>::dangling().as_ptr(), 0, false)
528    }
529}
530
531// -- Format --
532
533impl Debug for MStr<'_> {
534    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
535        Debug::fmt(self.as_str(), f)
536    }
537}
538
539impl Display for MStr<'_> {
540    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
541        Display::fmt(self.as_str(), f)
542    }
543}
544
545impl Pointer for MStr<'_> {
546    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
547        Pointer::fmt(&self.as_str_ptr(), f)
548    }
549}
550
551// -- Convert From --
552
553impl<'a> From<&'a str> for MStr<'a> {
554    fn from(value: &'a str) -> Self {
555        MStr::new_borrowed(value)
556    }
557}
558
559impl<'a> From<&'a mut str> for MStr<'a> {
560    fn from(value: &'a mut str) -> Self {
561        MStr::new_borrowed(value)
562    }
563}
564
565impl<'a> From<Cow<'a, str>> for MStr<'a> {
566    fn from(value: Cow<'a, str>) -> Self {
567        MStr::new_cow(value)
568    }
569}
570
571impl From<String> for MStr<'_> {
572    fn from(value: String) -> Self {
573        MStr::new_owned(value)
574    }
575}
576
577impl From<Box<str>> for MStr<'_> {
578    fn from(value: Box<str>) -> Self {
579        MStr::new_owned(value)
580    }
581}
582
583// -- Convert To --
584
585impl<'a> From<MStr<'a>> for Cow<'a, str> {
586    fn from(value: MStr<'a>) -> Self {
587        value.into_cow()
588    }
589}
590
591impl From<MStr<'_>> for String {
592    fn from(value: MStr<'_>) -> Self {
593        value.into_string()
594    }
595}
596
597impl From<MStr<'_>> for Box<str> {
598    fn from(value: MStr<'_>) -> Self {
599        value.into_boxed()
600    }
601}
602
603// -- Convert Ref --
604
605impl Deref for MStr<'_> {
606    type Target = str;
607
608    fn deref(&self) -> &Self::Target {
609        self.as_str()
610    }
611}
612
613impl AsRef<str> for MStr<'_> {
614    fn as_ref(&self) -> &str {
615        self.as_str()
616    }
617}
618
619impl AsRef<[u8]> for MStr<'_> {
620    fn as_ref(&self) -> &[u8] {
621        self.as_bytes()
622    }
623}
624
625impl Borrow<str> for MStr<'_> {
626    fn borrow(&self) -> &str {
627        self.as_str()
628    }
629}
630
631// no Borrow<[u8]> because str/String don't implement it
632// (because the Hash impls are different)
633
634// -- Hash --
635
636impl Hash for MStr<'_> {
637    fn hash<H: Hasher>(&self, state: &mut H) {
638        Hash::hash(self.as_str(), state)
639    }
640}
641
642// -- [Partial]Eq --
643
644impl Eq for MStr<'_> {}
645
646impl PartialEq for MStr<'_> {
647    fn eq(&self, other: &Self) -> bool {
648        self.as_str() == other.as_str()
649    }
650}
651
652// str
653
654impl PartialEq<str> for MStr<'_> {
655    fn eq(&self, other: &str) -> bool {
656        self.as_str() == other
657    }
658}
659
660impl PartialEq<MStr<'_>> for str {
661    fn eq(&self, other: &MStr<'_>) -> bool {
662        self == other.as_str()
663    }
664}
665
666// &str
667
668impl PartialEq<&str> for MStr<'_> {
669    fn eq(&self, other: &&str) -> bool {
670        self.as_str() == *other
671    }
672}
673
674impl PartialEq<MStr<'_>> for &str {
675    fn eq(&self, other: &MStr<'_>) -> bool {
676        *self == other.as_str()
677    }
678}
679
680// String
681
682impl PartialEq<String> for MStr<'_> {
683    fn eq(&self, other: &String) -> bool {
684        self.as_str() == other
685    }
686}
687
688impl PartialEq<MStr<'_>> for String {
689    fn eq(&self, other: &MStr<'_>) -> bool {
690        self == other.as_str()
691    }
692}
693
694// Box<str>
695
696impl PartialEq<Box<str>> for MStr<'_> {
697    fn eq(&self, other: &Box<str>) -> bool {
698        self.as_str() == &**other
699    }
700}
701
702impl PartialEq<MStr<'_>> for Box<str> {
703    fn eq(&self, other: &MStr<'_>) -> bool {
704        &**self == other.as_str()
705    }
706}
707
708// -- [Partial]Ord --
709
710impl Ord for MStr<'_> {
711    fn cmp(&self, other: &Self) -> Ordering {
712        self.as_str().cmp(other.as_str())
713    }
714}
715
716impl PartialOrd for MStr<'_> {
717    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
718        Some(self.cmp(other))
719    }
720}
721
722impl PartialOrd<str> for MStr<'_> {
723    fn partial_cmp(&self, other: &str) -> Option<Ordering> {
724        self.as_str().partial_cmp(other)
725    }
726}
727
728impl PartialOrd<MStr<'_>> for str {
729    fn partial_cmp(&self, other: &MStr<'_>) -> Option<Ordering> {
730        self.partial_cmp(other.as_str())
731    }
732}
733
734// ===== serde =====
735
736#[cfg(feature = "serde")]
737mod serde_impls {
738    use super::*;
739    use serde::de::{Deserialize, Deserializer, Error, Visitor};
740    use serde::ser::{Serialize, Serializer};
741
742    // -- Serialize --
743
744    impl Serialize for MStr<'_> {
745        fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
746            s.serialize_str(self.as_str())
747        }
748    }
749
750    // -- Deserialize --
751
752    struct MStrVisitor;
753
754    impl Visitor<'_> for MStrVisitor {
755        type Value = MStr<'static>;
756
757        fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
758            f.write_str("a string")
759        }
760
761        fn visit_str<E: Error>(self, s: &str) -> Result<Self::Value, E> {
762            Ok(MStr::new_owned(s))
763        }
764
765        fn visit_string<E: Error>(self, s: String) -> Result<Self::Value, E> {
766            Ok(MStr::new_owned(s))
767        }
768    }
769
770    impl<'de> Deserialize<'de> for MStr<'_> {
771        fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
772            d.deserialize_string(MStrVisitor)
773        }
774    }
775
776    // -- Unit Tests --
777
778    #[cfg(test)]
779    mod tests {
780        use super::*;
781        use serde::de::DeserializeOwned;
782        use serde_json::json;
783        use serde_test::{assert_tokens, Token};
784
785        #[test]
786        fn basic() {
787            assert_tokens(&MStr::from("roar"), &[Token::BorrowedStr("roar")]);
788            assert_tokens(&MStr::from("honk"), &[Token::Str("honk")]);
789            assert_tokens(&MStr::from("quack"), &[Token::String("quack")]);
790        }
791
792        #[test]
793        fn always_de_owned() {
794            let not_static = String::from("\"frogs <3\"");
795
796            let s: MStr<'static> = serde_json::from_str(&not_static).unwrap();
797
798            assert_eq!(s, "frogs <3");
799            assert!(s.is_owned());
800        }
801
802        #[test]
803        fn de_value() {
804            let s: MStr<'static> =
805                serde_json::from_value(json!("i like frogs can you tell")).unwrap();
806
807            assert_eq!(s, "i like frogs can you tell");
808            assert!(s.is_owned());
809        }
810
811        #[test]
812        fn assert_deserialize_owned() {
813            fn assert_deserialize_owned<T: DeserializeOwned>() {}
814
815            assert_deserialize_owned::<MStr<'_>>();
816            assert_deserialize_owned::<MStr<'static>>();
817        }
818    }
819}
820
821// ===== Unit Tests =====
822
823#[cfg(test)]
824mod tests {
825    use super::*;
826
827    // fix inference
828    type Cow<'a> = alloc::borrow::Cow<'a, str>;
829
830    #[test]
831    fn correct_repr() {
832        assert!(MStr::new_borrowed("abc").is_borrowed());
833        assert!(!MStr::new_borrowed("abc").is_owned());
834
835        assert!(MStr::new_owned("123").is_owned());
836        assert!(!MStr::new_owned("123").is_borrowed());
837    }
838
839    #[test]
840    fn empty() {
841        assert!(MStr::new_borrowed("").is_empty());
842        assert!(MStr::new_owned("").is_empty());
843        assert!(MStr::default().is_empty());
844
845        assert_eq!(MStr::new_borrowed("").len(), 0);
846        assert_eq!(MStr::new_owned("").len(), 0);
847        assert_eq!(MStr::default().len(), 0);
848    }
849
850    #[test]
851    fn owned_empty() {
852        // even though its dangling it should still be marked as owned
853        // behaviour has to be consistent
854        assert!(MStr::new_owned("").is_owned());
855        assert!(MStr::new_owned(Box::<str>::default()).is_owned());
856    }
857
858    #[test]
859    fn len() {
860        assert_eq!(MStr::new_borrowed("12345").len(), 5);
861        assert_eq!(MStr::new_owned("12345").len(), 5);
862    }
863
864    #[test]
865    fn borrowed_stays_borrowed() {
866        let s = "1234";
867        let mstr = MStr::new_borrowed(s);
868
869        assert_eq!(mstr, s);
870        assert_eq!(mstr.as_str(), s);
871
872        assert_eq!(mstr.as_ptr(), s.as_ptr());
873        assert_eq!(mstr.as_str().as_ptr(), s.as_ptr());
874        assert_eq!(mstr.as_str_ptr(), s as *const str);
875
876        let clone = mstr.clone();
877
878        assert!(clone.is_borrowed());
879        assert!(!clone.is_owned());
880
881        assert_eq!(mstr, clone);
882        assert_eq!(mstr.as_ptr(), clone.as_ptr());
883        assert_eq!(mstr.as_str_ptr(), clone.as_str_ptr());
884    }
885
886    #[test]
887    fn into_cow() {
888        assert!(matches!(
889            MStr::new_borrowed("meow").into_cow(),
890            Cow::Borrowed("meow")
891        ));
892        assert!(matches!(
893            MStr::new_cow(Cow::Borrowed("purr")).into_cow(),
894            Cow::Borrowed("purr")
895        ));
896
897        assert!(matches!(MStr::new_owned("woof").into_cow(), Cow::Owned(_)));
898        assert!(matches!(
899            MStr::new_cow(Cow::Owned("bark".into())).into_cow(),
900            Cow::Owned(_)
901        ));
902
903        assert_eq!(MStr::new_owned("woof").into_cow(), "woof");
904        assert_eq!(MStr::new_cow(Cow::Owned("bark".into())).into_cow(), "bark");
905    }
906
907    #[test]
908    fn roundtrip() {
909        assert_eq!(MStr::new_borrowed("foo").into_string(), String::from("foo"));
910        assert_eq!(MStr::new_owned("bar").into_string(), String::from("bar"));
911    }
912
913    #[test]
914    fn roundtrip_string_ptr() {
915        let s = String::from("quack");
916        let ptr = s.as_ptr();
917        let mstr = MStr::new_owned(s);
918
919        assert_eq!(mstr, "quack");
920        assert_eq!(mstr.as_ptr(), ptr);
921
922        let s2 = mstr.into_string();
923        assert_eq!(s2.as_ptr(), ptr);
924    }
925
926    #[test]
927    fn owned_clone() {
928        let mstr = MStr::new_owned("quack");
929        let mstr2 = mstr.clone();
930
931        assert!(mstr.is_owned());
932        assert!(mstr2.is_owned());
933        assert!(!mstr2.is_borrowed());
934
935        assert_eq!(mstr, mstr2);
936        assert_ne!(mstr.as_ptr(), mstr2.as_ptr());
937        assert_ne!(mstr.as_str_ptr(), mstr2.as_str_ptr());
938    }
939
940    #[test]
941    fn as_borrowed() {
942        let s = String::from("meow");
943        let mstr = MStr::new_borrowed(&s);
944        let s2 = mstr.as_borrowed();
945        drop(mstr);
946        assert_eq!(s2, Some("meow"));
947        assert_eq!(s2.unwrap(), s);
948    }
949
950    #[test]
951    fn static_lt() {
952        let owned: MStr<'static> = MStr::new_owned("abc");
953        let borrowed: MStr<'static> = MStr::new_borrowed("abc");
954
955        assert_eq!(owned, borrowed);
956    }
957
958    #[test]
959    fn covariant_lt() {
960        fn same_lt<'a>(a: &MStr<'a>, b: &MStr<'a>, s: &'a str) {
961            assert_eq!(a, b);
962            assert_eq!(a, s);
963            assert_eq!(b, s);
964        }
965
966        let st1: MStr<'static> = MStr::new_borrowed("oink");
967        let st2: MStr<'static> = MStr::new_owned("oink");
968
969        same_lt(&st1, &st2, "oink");
970
971        let s = String::from("oink");
972        let ms = MStr::new_borrowed(&s);
973
974        same_lt(&st1, &ms, &s);
975
976        // --
977
978        fn coerce_any_lt_owned<'a>() -> MStr<'a> {
979            MStr::new_owned("abc")
980        }
981        assert_eq!(coerce_any_lt_owned(), "abc");
982
983        fn coerce_any_lt_borrowed<'a>() -> MStr<'a> {
984            MStr::new_borrowed("123")
985        }
986        assert_eq!(coerce_any_lt_borrowed(), "123");
987    }
988
989    #[test]
990    fn assert_send_sync() {
991        fn assert_send_sync<T: Send + Sync>() {}
992
993        assert_send_sync::<MStr<'_>>();
994        assert_send_sync::<MStr<'static>>();
995    }
996}