1use std::str::FromStr;
2
3use log::error;
4use toml::Value;
5
6use super::{
7 error::TomlHelper,
8 functions::Return,
9 gobjects::GStatus,
10 ident::Ident,
11 parameter_matchable::Functionlike,
12 parsable::{Parsable, Parse},
13};
14use crate::{
15 library::{self, Nullable},
16 version::Version,
17};
18
19#[derive(Clone, Copy, Debug)]
20pub enum TransformationType {
21 None,
22 Borrow, TreePath, }
26
27impl FromStr for TransformationType {
28 type Err = String;
29 fn from_str(s: &str) -> Result<Self, Self::Err> {
30 match s {
31 "none" => Ok(Self::None),
32 "borrow" => Ok(Self::Borrow),
33 "treepath" => Ok(Self::TreePath),
34 _ => Err(format!("Wrong transformation \"{s}\"")),
35 }
36 }
37}
38
39#[derive(Clone, Debug)]
40pub struct Parameter {
41 pub ident: Ident,
42 pub nullable: Option<Nullable>,
43 pub transformation: Option<TransformationType>,
44 pub new_name: Option<String>,
45}
46
47impl Parse for Parameter {
48 fn parse(toml: &Value, object_name: &str) -> Option<Self> {
49 let Some(ident) = Ident::parse(toml, object_name, "signal parameter") else {
50 error!("No 'name' or 'pattern' given for parameter for object {object_name}");
51 return None;
52 };
53 toml.check_unwanted(
54 &["nullable", "transformation", "new_name", "name", "pattern"],
55 &format!("parameter {object_name}"),
56 );
57
58 let nullable = toml
59 .lookup("nullable")
60 .and_then(Value::as_bool)
61 .map(Nullable);
62 let transformation = toml
63 .lookup("transformation")
64 .and_then(Value::as_str)
65 .and_then(|s| {
66 TransformationType::from_str(s)
67 .map_err(|err| {
68 error!("{err}");
69 err
70 })
71 .ok()
72 });
73 let new_name = toml
74 .lookup("new_name")
75 .and_then(Value::as_str)
76 .map(ToOwned::to_owned);
77
78 Some(Self {
79 ident,
80 nullable,
81 transformation,
82 new_name,
83 })
84 }
85}
86
87impl AsRef<Ident> for Parameter {
88 fn as_ref(&self) -> &Ident {
89 &self.ident
90 }
91}
92
93pub type Parameters = Vec<Parameter>;
94
95#[derive(Clone, Debug)]
96pub struct Signal {
97 pub ident: Ident,
98 pub status: GStatus,
99 pub inhibit: bool,
100 pub version: Option<Version>,
101 pub parameters: Parameters,
102 pub ret: Return,
103 pub concurrency: library::Concurrency,
104 pub doc_hidden: bool,
105 pub doc_trait_name: Option<String>,
106 pub generate_doc: bool,
107 pub cfg_condition: Option<String>,
108}
109
110impl Signal {
111 pub fn parse(
112 toml: &Value,
113 object_name: &str,
114 concurrency: library::Concurrency,
115 ) -> Option<Self> {
116 let Some(ident) = Ident::parse(toml, object_name, "signal") else {
117 error!("No 'name' or 'pattern' given for signal for object {object_name}");
118 return None;
119 };
120 toml.check_unwanted(
121 &[
122 "ignore",
123 "manual",
124 "inhibit",
125 "version",
126 "cfg_condition",
127 "parameter",
128 "return",
129 "doc_hidden",
130 "name",
131 "pattern",
132 "concurrency",
133 "doc_trait_name",
134 "generate_doc",
135 ],
136 &format!("signal {object_name}"),
137 );
138
139 let status = {
140 if toml
141 .lookup("ignore")
142 .and_then(Value::as_bool)
143 .unwrap_or(false)
144 {
145 GStatus::Ignore
146 } else if toml
147 .lookup("manual")
148 .and_then(Value::as_bool)
149 .unwrap_or(false)
150 {
151 GStatus::Manual
152 } else {
153 GStatus::Generate
154 }
155 };
156
157 let inhibit = toml
158 .lookup("inhibit")
159 .and_then(Value::as_bool)
160 .unwrap_or(false);
161 let version = toml
162 .lookup("version")
163 .and_then(Value::as_str)
164 .and_then(|s| s.parse().ok());
165 let cfg_condition = toml
166 .lookup("cfg_condition")
167 .and_then(Value::as_str)
168 .map(ToOwned::to_owned);
169 let parameters = Parameters::parse(toml.lookup("parameter"), object_name);
170 let ret = Return::parse(toml.lookup("return"), object_name);
171
172 let concurrency = toml
173 .lookup("concurrency")
174 .and_then(Value::as_str)
175 .and_then(|v| v.parse().ok())
176 .unwrap_or(concurrency);
177
178 let doc_hidden = toml
179 .lookup("doc_hidden")
180 .and_then(Value::as_bool)
181 .unwrap_or(false);
182 let doc_trait_name = toml
183 .lookup("doc_trait_name")
184 .and_then(Value::as_str)
185 .map(ToOwned::to_owned);
186 let generate_doc = toml
187 .lookup("generate_doc")
188 .and_then(Value::as_bool)
189 .unwrap_or(true);
190
191 Some(Self {
192 ident,
193 status,
194 inhibit,
195 version,
196 parameters,
197 ret,
198 concurrency,
199 doc_hidden,
200 doc_trait_name,
201 generate_doc,
202 cfg_condition,
203 })
204 }
205}
206
207impl Functionlike for Signal {
208 type Parameter = self::Parameter;
209
210 fn parameters(&self) -> &[Self::Parameter] {
211 &self.parameters
212 }
213}
214
215impl AsRef<Ident> for Signal {
216 fn as_ref(&self) -> &Ident {
217 &self.ident
218 }
219}
220
221pub type Signals = Vec<Signal>;
222
223#[cfg(test)]
224mod tests {
225 use super::{super::ident::Ident, *};
226
227 fn toml(input: &str) -> ::toml::Value {
228 let value = input.parse::<::toml::Value>();
229 assert!(value.is_ok());
230 value.unwrap()
231 }
232
233 #[test]
234 fn signal_parse_default() {
235 let toml = toml(
236 r#"
237name = "signal1"
238"#,
239 );
240 let f = Signal::parse(&toml, "a", Default::default()).unwrap();
241 assert_eq!(f.ident, Ident::Name("signal1".into()));
242 assert!(f.status.need_generate());
243 }
244
245 #[test]
246 fn signal_parse_ignore() {
247 let toml = toml(
248 r#"
249name = "signal1"
250ignore = true
251"#,
252 );
253 let f = Signal::parse(&toml, "a", Default::default()).unwrap();
254 assert!(f.status.ignored());
255 }
256
257 #[test]
258 fn signal_parse_manual() {
259 let toml = toml(
260 r#"
261name = "signal1"
262manual = true
263"#,
264 );
265 let f = Signal::parse(&toml, "a", Default::default()).unwrap();
266 assert!(f.status.manual());
267 }
268
269 #[test]
270 fn signal_parse_generate_doc() {
271 let r = toml(
272 r#"
273name = "signal1"
274generate_doc = false
275"#,
276 );
277 let f = Signal::parse(&r, "a", Default::default()).unwrap();
278 assert!(!f.generate_doc);
279
280 let r = toml(
282 r#"
283name = "prop"
284"#,
285 );
286 let f = Signal::parse(&r, "a", Default::default()).unwrap();
287 assert!(f.generate_doc);
288 }
289}