webwire_cli/idl/
method.rs

1use nom::{
2    bytes::complete::tag,
3    character::complete::char,
4    combinator::map,
5    sequence::{preceded, tuple},
6    IResult,
7};
8
9use crate::idl::common::{parse_identifier, ws, Span};
10use crate::idl::r#type::{parse_opt_type, Type};
11
12#[cfg(test)]
13use crate::idl::common::assert_parse;
14
15#[derive(Debug, PartialEq)]
16pub struct Method {
17    pub name: String,
18    pub input: Option<Type>,
19    pub output: Option<Type>,
20}
21
22pub fn parse_method(input: Span) -> IResult<Span, Method> {
23    map(
24        tuple((
25            parse_identifier,
26            preceded(ws, preceded(char(':'), preceded(ws, parse_opt_type))),
27            preceded(ws, preceded(tag("->"), preceded(ws, parse_opt_type))),
28        )),
29        |(name, input, output)| Method {
30            name,
31            input,
32            output,
33        },
34    )(input)
35}
36
37#[test]
38fn test_parse_method_0() {
39    let contents = [
40        // normal whitespace
41        "ping: None -> None",
42        // whitespace variants
43        "ping:None->None",
44        "ping :None->None",
45        "ping: None->None",
46        "ping:None ->None",
47        "ping:None-> None",
48    ];
49    for content in contents.iter() {
50        assert_parse(
51            parse_method(Span::new(content)),
52            Method {
53                name: "ping".to_string(),
54                input: None,
55                output: None,
56            },
57        )
58    }
59}
60
61#[test]
62fn test_parse_method_1() {
63    use crate::idl::r#type::TypeRef;
64    let contents = [
65        // normal whitespace
66        "notify: Notification -> None",
67        // whitespace variants
68        "notify:Notification->None",
69        "notify :Notification->None",
70        "notify: Notification->None",
71        "notify:Notification ->None",
72        "notify:Notification-> None",
73    ];
74    for content in contents.iter() {
75        assert_parse(
76            parse_method(Span::new(content)),
77            Method {
78                name: "notify".to_string(),
79                input: Some(Type::Ref(TypeRef {
80                    abs: false,
81                    ns: vec![],
82                    name: "Notification".to_string(),
83                    generics: vec![],
84                })),
85                output: None,
86            },
87        )
88    }
89}
90
91#[test]
92fn test_parse_method_2() {
93    use crate::idl::r#type::TypeRef;
94    let contents = [
95        // normal whitespace
96        "get_time: None -> Time",
97        // whitespace variants
98        "get_time:None->Time",
99        "get_time :None->Time",
100        "get_time: None->Time",
101        "get_time:None ->Time",
102        "get_time:None-> Time",
103    ];
104    for content in contents.iter() {
105        assert_parse(
106            parse_method(Span::new(content)),
107            Method {
108                name: "get_time".to_string(),
109                input: None,
110                output: Some(Type::Ref(TypeRef {
111                    abs: false,
112                    ns: vec![],
113                    name: "Time".to_string(),
114                    generics: vec![],
115                })),
116            },
117        )
118    }
119}
120
121#[test]
122fn test_parse_method_3() {
123    use crate::idl::r#type::TypeRef;
124    let contents = [
125        // normal whitespace
126        "no_response: None -> Result<None, SomeError>",
127        // whitespace variants
128        "no_response:None->Result<None,SomeError>",
129        "no_response :None->Result<None,SomeError>",
130        "no_response: None->Result<None,SomeError>",
131        "no_response:None ->Result<None,SomeError>",
132        "no_response:None-> Result<None,SomeError>",
133        "no_response:None->Result <None,SomeError>",
134        "no_response:None->Result< None,SomeError>",
135        "no_response:None->Result<None ,SomeError>",
136        "no_response:None->Result<None, SomeError>",
137        "no_response:None->Result<None,SomeError >",
138    ];
139    for content in contents.iter() {
140        assert_parse(
141            parse_method(Span::new(content)),
142            Method {
143                name: "no_response".to_string(),
144                input: None,
145                output: Some(Type::Ref(TypeRef {
146                    abs: false,
147                    ns: vec![],
148                    name: "Result".to_string(),
149                    generics: vec![
150                        Type::Ref(TypeRef {
151                            abs: false,
152                            ns: vec![],
153                            name: "None".to_string(),
154                            generics: vec![],
155                        }),
156                        Type::Ref(TypeRef {
157                            abs: false,
158                            ns: vec![],
159                            name: "SomeError".to_string(),
160                            generics: vec![],
161                        }),
162                    ],
163                })),
164            },
165        )
166    }
167}
168
169#[test]
170fn test_parse_method_4() {
171    use crate::idl::r#type::TypeRef;
172    let contents = [
173        // normal whitespace
174        "hello: HelloRequest -> Result<HelloResponse, HelloError>",
175        // whitespace variants
176        "hello:HelloRequest->Result<HelloResponse,HelloError>",
177        "hello :HelloRequest->Result<HelloResponse,HelloError>",
178        "hello: HelloRequest->Result<HelloResponse,HelloError>",
179        "hello:HelloRequest ->Result<HelloResponse,HelloError>",
180        "hello:HelloRequest-> Result<HelloResponse,HelloError>",
181        "hello:HelloRequest->Result <HelloResponse,HelloError>",
182        "hello:HelloRequest->Result< HelloResponse,HelloError>",
183        "hello:HelloRequest->Result<HelloResponse ,HelloError>",
184        "hello:HelloRequest->Result<HelloResponse, HelloError>",
185        "hello:HelloRequest->Result<HelloResponse,HelloError >",
186    ];
187    for content in contents.iter() {
188        assert_parse(
189            parse_method(Span::new(content)),
190            Method {
191                name: "hello".to_string(),
192                input: Some(Type::Ref(TypeRef {
193                    abs: false,
194                    ns: vec![],
195                    name: "HelloRequest".to_string(),
196                    generics: vec![],
197                })),
198                output: Some(Type::Ref(TypeRef {
199                    abs: false,
200                    ns: vec![],
201                    name: "Result".to_string(),
202                    generics: vec![
203                        Type::Ref(TypeRef {
204                            abs: false,
205                            ns: vec![],
206                            name: "HelloResponse".to_string(),
207                            generics: vec![],
208                        }),
209                        Type::Ref(TypeRef {
210                            abs: false,
211                            ns: vec![],
212                            name: "HelloError".to_string(),
213                            generics: vec![],
214                        }),
215                    ],
216                })),
217            },
218        )
219    }
220}