arcstr/
mac.rs

1/// Create a const [`ArcStr`](crate::ArcStr) from a string literal. The
2/// resulting `ArcStr` require no heap allocation, can be freely cloned and used
3/// interchangeably with `ArcStr`s from the heap, and are effectively "free".
4///
5/// The main downside is that it's a macro. Eventually it may be doable as a
6/// `const fn`, which would be cleaner, but for now the drawbacks to this are
7/// not overwhelming, and the functionality it provides is very useful.
8///
9/// # Usage
10///
11/// ```
12/// # use arcstr::ArcStr;
13/// // Works in const:
14/// const MY_ARCSTR: ArcStr = arcstr::literal!("testing testing");
15/// assert_eq!(MY_ARCSTR, "testing testing");
16///
17/// // Or, just in normal expressions.
18/// assert_eq!("Wow!", arcstr::literal!("Wow!"));
19/// ```
20///
21/// Another motivating use case is bundled files:
22///
23/// ```rust,ignore
24/// use arcstr::ArcStr;
25/// const VERY_IMPORTANT_FILE: ArcStr =
26///     arcstr::literal!(include_str!("./very-important.txt"));
27/// ```
28#[macro_export]
29macro_rules! literal {
30    ($text:expr $(,)?) => {{
31        // Note: extra scope to reduce the size of what's in `$text`'s scope
32        // (note that consts in macros dont have hygene the way let does).
33        const __TEXT: &$crate::_private::str = $text;
34        {
35            #[allow(clippy::declare_interior_mutable_const)]
36            const SI: &$crate::_private::StaticArcStrInner<[$crate::_private::u8; __TEXT.len()]> = unsafe {
37                &$crate::_private::StaticArcStrInner {
38                    len_flag: match $crate::_private::StaticArcStrInner::<[$crate::_private::u8; __TEXT.len()]>::encode_len(__TEXT.len()) {
39                        Some(len) => len,
40                        None => $crate::core::panic!("impossibly long length")
41                    },
42                    count_flag: $crate::_private::StaticArcStrInner::<[$crate::_private::u8; __TEXT.len()]>::STATIC_COUNT_VALUE,
43                    // See comment for `_private::ConstPtrDeref` for what the hell's
44                    // going on here.
45                    data: *$crate::_private::ConstPtrDeref::<[$crate::_private::u8; __TEXT.len()]> {
46                        p: __TEXT.as_ptr(),
47                    }
48                    .a,
49                    // data: __TEXT.as_ptr().cast::<[$crate::_private::u8; __TEXT.len()]>().read(),
50                }
51            };
52            #[allow(clippy::declare_interior_mutable_const)]
53            const S: $crate::ArcStr = unsafe { $crate::ArcStr::_private_new_from_static_data(SI) };
54            S
55        }
56    }};
57}
58
59/// Conceptually equivalent to `ArcStr::from(format!("...", args...))`.
60///
61/// In the future, this will be implemented in such a way to avoid an additional
62/// string copy which is required by the `from` operation.
63///
64/// # Example
65///
66/// ```
67/// let arcstr = arcstr::format!("testing {}", 123);
68/// assert_eq!(arcstr, "testing 123");
69/// ```
70#[macro_export]
71macro_rules! format {
72    ($($toks:tt)*) => {
73        $crate::ArcStr::from($crate::alloc::fmt::format($crate::core::format_args!($($toks)*)))
74    };
75}
76
77/// `feature = "substr"`: Create a `const` [`Substr`][crate::Substr].
78///
79/// This is a wrapper that initializes a `Substr` over the entire contents of a
80/// `const` [`ArcStr`](crate::ArcStr) made using [arcstr::literal!](crate::literal).
81///
82/// As with `arcstr::literal`, these require no heap allocation, can be freely
83/// cloned and used interchangeably with `ArcStr`s from the heap, and are
84/// effectively "free".
85///
86/// The main use case here is in applications where `Substr` is a much more
87/// common string type than `ArcStr`.
88///
89/// # Examples
90///
91/// ```
92/// use arcstr::{Substr, literal_substr};
93/// // Works in const:
94/// const EXAMPLE_SUBSTR: Substr = literal_substr!("testing testing");
95/// assert_eq!(EXAMPLE_SUBSTR, "testing testing");
96///
97/// // Or, just in normal expressions.
98/// assert_eq!("Wow!", literal_substr!("Wow!"));
99/// ```
100#[macro_export]
101#[cfg(feature = "substr")]
102macro_rules! literal_substr {
103    ($text:expr $(,)?) => {{
104        const __S: &$crate::_private::str = $text;
105        {
106            const PARENT: $crate::ArcStr = $crate::literal!(__S);
107            const SUBSTR: $crate::Substr =
108                unsafe { $crate::Substr::from_parts_unchecked(PARENT, 0..__S.len()) };
109            SUBSTR
110        }
111    }};
112}
113
114#[cfg(test)]
115mod test {
116    #[test]
117    fn ensure_no_import() {
118        let v = literal!("foo");
119        assert_eq!(v, "foo");
120        #[cfg(feature = "substr")]
121        {
122            let substr = literal_substr!("bar");
123            assert_eq!(substr, "bar");
124        }
125        // Loom doesn't like it if you do things outside `loom::model`, AFAICT.
126        // These calls produce error messages from inside `libstd` about
127        // accessing thread_locals that haven't been initialized.
128        #[cfg(not(loom))]
129        {
130            let test = crate::format!("foo");
131            assert_eq!(test, "foo");
132            let test2 = crate::format!("foo {}", 123);
133            assert_eq!(test2, "foo 123");
134            #[cfg(not(msrv))]
135            {
136                let foo = "abc";
137                let test3 = crate::format!("foo {foo}");
138                assert_eq!(test3, "foo abc");
139            }
140        }
141    }
142}