pmhelp_internal/exts/
is_exts.rs

1use alloc::vec::Vec;
2use syn::{
3    parse::{Parse, ParseBuffer, Peek},
4    GenericArgument, Ident, Path, PathArguments, PathSegment, Type, TypePath,
5};
6
7#[derive(PartialEq, Clone, Copy)]
8enum OptionCheckerState {
9    Unknown = 1,
10    StdOrCore = 2,
11    OptionMod = 3,
12    Final = 4,
13}
14
15impl PartialEq<PathSegment> for OptionCheckerState {
16    fn eq(&self, PathSegment { ident, arguments }: &PathSegment) -> bool {
17        match self {
18            Self::StdOrCore => {
19                (ident == "std" || ident == "core") && matches!(arguments, PathArguments::None)
20            }
21            Self::OptionMod => ident == "option" && matches!(arguments, PathArguments::None),
22            Self::Final => ident == "Option" && !matches!(arguments, PathArguments::None),
23            Self::Unknown => true,
24        }
25    }
26}
27
28impl OptionCheckerState {
29    fn next_states(&self) -> &[Self] {
30        match self {
31            Self::Final => &[],
32            Self::OptionMod => &[Self::Final],
33            Self::StdOrCore => &[Self::OptionMod],
34            Self::Unknown => &[Self::OptionMod, Self::Final, Self::StdOrCore],
35        }
36    }
37}
38
39pub trait OptionTypeExt {
40    fn is_option(&self) -> bool;
41}
42
43impl OptionTypeExt for Path {
44    fn is_option(&self) -> bool {
45        let mut current_state = if self.leading_colon.is_some() {
46            OptionCheckerState::StdOrCore
47        } else {
48            OptionCheckerState::Unknown
49        };
50        for segment in self.segments.iter() {
51            let mut state_changed = false;
52            for state in current_state.next_states() {
53                if state == segment {
54                    current_state = *state;
55                    state_changed = true;
56                    break;
57                }
58            }
59            if !state_changed {
60                return false;
61            }
62        }
63        current_state == OptionCheckerState::Final
64    }
65}
66
67impl OptionTypeExt for Type {
68    fn is_option(&self) -> bool {
69        if let Self::Path(TypePath { path, qself: None }) = &self {
70            path.is_option()
71        } else {
72            false
73        }
74    }
75}
76
77#[derive(PartialEq, Clone, Copy)]
78enum ResultCheckerState {
79    Unknown = 1,
80    StdOrCore = 2,
81    ResultMod = 3,
82    Final = 4,
83}
84
85impl PartialEq<PathSegment> for ResultCheckerState {
86    fn eq(&self, PathSegment { ident, arguments }: &PathSegment) -> bool {
87        match self {
88            Self::StdOrCore => {
89                (ident == "std" || ident == "core") && matches!(arguments, PathArguments::None)
90            }
91            Self::ResultMod => ident == "result" && matches!(arguments, PathArguments::None),
92            Self::Final => ident == "Result" && !matches!(arguments, PathArguments::None),
93            Self::Unknown => true,
94        }
95    }
96}
97
98impl ResultCheckerState {
99    fn next_states(&self) -> &[Self] {
100        match self {
101            Self::Final => &[],
102            Self::ResultMod => &[Self::Final],
103            Self::StdOrCore => &[Self::ResultMod],
104            Self::Unknown => &[Self::ResultMod, Self::Final, Self::StdOrCore],
105        }
106    }
107}
108
109pub trait ResultTypeExt {
110    fn is_result(&self) -> bool;
111}
112
113impl ResultTypeExt for Path {
114    fn is_result(&self) -> bool {
115        let mut current_state = if self.leading_colon.is_some() {
116            ResultCheckerState::StdOrCore
117        } else {
118            ResultCheckerState::Unknown
119        };
120        for segment in self.segments.iter() {
121            let mut state_changed = false;
122            for state in current_state.next_states() {
123                if state == segment {
124                    current_state = *state;
125                    state_changed = true;
126                    break;
127                }
128            }
129            if !state_changed {
130                return false;
131            }
132        }
133        current_state == ResultCheckerState::Final
134    }
135}
136
137impl ResultTypeExt for Type {
138    fn is_result(&self) -> bool {
139        if let Self::Path(TypePath { path, qself: None }) = &self {
140            path.is_result()
141        } else {
142            false
143        }
144    }
145}