virtue_next/parse/
visibility.rs

1use super::utils::*;
2use crate::prelude::{Delimiter, TokenTree};
3use crate::Result;
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                match (iter.next(), iter.next()) {
47                    (Some(TokenTree::Ident(ident)), None) if ident_eq(&ident, "pub") => {
48                        // Consume this token
49                        assume_group(input.next());
50
51                        // check if the next token is `pub(...)`
52                        if let Some(TokenTree::Group(_)) = input.peek() {
53                            // we just consume the visibility, we're not actually using it for generation
54                            assume_group(input.next());
55                        }
56                        Ok(Visibility::Pub)
57                    }
58                    _ => Ok(Visibility::Default),
59                }
60            }
61            _ => Ok(Visibility::Default),
62        }
63    }
64}
65
66#[test]
67fn test_visibility_try_take() {
68    use crate::token_stream;
69
70    assert_eq!(
71        Visibility::Default,
72        Visibility::try_take(&mut token_stream("")).unwrap()
73    );
74    assert_eq!(
75        Visibility::Pub,
76        Visibility::try_take(&mut token_stream("pub")).unwrap()
77    );
78    assert_eq!(
79        Visibility::Pub,
80        Visibility::try_take(&mut token_stream(" pub ")).unwrap(),
81    );
82    assert_eq!(
83        Visibility::Pub,
84        Visibility::try_take(&mut token_stream("\tpub\t")).unwrap()
85    );
86    assert_eq!(
87        Visibility::Pub,
88        Visibility::try_take(&mut token_stream("pub(crate)")).unwrap()
89    );
90    assert_eq!(
91        Visibility::Pub,
92        Visibility::try_take(&mut token_stream(" pub ( crate ) ")).unwrap()
93    );
94    assert_eq!(
95        Visibility::Pub,
96        Visibility::try_take(&mut token_stream("\tpub\t(\tcrate\t)\t")).unwrap()
97    );
98
99    assert_eq!(
100        Visibility::Default,
101        Visibility::try_take(&mut token_stream("pb")).unwrap()
102    );
103}