grammers_tl_parser/tl/
parameter.rs1use std::fmt;
10use std::str::FromStr;
11
12use crate::errors::ParamParseError;
13use crate::tl::ParameterType;
14
15#[derive(Debug, PartialEq, Eq, Hash)]
17pub struct Parameter {
18 pub name: String,
20
21 pub ty: ParameterType,
23}
24
25impl fmt::Display for Parameter {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 write!(f, "{}:{}", self.name, self.ty)
28 }
29}
30
31impl FromStr for Parameter {
32 type Err = ParamParseError;
33
34 fn from_str(param: &str) -> Result<Self, Self::Err> {
44 if let Some(def) = param.strip_prefix('{') {
46 return Err(if let Some(def) = def.strip_suffix(":Type}") {
47 ParamParseError::TypeDef { name: def.into() }
48 } else {
49 ParamParseError::MissingDef
50 });
51 };
52
53 let (name, ty) = match param.split_once(':') {
55 Some((name, ty)) => (name, ty),
56 None => return Err(ParamParseError::NotImplemented),
57 };
58 if name.is_empty() || ty.is_empty() {
59 return Err(ParamParseError::Empty);
60 }
61
62 Ok(Parameter {
63 name: name.into(),
64 ty: ty.parse()?,
65 })
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use crate::tl::{Flag, Type};
73
74 #[test]
75 fn parse_empty_param() {
76 for param_str in [":noname", "notype:", ":"] {
77 assert_eq!(
78 Parameter::from_str(param_str),
79 Err(ParamParseError::Empty),
80 "Parameter::from_str({param_str:?})"
81 );
82 }
83 }
84
85 #[test]
86 fn parse_unknown_param() {
87 for param_str in ["", "no colon", "colonless"] {
88 assert_eq!(
89 Parameter::from_str(param_str),
90 Err(ParamParseError::NotImplemented),
91 "Parameter::from_str({param_str:?})"
92 );
93 }
94 }
95
96 #[test]
97 fn parse_bad_flags() {
98 for param_str in ["foo:bar?", "foo:?bar?", "foo:bar?baz", "foo:bar.baz?qux"] {
99 assert_eq!(
100 Parameter::from_str(param_str),
101 Err(ParamParseError::InvalidFlag),
102 "Parameter::from_str({param_str:?})"
103 );
104 }
105 }
106
107 #[test]
108 fn parse_bad_generics() {
109 assert_eq!(
110 Parameter::from_str("foo:<bar"),
111 Err(ParamParseError::InvalidGeneric)
112 );
113 assert_eq!(
114 Parameter::from_str("foo:bar<"),
115 Err(ParamParseError::InvalidGeneric)
116 );
117 }
118
119 #[test]
120 fn parse_type_def_param() {
121 assert_eq!(
122 Parameter::from_str("{a:Type}"),
123 Err(ParamParseError::TypeDef { name: "a".into() })
124 );
125 }
126
127 #[test]
128 fn parse_unknown_def_param() {
129 assert_eq!(
130 Parameter::from_str("{a:foo}"),
131 Err(ParamParseError::MissingDef)
132 );
133 }
134
135 #[test]
136 fn parse_valid_param() {
137 assert_eq!(
138 Parameter::from_str("foo:#"),
139 Ok(Parameter {
140 name: "foo".into(),
141 ty: ParameterType::Flags
142 })
143 );
144 assert_eq!(
145 Parameter::from_str("foo:!bar"),
146 Ok(Parameter {
147 name: "foo".into(),
148 ty: ParameterType::Normal {
149 ty: Type {
150 namespace: vec![],
151 name: "bar".into(),
152 bare: true,
153 generic_ref: true,
154 generic_arg: None,
155 },
156 flag: None,
157 }
158 })
159 );
160 assert_eq!(
161 Parameter::from_str("foo:bar.1?baz"),
162 Ok(Parameter {
163 name: "foo".into(),
164 ty: ParameterType::Normal {
165 ty: Type {
166 namespace: vec![],
167 name: "baz".into(),
168 bare: true,
169 generic_ref: false,
170 generic_arg: None,
171 },
172 flag: Some(Flag {
173 name: "bar".into(),
174 index: 1,
175 }),
176 }
177 })
178 );
179 assert_eq!(
180 Parameter::from_str("foo:bar<baz>"),
181 Ok(Parameter {
182 name: "foo".into(),
183 ty: ParameterType::Normal {
184 ty: Type {
185 namespace: vec![],
186 name: "bar".into(),
187 bare: true,
188 generic_ref: false,
189 generic_arg: Some(Box::new("baz".parse().unwrap())),
190 },
191 flag: None,
192 }
193 })
194 );
195 assert_eq!(
196 Parameter::from_str("foo:bar.1?baz<qux>"),
197 Ok(Parameter {
198 name: "foo".into(),
199 ty: ParameterType::Normal {
200 ty: Type {
201 namespace: vec![],
202 name: "baz".into(),
203 bare: true,
204 generic_ref: false,
205 generic_arg: Some(Box::new("qux".parse().unwrap())),
206 },
207 flag: Some(Flag {
208 name: "bar".into(),
209 index: 1,
210 }),
211 }
212 })
213 );
214 }
215}