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