Skip to main content

g_string/
macros.rs

1use crate::{Err, GString, GStringError, Validator};
2
3/// GString from const generic constructor.
4///
5/// Const generic `gstring!` is compile-time check and return this temporary type before you validate it.
6///
7/// It must be validated before getting actual `GString`.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
9pub struct NotValidatedGString<
10    V: Validator,
11    const MIN: usize,
12    const MAX: usize,
13    const ASCII_ONLY: bool,
14>(GString<V, MIN, MAX, ASCII_ONLY>);
15
16impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
17    NotValidatedGString<V, MIN, MAX, ASCII_ONLY>
18{
19    #[inline(always)]
20    pub fn validate(self) -> Result<GString<V, MIN, MAX, ASCII_ONLY>, GStringError<V::Err>> {
21        V::validate(&self.0).map_err(GStringError::Validation)?;
22        Ok(self.0)
23    }
24}
25
26macro_rules! errpanic {
27    ($expr:expr) => {
28        match $expr {
29            Ok(v) => v,
30            Err(Err::TooShort(_)) => {
31                panic!("minimum length below MIN")
32            }
33            Err(Err::TooLong(_)) => {
34                panic!("maximum length exceeds MAX")
35            }
36            Err(Err::NotAscii) => {
37                panic!("only ASCII characters are allowed")
38            }
39        }
40    };
41}
42
43impl<V: Validator, const MIN: usize, const MAX: usize, const ASCII_ONLY: bool>
44    GString<V, MIN, MAX, ASCII_ONLY>
45{
46    #[doc(hidden)]
47    pub const fn __new(s: &str) -> NotValidatedGString<V, MIN, MAX, ASCII_ONLY> {
48        let ret = errpanic!(Self::stack_allocate(s));
49        errpanic!(ret.check_bounds());
50        errpanic!(ret.check_ascii());
51        NotValidatedGString(ret)
52    }
53}
54
55/// Compile-time check for GString without validation.
56///
57/// Validation can only happen at runtime, so this macro returned [`NotValidatedGString`] needed to be validated.
58///
59/// It's only useful for checking bounds and ASCII statically at compile-time.
60///
61/// # Examples
62///
63/// ```rust
64/// use g_string::gstring;
65///
66/// let ret = gstring!("aslkdm");
67/// let ret = ret.validate().unwrap();
68/// assert_eq!(ret, "aslkdm");
69///
70/// // let ret = gstring!("aslkdm", (), 2, 4); // won't even compile
71/// ```
72#[macro_export]
73macro_rules! gstring {
74    ($s:literal) => {
75        gstring!(
76            $s,
77            $crate::NoValidation,
78            { $crate::DEFAULT_MIN },
79            { $crate::DEFAULT_MAX },
80            { $crate::DEFAULT_ASCII_ONLY }
81        )
82    };
83    ($s:literal, $validator:ty) => {
84        gstring!(
85            $s,
86            $validator,
87            { $crate::DEFAULT_MIN },
88            { $crate::DEFAULT_MAX },
89            { $crate::DEFAULT_ASCII_ONLY }
90        )
91    };
92    ($s:literal, $validator:ty, $min:expr) => {
93        gstring!($s, $validator, $min, { $crate::DEFAULT_MAX }, {
94            $crate::DEFAULT_ASCII_ONLY
95        })
96    };
97    ($s:literal, $validator:ty, $min:expr, $max:expr) => {
98        gstring!($s, $validator, $min, $max, { $crate::DEFAULT_ASCII_ONLY })
99    };
100    ($s:literal, $validator:ty, $min:expr, $max:expr, $ascii_only:expr) => {{
101        const RET: $crate::NotValidatedGString<$validator, $min, $max, $ascii_only> =
102            $crate::GString::<$validator, $min, $max, $ascii_only>::__new($s);
103        RET
104    }};
105}
106
107/// `gformat` formats string like stdlib's `format!` does, with generic/config params pluggable.
108///
109/// # Examples
110/// ```rust
111/// use g_string::gformat;
112///
113/// let ret = gformat!("--> {} - {} equals to {}", 5, 2, "three"; (), 2, 100, true).unwrap();
114/// assert_eq!(ret, "--> 5 - 2 equals to three");
115///
116/// let ret = gformat!("--> fire: {}", "🔥"; (), 2, 102, true);
117/// assert!(ret.is_err()); // ASCII_ONLY is true
118/// ```
119#[macro_export]
120macro_rules! gformat {
121    // -----------------------------------------------------------------------------
122    // DEFAULT GENERICS
123    // -----------------------------------------------------------------------------
124    ($fmt:expr $(, $args:expr)* ) => {
125        gformat!(
126            $fmt $(, $args)* ;
127            $crate::NoValidation,
128            { $crate::DEFAULT_MIN },
129            { $crate::DEFAULT_MAX },
130            { $crate::DEFAULT_ASCII_ONLY }
131        )
132    };
133
134    // -----------------------------------------------------------------------------
135    // VALIDATOR ONLY
136    // -----------------------------------------------------------------------------
137    ($fmt:expr $(, $args:expr)* ; $validator:ty) => {
138        gformat!(
139            $fmt $(, $args)* ;
140            $validator,
141            { $crate::DEFAULT_MIN },
142            { $crate::DEFAULT_MAX },
143            { $crate::DEFAULT_ASCII_ONLY }
144        )
145    };
146
147    // -----------------------------------------------------------------------------
148    // VALIDATOR + MIN
149    // -----------------------------------------------------------------------------
150    ($fmt:expr $(, $args:expr)* ; $validator:ty, $min:expr) => {
151        gformat!(
152            $fmt $(, $args)* ;
153            $validator,
154            $min,
155            { $crate::DEFAULT_MAX },
156            { $crate::DEFAULT_ASCII_ONLY }
157        )
158    };
159
160    // -----------------------------------------------------------------------------
161    // VALIDATOR + MIN + MAX
162    // -----------------------------------------------------------------------------
163    ($fmt:expr $(, $args:expr)* ; $validator:ty, $min:expr, $max:expr) => {
164        gformat!(
165            $fmt $(, $args)* ;
166            $validator,
167            $min,
168            $max,
169            { $crate::DEFAULT_ASCII_ONLY }
170        )
171    };
172
173    // -----------------------------------------------------------------------------
174    // FULL FORM
175    // -----------------------------------------------------------------------------
176    (
177        $fmt:expr $(, $args:expr)* ;
178        $validator:ty,
179        $min:expr,
180        $max:expr,
181        $ascii_only:expr
182    ) => {{
183        #[cfg(feature = "alloc")]
184        {
185            let s = format!($fmt $(, $args)*);
186
187            $crate::GString::<
188                $validator,
189                $min,
190                $max,
191                $ascii_only
192            >::try_new(&s)
193        }
194
195        #[cfg(not(feature = "alloc"))]
196        compile_error!(
197            "gformat! requires the `alloc` feature"
198        );
199    }};
200}