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!(
51 "No 'name' or 'pattern' given for parameter for object {}",
52 object_name
53 );
54 return None;
55 };
56 toml.check_unwanted(
57 &["nullable", "transformation", "new_name", "name", "pattern"],
58 &format!("parameter {object_name}"),
59 );
60
61 let nullable = toml
62 .lookup("nullable")
63 .and_then(Value::as_bool)
64 .map(Nullable);
65 let transformation = toml
66 .lookup("transformation")
67 .and_then(Value::as_str)
68 .and_then(|s| {
69 TransformationType::from_str(s)
70 .map_err(|err| {
71 error!("{0}", err);
72 err
73 })
74 .ok()
75 });
76 let new_name = toml
77 .lookup("new_name")
78 .and_then(Value::as_str)
79 .map(ToOwned::to_owned);
80
81 Some(Self {
82 ident,
83 nullable,
84 transformation,
85 new_name,
86 })
87 }
88}
89
90impl AsRef<Ident> for Parameter {
91 fn as_ref(&self) -> &Ident {
92 &self.ident
93 }
94}
95
96pub type Parameters = Vec<Parameter>;
97
98#[derive(Clone, Debug)]
99pub struct Signal {
100 pub ident: Ident,
101 pub status: GStatus,
102 pub inhibit: bool,
103 pub version: Option<Version>,
104 pub parameters: Parameters,
105 pub ret: Return,
106 pub concurrency: library::Concurrency,
107 pub doc_hidden: bool,
108 pub doc_trait_name: Option<String>,
109 pub generate_doc: bool,
110}
111
112impl Signal {
113 pub fn parse(
114 toml: &Value,
115 object_name: &str,
116 concurrency: library::Concurrency,
117 ) -> Option<Self> {
118 let Some(ident) = Ident::parse(toml, object_name, "signal") else {
119 error!(
120 "No 'name' or 'pattern' given for signal for object {}",
121 object_name
122 );
123 return None;
124 };
125 toml.check_unwanted(
126 &[
127 "ignore",
128 "manual",
129 "inhibit",
130 "version",
131 "parameter",
132 "return",
133 "doc_hidden",
134 "name",
135 "pattern",
136 "concurrency",
137 "doc_trait_name",
138 "generate_doc",
139 ],
140 &format!("signal {object_name}"),
141 );
142
143 let status = {
144 if toml
145 .lookup("ignore")
146 .and_then(Value::as_bool)
147 .unwrap_or(false)
148 {
149 GStatus::Ignore
150 } else if toml
151 .lookup("manual")
152 .and_then(Value::as_bool)
153 .unwrap_or(false)
154 {
155 GStatus::Manual
156 } else {
157 GStatus::Generate
158 }
159 };
160
161 let inhibit = toml
162 .lookup("inhibit")
163 .and_then(Value::as_bool)
164 .unwrap_or(false);
165 let version = toml
166 .lookup("version")
167 .and_then(Value::as_str)
168 .and_then(|s| s.parse().ok());
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 })
203 }
204}
205
206impl Functionlike for Signal {
207 type Parameter = self::Parameter;
208
209 fn parameters(&self) -> &[Self::Parameter] {
210 &self.parameters
211 }
212}
213
214impl AsRef<Ident> for Signal {
215 fn as_ref(&self) -> &Ident {
216 &self.ident
217 }
218}
219
220pub type Signals = Vec<Signal>;
221
222#[cfg(test)]
223mod tests {
224 use super::{super::ident::Ident, *};
225
226 fn toml(input: &str) -> ::toml::Value {
227 let value = input.parse::<::toml::Value>();
228 assert!(value.is_ok());
229 value.unwrap()
230 }
231
232 #[test]
233 fn signal_parse_default() {
234 let toml = toml(
235 r#"
236name = "signal1"
237"#,
238 );
239 let f = Signal::parse(&toml, "a", Default::default()).unwrap();
240 assert_eq!(f.ident, Ident::Name("signal1".into()));
241 assert!(f.status.need_generate());
242 }
243
244 #[test]
245 fn signal_parse_ignore() {
246 let toml = toml(
247 r#"
248name = "signal1"
249ignore = true
250"#,
251 );
252 let f = Signal::parse(&toml, "a", Default::default()).unwrap();
253 assert!(f.status.ignored());
254 }
255
256 #[test]
257 fn signal_parse_manual() {
258 let toml = toml(
259 r#"
260name = "signal1"
261manual = true
262"#,
263 );
264 let f = Signal::parse(&toml, "a", Default::default()).unwrap();
265 assert!(f.status.manual());
266 }
267
268 #[test]
269 fn signal_parse_generate_doc() {
270 let r = toml(
271 r#"
272name = "signal1"
273generate_doc = false
274"#,
275 );
276 let f = Signal::parse(&r, "a", Default::default()).unwrap();
277 assert!(!f.generate_doc);
278
279 let r = toml(
281 r#"
282name = "prop"
283"#,
284 );
285 let f = Signal::parse(&r, "a", Default::default()).unwrap();
286 assert!(f.generate_doc);
287 }
288}