thrift_parser/
functions.rs

1use nom::branch::alt;
2use nom::bytes::complete::tag;
3use nom::character::complete::char as cchar;
4use nom::combinator::{map, opt};
5use nom::multi::separated_list0;
6use nom::sequence::{delimited, pair, preceded, terminated, tuple};
7use nom::IResult;
8
9use crate::basic::{Identifier, IdentifierRef, ListSeparator, Separator};
10use crate::field::{Field, FieldRef};
11use crate::types::{FieldType, FieldTypeRef};
12use crate::Parser;
13
14// Function        ::=  'oneway'? FunctionType Identifier '(' Field* ')' Throws? ListSeparator?
15// FunctionType    ::=  FieldType | 'void'
16// Throws          ::=  'throws' '(' Field* ')'
17#[derive(Debug, Clone, PartialEq)]
18pub struct FunctionRef<'a> {
19    pub oneway: bool,
20    // returns None means void
21    pub returns: Option<FieldTypeRef<'a>>,
22    pub name: IdentifierRef<'a>,
23    pub parameters: Vec<FieldRef<'a>>,
24    pub exceptions: Option<Vec<FieldRef<'a>>>,
25}
26
27impl<'a> Parser<'a> for FunctionRef<'a> {
28    fn parse(input: &'a str) -> IResult<&'a str, Self> {
29        map(
30            tuple((
31                map(opt(terminated(tag("oneway"), Separator::parse)), |x| {
32                    x.is_some()
33                }),
34                terminated(
35                    alt((map(tag("void"), |_| None), map(FieldTypeRef::parse, Some))),
36                    Separator::parse,
37                ),
38                terminated(IdentifierRef::parse, opt(Separator::parse)),
39                terminated(
40                    delimited(
41                        cchar('('),
42                        separated_list0(Separator::parse, FieldRef::parse),
43                        cchar(')'),
44                    ),
45                    opt(Separator::parse),
46                ),
47                opt(preceded(
48                    pair(tag("throws"), Separator::parse),
49                    delimited(
50                        cchar('('),
51                        separated_list0(Separator::parse, FieldRef::parse),
52                        cchar(')'),
53                    ),
54                )),
55                opt(pair(opt(Separator::parse), ListSeparator::parse)),
56            )),
57            |(oneway, returns, name, parameters, exceptions, _)| Self {
58                oneway,
59                returns,
60                name,
61                parameters,
62                exceptions,
63            },
64        )(input)
65    }
66}
67
68#[derive(Debug, Clone, PartialEq)]
69pub struct Function {
70    pub oneway: bool,
71    // returns None means void
72    pub returns: Option<FieldType>,
73    pub name: Identifier,
74    pub parameters: Vec<Field>,
75    pub exceptions: Option<Vec<Field>>,
76}
77
78impl<'a> From<FunctionRef<'a>> for Function {
79    fn from(r: FunctionRef<'a>) -> Self {
80        Self {
81            oneway: r.oneway,
82            returns: r.returns.map(Into::into),
83            name: r.name.into(),
84            parameters: r.parameters.into_iter().map(Into::into).collect(),
85            exceptions: r
86                .exceptions
87                .map(|x| x.into_iter().map(Into::into).collect()),
88        }
89    }
90}
91
92impl<'a> Parser<'a> for Function {
93    fn parse(input: &'a str) -> IResult<&'a str, Self> {
94        FunctionRef::parse(input).map(|(remains, parsed)| (remains, parsed.into()))
95    }
96}
97
98#[cfg(test)]
99mod test {
100    use crate::basic::LiteralRef;
101    use crate::constant::{ConstValueRef, IntConstant};
102
103    use super::*;
104
105    #[test]
106    fn test_function() {
107        let expected = FunctionRef {
108            oneway: false,
109            returns: Some(FieldTypeRef::String),
110            name: IdentifierRef::from("GetUser"),
111            parameters: vec![FieldRef {
112                id: None,
113                required: Some(true),
114                type_: FieldTypeRef::String,
115                name: IdentifierRef::from("name"),
116                default: Some(ConstValueRef::Literal(LiteralRef::from("ihciah"))),
117            }],
118            exceptions: None,
119        };
120        assert_eq!(
121            FunctionRef::parse("string GetUser(required string name='ihciah')")
122                .unwrap()
123                .1,
124            expected
125        );
126
127        let expected = FunctionRef {
128            oneway: true,
129            returns: None,
130            name: IdentifierRef::from("DeleteUser"),
131            parameters: vec![FieldRef {
132                id: Some(IntConstant::from(10086)),
133                required: Some(false),
134                type_: FieldTypeRef::I32,
135                name: IdentifierRef::from("age"),
136                default: None,
137            }],
138            exceptions: None,
139        };
140        assert_eq!(
141            FunctionRef::parse("oneway void DeleteUser(10086:optional i32 age)")
142                .unwrap()
143                .1,
144            expected
145        );
146    }
147}