rama_core/username/
parse.rs

1use super::DEFAULT_USERNAME_LABEL_SEPARATOR;
2use crate::context::Extensions;
3use crate::error::{BoxError, OpaqueError};
4use rama_utils::macros::all_the_tuples_no_last_special_case;
5use std::{convert::Infallible, fmt};
6
7/// Parse a username, extracting the username (first part)
8/// and passing everything else to the [`UsernameLabelParser`].
9#[inline]
10pub fn parse_username<P>(
11    ext: &mut Extensions,
12    parser: P,
13    username_ref: impl AsRef<str>,
14) -> Result<String, OpaqueError>
15where
16    P: UsernameLabelParser<Error: Into<BoxError>>,
17{
18    parse_username_with_separator(ext, parser, username_ref, DEFAULT_USERNAME_LABEL_SEPARATOR)
19}
20
21/// Parse a username, extracting the username (first part)
22/// and passing everything else to the [`UsernameLabelParser`].
23pub fn parse_username_with_separator<P>(
24    ext: &mut Extensions,
25    mut parser: P,
26    username_ref: impl AsRef<str>,
27    separator: char,
28) -> Result<String, OpaqueError>
29where
30    P: UsernameLabelParser<Error: Into<BoxError>>,
31{
32    let username_ref = username_ref.as_ref();
33    let mut label_it = username_ref.split(separator);
34
35    let username = match label_it.next() {
36        Some(username) => {
37            if username.is_empty() {
38                return Err(OpaqueError::from_display("empty username"));
39            } else {
40                username
41            }
42        }
43        None => return Err(OpaqueError::from_display("missing username")),
44    };
45
46    for (index, label) in label_it.enumerate() {
47        match parser.parse_label(label) {
48            UsernameLabelState::Used => (), // optimistic smiley
49            UsernameLabelState::Ignored => {
50                return Err(OpaqueError::from_display(format!(
51                    "ignored username label #{index}: {}",
52                    label
53                )));
54            }
55            UsernameLabelState::Abort => {
56                return Err(OpaqueError::from_display(format!(
57                    "invalid username label #{index}: {}",
58                    label
59                )));
60            }
61        }
62    }
63
64    parser
65        .build(ext)
66        .map_err(|err| OpaqueError::from_boxed(err.into()))?;
67
68    Ok(username.to_owned())
69}
70
71/// The parse state of a username label.
72///
73/// This can be used to signal that a label was recognised in the case
74/// that you wish to fail on labels that weren't recognised.
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
76pub enum UsernameLabelState {
77    /// The label was used by this parser.
78    ///
79    /// Note in case multiple parsers are used it should in generally be ok,
80    /// for multiple to "use" the same label.
81    Used,
82
83    /// The label was ignored by this parser,
84    /// reasons for which are not important here.
85    ///
86    /// A parser-user can choose to error a request in case
87    /// a label was ignored by its parser.
88    Ignored,
89
90    /// Abort the parsing as a state has been reached
91    /// from which cannot be recovered.
92    Abort,
93}
94
95/// A parser which can parse labels from a username.
96///
97/// [`Default`] is to be implemented for every [`UsernameLabelParser`],
98/// as it is what is used to create the parser instances for one-time usage.
99pub trait UsernameLabelParser: Default + Send + Sync + 'static {
100    /// Error which can occur during the building phase.
101    type Error: Into<BoxError>;
102
103    /// Interpret the label and return whether or not the label was recognised and valid.
104    ///
105    /// [`UsernameLabelState::Ignored`] should be returned in case the label was not recognised or was not valid.
106    fn parse_label(&mut self, label: &str) -> UsernameLabelState;
107
108    /// Consume self and store/use any of the relevant info seen.
109    fn build(self, ext: &mut Extensions) -> Result<(), Self::Error>;
110}
111
112/// Wrapper type that can be used with a tuple of [`UsernameLabelParser`]s
113/// in order for it to stop iterating over the parsers once there was one that consumed the label.
114pub struct ExclusiveUsernameParsers<P>(pub P);
115
116impl<P: Clone> Clone for ExclusiveUsernameParsers<P> {
117    fn clone(&self) -> Self {
118        Self(self.0.clone())
119    }
120}
121
122impl<P: Default> Default for ExclusiveUsernameParsers<P> {
123    fn default() -> Self {
124        Self(P::default())
125    }
126}
127
128impl<P: fmt::Debug> fmt::Debug for ExclusiveUsernameParsers<P> {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        f.debug_tuple("ExclusiveUsernameParsers")
131            .field(&self.0)
132            .finish()
133    }
134}
135
136macro_rules! username_label_parser_tuple_impl {
137    ($($T:ident),+ $(,)?) => {
138        #[allow(non_snake_case)]
139        impl<$($T,)+> UsernameLabelParser for ($($T,)+)
140        where
141            $(
142                $T: UsernameLabelParser<Error: Into<BoxError>>,
143            )+
144        {
145            type Error = OpaqueError;
146
147            fn parse_label(&mut self, label: &str) -> UsernameLabelState {
148                let ($($T,)+) = self;
149                let mut state = UsernameLabelState::Ignored;
150                $(
151                    match $T.parse_label(label) {
152                        UsernameLabelState::Ignored => (),
153                        UsernameLabelState::Used => state = UsernameLabelState::Used,
154                        UsernameLabelState::Abort => return UsernameLabelState::Abort,
155                    }
156                )+
157                state
158            }
159
160            fn build(self, ext: &mut Extensions) -> Result<(), Self::Error> {
161                let ($($T,)+) = self;
162                $(
163                    $T.build(ext).map_err(|err| OpaqueError::from_boxed(err.into()))?;
164                )+
165                Ok(())
166            }
167        }
168    };
169}
170
171all_the_tuples_no_last_special_case!(username_label_parser_tuple_impl);
172
173macro_rules! username_label_parser_tuple_exclusive_labels_impl {
174    ($($T:ident),+ $(,)?) => {
175        #[allow(non_snake_case)]
176        impl<$($T,)+> UsernameLabelParser for ExclusiveUsernameParsers<($($T,)+)>
177        where
178            $(
179                $T: UsernameLabelParser<Error: Into<BoxError>>,
180            )+
181        {
182            type Error = OpaqueError;
183
184            fn parse_label(&mut self, label: &str) -> UsernameLabelState {
185                let ($(ref mut $T,)+) = self.0;
186                $(
187                    match $T.parse_label(label) {
188                        UsernameLabelState::Ignored => (),
189                        UsernameLabelState::Used => return UsernameLabelState::Used,
190                        UsernameLabelState::Abort => return UsernameLabelState::Abort,
191                    }
192                )+
193                UsernameLabelState::Ignored
194            }
195
196            fn build(self, ext: &mut Extensions) -> Result<(), Self::Error> {
197                let ($($T,)+) = self.0;
198                $(
199                    $T.build(ext).map_err(|err| OpaqueError::from_boxed(err.into()))?;
200                )+
201                Ok(())
202            }
203        }
204    };
205}
206
207all_the_tuples_no_last_special_case!(username_label_parser_tuple_exclusive_labels_impl);
208
209impl UsernameLabelParser for () {
210    type Error = Infallible;
211
212    fn parse_label(&mut self, _label: &str) -> UsernameLabelState {
213        UsernameLabelState::Used
214    }
215
216    fn build(self, _ext: &mut Extensions) -> Result<(), Self::Error> {
217        Ok(())
218    }
219}
220
221#[derive(Debug, Clone, Default)]
222/// Opaque string labels parsed collected using the [`UsernameOpaqueLabelParser`].
223///
224/// Useful in case you want to collect all labels from the username,
225/// without any specific parsing logic.
226pub struct UsernameLabels(pub Vec<String>);
227
228impl<const SEPARATOR: char> super::UsernameLabelWriter<SEPARATOR> for UsernameLabels {
229    fn write_labels(
230        &self,
231        composer: &mut super::Composer<SEPARATOR>,
232    ) -> Result<(), super::ComposeError> {
233        self.0.write_labels(composer)
234    }
235}
236
237#[derive(Debug, Clone, Default)]
238/// A [`UsernameLabelParser`] which collects all labels from the username,
239/// without any specific parsing logic.
240pub struct UsernameOpaqueLabelParser {
241    labels: Vec<String>,
242}
243
244impl UsernameOpaqueLabelParser {
245    /// Create a new [`UsernameOpaqueLabelParser`].
246    pub fn new() -> Self {
247        Self::default()
248    }
249}
250
251impl UsernameLabelParser for UsernameOpaqueLabelParser {
252    type Error = Infallible;
253
254    fn parse_label(&mut self, label: &str) -> UsernameLabelState {
255        self.labels.push(label.to_owned());
256        UsernameLabelState::Used
257    }
258
259    fn build(self, ext: &mut Extensions) -> Result<(), Self::Error> {
260        if !self.labels.is_empty() {
261            ext.insert(UsernameLabels(self.labels));
262        }
263        Ok(())
264    }
265}
266
267#[cfg(test)]
268mod test {
269    use super::*;
270
271    #[derive(Debug, Clone, Default)]
272    #[non_exhaustive]
273    struct UsernameNoLabelParser;
274
275    impl UsernameLabelParser for UsernameNoLabelParser {
276        type Error = Infallible;
277
278        fn parse_label(&mut self, _label: &str) -> UsernameLabelState {
279            UsernameLabelState::Ignored
280        }
281
282        fn build(self, _ext: &mut Extensions) -> Result<(), Self::Error> {
283            Ok(())
284        }
285    }
286
287    #[derive(Debug, Clone, Default)]
288    #[non_exhaustive]
289    struct UsernameNoLabelPanicParser;
290
291    impl UsernameLabelParser for UsernameNoLabelPanicParser {
292        type Error = Infallible;
293
294        fn parse_label(&mut self, _label: &str) -> UsernameLabelState {
295            unreachable!("this parser should not be called");
296        }
297
298        fn build(self, _ext: &mut Extensions) -> Result<(), Self::Error> {
299            Ok(())
300        }
301    }
302
303    #[derive(Debug, Clone, Default)]
304    #[non_exhaustive]
305    struct UsernameLabelAbortParser;
306
307    impl UsernameLabelParser for UsernameLabelAbortParser {
308        type Error = Infallible;
309
310        fn parse_label(&mut self, _label: &str) -> UsernameLabelState {
311            UsernameLabelState::Abort
312        }
313
314        fn build(self, _ext: &mut Extensions) -> Result<(), Self::Error> {
315            unreachable!("should not happen")
316        }
317    }
318
319    #[derive(Debug, Clone, Default)]
320    #[non_exhaustive]
321    struct MyLabelParser {
322        labels: Vec<String>,
323    }
324
325    #[derive(Debug, Clone, Default)]
326    struct MyLabels(Vec<String>);
327
328    impl UsernameLabelParser for MyLabelParser {
329        type Error = Infallible;
330
331        fn parse_label(&mut self, label: &str) -> UsernameLabelState {
332            self.labels.push(label.to_owned());
333            UsernameLabelState::Used
334        }
335
336        fn build(self, ext: &mut Extensions) -> Result<(), Self::Error> {
337            if !self.labels.is_empty() {
338                ext.insert(MyLabels(self.labels));
339            }
340            Ok(())
341        }
342    }
343
344    #[test]
345    fn test_parse_username_empty() {
346        let mut ext = Extensions::default();
347
348        assert!(parse_username(&mut ext, (), "",).is_err());
349        assert!(parse_username(&mut ext, (), "-",).is_err());
350    }
351
352    #[test]
353    fn test_parse_username_no_labels() {
354        let mut ext = Extensions::default();
355
356        assert_eq!(
357            parse_username(&mut ext, UsernameNoLabelParser, "username",).unwrap(),
358            "username"
359        );
360    }
361
362    #[test]
363    fn test_parse_username_label_collector() {
364        let mut ext = Extensions::default();
365        assert_eq!(
366            parse_username(
367                &mut ext,
368                UsernameOpaqueLabelParser::new(),
369                "username-label1-label2",
370            )
371            .unwrap(),
372            "username"
373        );
374
375        let labels = ext.get::<UsernameLabels>().unwrap();
376        assert_eq!(labels.0, vec!["label1".to_owned(), "label2".to_owned()]);
377    }
378
379    #[test]
380    fn test_username_labels_multi_parser() {
381        let mut ext = Extensions::default();
382
383        let parser = (
384            UsernameOpaqueLabelParser::new(),
385            UsernameNoLabelParser::default(),
386        );
387
388        assert_eq!(
389            parse_username(&mut ext, parser, "username-label1-label2",).unwrap(),
390            "username"
391        );
392
393        let labels = ext.get::<UsernameLabels>().unwrap();
394        assert_eq!(labels.0, vec!["label1".to_owned(), "label2".to_owned()]);
395    }
396
397    #[test]
398    fn test_username_labels_multi_consumer_parser() {
399        let mut ext = Extensions::default();
400
401        let parser = (
402            UsernameNoLabelParser::default(),
403            MyLabelParser::default(),
404            UsernameOpaqueLabelParser::new(),
405        );
406
407        assert_eq!(
408            parse_username(&mut ext, parser, "username-label1-label2",).unwrap(),
409            "username"
410        );
411
412        let labels = ext.get::<UsernameLabels>().unwrap();
413        assert_eq!(labels.0, vec!["label1".to_owned(), "label2".to_owned()]);
414
415        let labels = ext.get::<MyLabels>().unwrap();
416        assert_eq!(labels.0, vec!["label1".to_owned(), "label2".to_owned()]);
417    }
418
419    #[test]
420    fn test_username_labels_multi_consumer_exclusive_parsers() {
421        let mut ext = Extensions::default();
422
423        let parser = ExclusiveUsernameParsers((
424            UsernameOpaqueLabelParser::default(),
425            MyLabelParser::default(),
426            UsernameNoLabelPanicParser::default(),
427        ));
428
429        assert_eq!(
430            parse_username(&mut ext, parser, "username-label1-label2",).unwrap(),
431            "username"
432        );
433
434        let labels = ext.get::<UsernameLabels>().unwrap();
435        assert_eq!(labels.0, vec!["label1".to_owned(), "label2".to_owned()]);
436
437        assert!(ext.get::<MyLabels>().is_none());
438    }
439
440    #[test]
441    fn test_username_opaque_labels_none() {
442        let mut ext = Extensions::default();
443
444        let parser = UsernameOpaqueLabelParser::new();
445
446        assert_eq!(
447            parse_username(&mut ext, parser, "username",).unwrap(),
448            "username"
449        );
450
451        assert!(ext.get::<UsernameLabels>().is_none());
452    }
453
454    #[test]
455    fn test_username_label_parser_abort_tuple() {
456        let mut ext = Extensions::default();
457
458        let parser = (
459            UsernameLabelAbortParser::default(),
460            UsernameOpaqueLabelParser::default(),
461        );
462        assert!(parse_username(&mut ext, parser, "username-foo",).is_err());
463
464        let parser = (
465            UsernameOpaqueLabelParser::default(),
466            UsernameLabelAbortParser::default(),
467        );
468        assert!(parse_username(&mut ext, parser, "username-foo",).is_err());
469    }
470
471    #[test]
472    fn test_username_label_parser_abort_exclusive_tuple() {
473        let mut ext = Extensions::default();
474
475        let parser = ExclusiveUsernameParsers((
476            UsernameLabelAbortParser::default(),
477            UsernameOpaqueLabelParser::default(),
478        ));
479        assert!(parse_username(&mut ext, parser, "username-foo",).is_err());
480
481        let parser = (
482            UsernameOpaqueLabelParser::default(),
483            UsernameLabelAbortParser::default(),
484        );
485        assert!(parse_username(&mut ext, parser, "username-foo",).is_err());
486    }
487}