thrift_parser/
types.rs

1use nom::branch::alt;
2use nom::bytes::complete::tag;
3use nom::character::complete::char as cchar;
4use nom::combinator::{map, opt};
5use nom::sequence::{delimited, pair, preceded, separated_pair, terminated, tuple};
6use nom::IResult;
7
8use crate::basic::{Identifier, IdentifierRef, Literal, LiteralRef, Separator};
9use crate::Parser;
10
11// FieldType       ::=  Identifier | BaseType | ContainerType
12// BaseType        ::=  'bool' | 'byte' | 'i8' | 'i16' | 'i32' | 'i64' | 'double' | 'string' | 'binary'
13// ContainerType   ::=  MapType | SetType | ListType
14// MapType         ::=  'map' CppType? '<' FieldType ',' FieldType '>'
15// SetType         ::=  'set' CppType? '<' FieldType '>'
16// ListType        ::=  'list' '<' FieldType '>' CppType?
17// CppType         ::=  'cpp_type' Literal
18// Note: CppType is not fully supported in out impl.
19#[derive(Debug, Clone, PartialEq)]
20pub enum FieldTypeRef<'a> {
21    Identifier(IdentifierRef<'a>),
22    Bool,
23    Byte,
24    I8,
25    I16,
26    I32,
27    I64,
28    Double,
29    String,
30    Binary,
31    Map(Box<FieldTypeRef<'a>>, Box<FieldTypeRef<'a>>),
32    Set(Box<FieldTypeRef<'a>>),
33    List(Box<FieldTypeRef<'a>>),
34}
35
36impl<'a> FieldTypeRef<'a> {
37    pub fn parse_base_type(input: &'a str) -> IResult<&'a str, Self> {
38        alt((
39            map(tag("bool"), |_| Self::Bool),
40            map(tag("byte"), |_| Self::Byte),
41            map(tag("i8"), |_| Self::I8),
42            map(tag("i16"), |_| Self::I16),
43            map(tag("i32"), |_| Self::I32),
44            map(tag("i64"), |_| Self::I64),
45            map(tag("double"), |_| Self::Double),
46            map(tag("string"), |_| Self::String),
47            map(tag("binary"), |_| Self::Binary),
48        ))(input)
49    }
50
51    pub fn parse_container_type(input: &'a str) -> IResult<&'a str, Self> {
52        alt((
53            map(
54                preceded(
55                    tuple((
56                        tag("map"),
57                        opt(Separator::parse),
58                        opt(terminated(CppTypeRef::parse, opt(Separator::parse))),
59                    )),
60                    delimited(
61                        pair(cchar('<'), opt(Separator::parse)),
62                        separated_pair(
63                            FieldTypeRef::parse,
64                            tuple((opt(Separator::parse), cchar(','), opt(Separator::parse))),
65                            FieldTypeRef::parse,
66                        ),
67                        pair(opt(Separator::parse), cchar('>')),
68                    ),
69                ),
70                |(k, v)| Self::Map(Box::new(k), Box::new(v)),
71            ),
72            map(
73                preceded(
74                    tuple((
75                        tag("set"),
76                        opt(Separator::parse),
77                        opt(terminated(CppTypeRef::parse, opt(Separator::parse))),
78                    )),
79                    delimited(
80                        pair(cchar('<'), opt(Separator::parse)),
81                        FieldTypeRef::parse,
82                        pair(opt(Separator::parse), cchar('>')),
83                    ),
84                ),
85                |v| Self::Set(Box::new(v)),
86            ),
87            map(
88                delimited(
89                    pair(tag("list"), opt(Separator::parse)),
90                    delimited(
91                        pair(cchar('<'), opt(Separator::parse)),
92                        FieldTypeRef::parse,
93                        pair(opt(Separator::parse), cchar('>')),
94                    ),
95                    opt(pair(opt(Separator::parse), CppTypeRef::parse)),
96                ),
97                |v| Self::List(Box::new(v)),
98            ),
99            map(IdentifierRef::parse, Self::Identifier),
100        ))(input)
101    }
102
103    pub fn parse_identifier_type(input: &'a str) -> IResult<&'a str, Self> {
104        map(IdentifierRef::parse, Self::Identifier)(input)
105    }
106}
107
108impl<'a> Parser<'a> for FieldTypeRef<'a> {
109    fn parse(input: &'a str) -> IResult<&'a str, Self> {
110        alt((
111            Self::parse_base_type,
112            Self::parse_container_type,
113            Self::parse_identifier_type,
114        ))(input)
115    }
116}
117
118#[derive(Debug, Clone, PartialEq)]
119pub enum FieldType {
120    Identifier(Identifier),
121    Bool,
122    Byte,
123    I8,
124    I16,
125    I32,
126    I64,
127    Double,
128    String,
129    Binary,
130    Map(Box<FieldType>, Box<FieldType>),
131    Set(Box<FieldType>),
132    List(Box<FieldType>),
133}
134
135impl<'a> From<FieldTypeRef<'a>> for FieldType {
136    fn from(r: FieldTypeRef<'a>) -> Self {
137        match r {
138            FieldTypeRef::Identifier(i) => FieldType::Identifier(i.into()),
139            FieldTypeRef::Bool => FieldType::Bool,
140            FieldTypeRef::Byte => FieldType::Byte,
141            FieldTypeRef::I8 => FieldType::I8,
142            FieldTypeRef::I16 => FieldType::I16,
143            FieldTypeRef::I32 => FieldType::I32,
144            FieldTypeRef::I64 => FieldType::I64,
145            FieldTypeRef::Double => FieldType::Double,
146            FieldTypeRef::String => FieldType::String,
147            FieldTypeRef::Binary => FieldType::Binary,
148            FieldTypeRef::Map(k, v) => {
149                FieldType::Map(Box::new(k.as_ref().into()), Box::new(v.as_ref().into()))
150            }
151            FieldTypeRef::Set(v) => FieldType::Set(Box::new(v.as_ref().into())),
152            FieldTypeRef::List(v) => FieldType::List(Box::new(v.as_ref().into())),
153        }
154    }
155}
156
157impl<'a> From<&FieldTypeRef<'a>> for FieldType {
158    fn from(r: &FieldTypeRef<'a>) -> Self {
159        match r {
160            FieldTypeRef::Identifier(i) => FieldType::Identifier(i.clone().into()),
161            FieldTypeRef::Bool => FieldType::Bool,
162            FieldTypeRef::Byte => FieldType::Byte,
163            FieldTypeRef::I8 => FieldType::I8,
164            FieldTypeRef::I16 => FieldType::I16,
165            FieldTypeRef::I32 => FieldType::I32,
166            FieldTypeRef::I64 => FieldType::I64,
167            FieldTypeRef::Double => FieldType::Double,
168            FieldTypeRef::String => FieldType::String,
169            FieldTypeRef::Binary => FieldType::Binary,
170            FieldTypeRef::Map(k, v) => {
171                FieldType::Map(Box::new(k.as_ref().into()), Box::new(v.as_ref().into()))
172            }
173            FieldTypeRef::Set(v) => FieldType::Set(Box::new(v.as_ref().into())),
174            FieldTypeRef::List(v) => FieldType::List(Box::new(v.as_ref().into())),
175        }
176    }
177}
178
179impl<'a> Parser<'a> for FieldType {
180    fn parse(input: &'a str) -> IResult<&'a str, Self> {
181        FieldTypeRef::parse(input).map(|(remains, parsed)| (remains, parsed.into()))
182    }
183}
184
185// CppType         ::=  'cpp_type' Literal
186#[derive(derive_newtype::NewType, Eq, PartialEq, Debug, Clone)]
187pub struct CppTypeRef<'a>(LiteralRef<'a>);
188
189impl<'a> Parser<'a> for CppTypeRef<'a> {
190    fn parse(input: &'a str) -> IResult<&'a str, Self> {
191        map(
192            preceded(
193                tag("cpp_type"),
194                preceded(Separator::parse, LiteralRef::parse),
195            ),
196            Self,
197        )(input)
198    }
199}
200#[derive(derive_newtype::NewType, Eq, PartialEq, Debug, Clone)]
201pub struct CppType(Literal);
202
203impl<'a> From<CppTypeRef<'a>> for CppType {
204    fn from(r: CppTypeRef<'a>) -> Self {
205        Self(r.0.into())
206    }
207}
208
209impl<'a> Parser<'a> for CppType {
210    fn parse(input: &'a str) -> IResult<&'a str, Self> {
211        CppTypeRef::parse(input).map(|(remains, parsed)| (remains, parsed.into()))
212    }
213}
214
215#[cfg(test)]
216mod test {
217    use crate::utils::*;
218
219    use super::*;
220
221    #[test]
222    fn test_cpp_type() {
223        assert_list_eq_with_f(
224            vec!["cpp_type \"MINI-LUST\"", "cpp_type 'ihciah'"],
225            vec![LiteralRef::from("MINI-LUST"), LiteralRef::from("ihciah")],
226            CppTypeRef::parse,
227            CppTypeRef,
228        );
229    }
230
231    #[test]
232    fn test_field_type() {
233        assert_list_eq_with_f(
234            vec!["bool", "i16"],
235            vec![FieldTypeRef::Bool, FieldTypeRef::I16],
236            FieldTypeRef::parse,
237            |x| x,
238        );
239        assert_eq!(
240            FieldTypeRef::parse("map <bool, bool>").unwrap().1,
241            FieldTypeRef::Map(Box::new(FieldTypeRef::Bool), Box::new(FieldTypeRef::Bool))
242        );
243        assert_eq!(
244            FieldTypeRef::parse("map<bool,bool>").unwrap().1,
245            FieldTypeRef::Map(Box::new(FieldTypeRef::Bool), Box::new(FieldTypeRef::Bool))
246        );
247        assert_eq!(
248            FieldTypeRef::parse("set <bool>").unwrap().1,
249            FieldTypeRef::Set(Box::new(FieldTypeRef::Bool))
250        );
251        assert_eq!(
252            FieldTypeRef::parse("set<bool>").unwrap().1,
253            FieldTypeRef::Set(Box::new(FieldTypeRef::Bool))
254        );
255        assert_eq!(
256            FieldTypeRef::parse("list <bool>").unwrap().1,
257            FieldTypeRef::List(Box::new(FieldTypeRef::Bool))
258        );
259        assert_eq!(
260            FieldTypeRef::parse("list<bool>").unwrap().1,
261            FieldTypeRef::List(Box::new(FieldTypeRef::Bool))
262        );
263        assert_eq!(
264            FieldTypeRef::parse("ihc_iah").unwrap().1,
265            FieldTypeRef::Identifier(IdentifierRef::from("ihc_iah"))
266        );
267    }
268}