Skip to main content

virtue_next/parse/
visibility.rs

1use super::utils::*;
2use crate::Result;
3use crate::prelude::{Delimiter, TokenTree};
4use std::iter::Peekable;
5
6/// The visibility of a struct, enum, field, etc
7#[derive(Debug, PartialEq, Eq, Clone)]
8pub enum Visibility {
9    /// Default visibility. Most items are private by default.
10    Default,
11
12    /// Public visibility
13    Pub,
14}
15
16impl Visibility {
17    pub(crate) fn try_take(input: &mut Peekable<impl Iterator<Item = TokenTree>>) -> Result<Self> {
18        match input.peek() {
19            Some(TokenTree::Ident(ident)) if ident_eq(ident, "pub") => {
20                // Consume this token
21                assume_ident(input.next());
22
23                // check if the next token is `pub(...)`
24                if let Some(TokenTree::Group(g)) = input.peek() {
25                    if g.delimiter() == Delimiter::Parenthesis {
26                        // check if this is one of:
27                        // - pub ( crate )
28                        // - pub ( self )
29                        // - pub ( super )
30                        // - pub ( in ... )
31                        if let Some(TokenTree::Ident(i)) = g.stream().into_iter().next() {
32                            if matches!(i.to_string().as_str(), "crate" | "self" | "super" | "in") {
33                                // it is, ignore this token
34                                assume_group(input.next());
35                            }
36                        }
37                    }
38                }
39
40                Ok(Visibility::Pub)
41            }
42            Some(TokenTree::Group(group)) => {
43                // sometimes this is a group instead of an ident
44                // e.g. when used in `bitflags! {}`
45                let mut iter = group.stream().into_iter();
46                let tokens = (iter.next(), iter.next());
47                match tokens {
48                    (Some(TokenTree::Ident(ident)), None) if ident_eq(&ident, "pub") => {
49                        // Consume this token
50                        assume_group(input.next());
51
52                        // check if the next token is `pub(...)`
53                        if let Some(TokenTree::Group(_)) = input.peek() {
54                            // we just consume the visibility, we're not actually using it for generation
55                            assume_group(input.next());
56                        }
57                        Ok(Visibility::Pub)
58                    }
59                    _ => Ok(Visibility::Default),
60                }
61            }
62            _ => Ok(Visibility::Default),
63        }
64    }
65}
66
67#[test]
68fn test_visibility_try_take() {
69    use crate::token_stream;
70
71    assert_eq!(
72        Visibility::Default,
73        Visibility::try_take(&mut token_stream("")).unwrap()
74    );
75    assert_eq!(
76        Visibility::Pub,
77        Visibility::try_take(&mut token_stream("pub")).unwrap()
78    );
79    assert_eq!(
80        Visibility::Pub,
81        Visibility::try_take(&mut token_stream(" pub ")).unwrap(),
82    );
83    assert_eq!(
84        Visibility::Pub,
85        Visibility::try_take(&mut token_stream("\tpub\t")).unwrap()
86    );
87    assert_eq!(
88        Visibility::Pub,
89        Visibility::try_take(&mut token_stream("pub(crate)")).unwrap()
90    );
91    assert_eq!(
92        Visibility::Pub,
93        Visibility::try_take(&mut token_stream(" pub ( crate ) ")).unwrap()
94    );
95    assert_eq!(
96        Visibility::Pub,
97        Visibility::try_take(&mut token_stream("\tpub\t(\tcrate\t)\t")).unwrap()
98    );
99
100    assert_eq!(
101        Visibility::Default,
102        Visibility::try_take(&mut token_stream("pb")).unwrap()
103    );
104}