libgir/config/
functions.rs

1use std::{collections::HashSet, str::FromStr};
2
3use log::error;
4use toml::Value;
5
6use super::{
7    error::TomlHelper,
8    gobjects::GStatus,
9    ident::Ident,
10    parameter_matchable::Functionlike,
11    parsable::{Parsable, Parse},
12    string_type::StringType,
13};
14use crate::{
15    analysis::safety_assertion_mode::SafetyAssertionMode,
16    codegen::Visibility,
17    library::{Infallible, Mandatory, Nullable},
18    version::Version,
19};
20
21#[derive(Clone, Debug)]
22pub struct CallbackParameter {
23    pub ident: Ident,
24    pub nullable: Option<Nullable>,
25}
26
27pub type CallbackParameters = Vec<CallbackParameter>;
28
29impl Parse for CallbackParameter {
30    fn parse(toml: &Value, object_name: &str) -> Option<Self> {
31        let Some(ident) = Ident::parse(toml, object_name, "callback parameter") else {
32            error!(
33                "No 'name' or 'pattern' given for parameter for object {}",
34                object_name
35            );
36            return None;
37        };
38        toml.check_unwanted(&["nullable"], &format!("callback parameter {object_name}"));
39
40        let nullable = toml
41            .lookup("nullable")
42            .and_then(Value::as_bool)
43            .map(Nullable);
44
45        Some(Self { ident, nullable })
46    }
47}
48
49impl AsRef<Ident> for CallbackParameter {
50    fn as_ref(&self) -> &Ident {
51        &self.ident
52    }
53}
54
55#[derive(Clone, Debug)]
56pub struct Parameter {
57    pub ident: Ident,
58    // true - parameter don't changed in FFI function,
59    // false(default) - parameter can be changed in FFI function
60    pub constant: bool,
61    pub move_: Option<bool>,
62    pub nullable: Option<Nullable>,
63    pub mandatory: Option<Mandatory>,
64    pub infallible: Option<Infallible>,
65    pub length_of: Option<String>,
66    pub string_type: Option<StringType>,
67    pub callback_parameters: CallbackParameters,
68}
69
70impl Parse for Parameter {
71    fn parse(toml: &Value, object_name: &str) -> Option<Self> {
72        let Some(ident) = Ident::parse(toml, object_name, "function parameter") else {
73            error!(
74                "No 'name' or 'pattern' given for parameter for object {}",
75                object_name
76            );
77            return None;
78        };
79        toml.check_unwanted(
80            &[
81                "const",
82                "nullable",
83                "mandatory",
84                "infallible",
85                "length_of",
86                "name",
87                "move",
88                "pattern",
89                "string_type",
90                "callback_parameter",
91            ],
92            &format!("function parameter {object_name}"),
93        );
94
95        let constant = toml
96            .lookup("const")
97            .and_then(Value::as_bool)
98            .unwrap_or(false);
99        let move_ = toml.lookup("move").and_then(Value::as_bool);
100        let nullable = toml
101            .lookup("nullable")
102            .and_then(Value::as_bool)
103            .map(Nullable);
104        let mandatory = toml
105            .lookup("mandatory")
106            .and_then(Value::as_bool)
107            .map(Mandatory);
108        let infallible = toml
109            .lookup("infallible")
110            .and_then(Value::as_bool)
111            .map(Infallible);
112        let length_of = toml
113            .lookup("length_of")
114            .and_then(Value::as_str)
115            .map(|s| if s == "return" { "" } else { s })
116            .map(ToOwned::to_owned);
117        let string_type = toml.lookup("string_type").and_then(Value::as_str);
118        let string_type = match string_type {
119            None => None,
120            Some(val) => match StringType::from_str(val) {
121                Ok(val) => Some(val),
122                Err(error_str) => {
123                    error!(
124                        "Error: {} for parameter for object {}",
125                        error_str, object_name
126                    );
127                    None
128                }
129            },
130        };
131        let callback_parameters =
132            CallbackParameters::parse(toml.lookup("callback_parameter"), object_name);
133
134        Some(Self {
135            ident,
136            constant,
137            move_,
138            nullable,
139            mandatory,
140            infallible,
141            length_of,
142            string_type,
143            callback_parameters,
144        })
145    }
146}
147
148impl AsRef<Ident> for Parameter {
149    fn as_ref(&self) -> &Ident {
150        &self.ident
151    }
152}
153
154pub type Parameters = Vec<Parameter>;
155
156#[derive(Clone, Debug)]
157pub struct Return {
158    pub nullable: Option<Nullable>,
159    pub mandatory: Option<Mandatory>,
160    pub infallible: Option<Infallible>,
161    pub bool_return_is_error: Option<String>,
162    pub nullable_return_is_error: Option<String>,
163    pub use_return_for_result: Option<bool>,
164    pub string_type: Option<StringType>,
165    pub type_name: Option<String>,
166}
167
168impl Return {
169    pub fn parse(toml: Option<&Value>, object_name: &str) -> Self {
170        if toml.is_none() {
171            return Self {
172                nullable: None,
173                mandatory: None,
174                infallible: None,
175                bool_return_is_error: None,
176                nullable_return_is_error: None,
177                use_return_for_result: None,
178                string_type: None,
179                type_name: None,
180            };
181        }
182
183        let v = toml.unwrap();
184        v.check_unwanted(
185            &[
186                "nullable",
187                "mandatory",
188                "infallible",
189                "bool_return_is_error",
190                "nullable_return_is_error",
191                "use_return_for_result",
192                "string_type",
193                "type",
194            ],
195            "return",
196        );
197
198        let nullable = v.lookup("nullable").and_then(Value::as_bool).map(Nullable);
199        let mandatory = v
200            .lookup("mandatory")
201            .and_then(Value::as_bool)
202            .map(Mandatory);
203        let infallible = v
204            .lookup("infallible")
205            .and_then(Value::as_bool)
206            .map(Infallible);
207        let bool_return_is_error = v
208            .lookup("bool_return_is_error")
209            .and_then(Value::as_str)
210            .map(ToOwned::to_owned);
211        let nullable_return_is_error = v
212            .lookup("nullable_return_is_error")
213            .and_then(Value::as_str)
214            .map(ToOwned::to_owned);
215        let use_return_for_result = v.lookup("use_return_for_result").and_then(Value::as_bool);
216        let string_type = v.lookup("string_type").and_then(Value::as_str);
217        let string_type = match string_type {
218            None => None,
219            Some(v) => match StringType::from_str(v) {
220                Ok(v) => Some(v),
221                Err(error_str) => {
222                    error!("Error: {} for return", error_str);
223                    None
224                }
225            },
226        };
227        let type_name = v
228            .lookup("type")
229            .and_then(Value::as_str)
230            .map(ToOwned::to_owned);
231        if string_type.is_some() && type_name.is_some() {
232            error!(
233                "\"string_type\" and \"type\" parameters can't be passed at the same time for \
234                 object {}, only \"type\" will be applied in this case",
235                object_name
236            );
237        }
238
239        Self {
240            nullable,
241            mandatory,
242            infallible,
243            bool_return_is_error,
244            nullable_return_is_error,
245            use_return_for_result,
246            string_type,
247            type_name,
248        }
249    }
250}
251
252pub fn check_rename(rename: &Option<String>, object_name: &str, function_name: &Ident) -> bool {
253    if let Some(rename) = rename {
254        for c in &["\t", "\n", " "] {
255            if rename.contains(c) {
256                error!(
257                    "Invalid 'rename' value given to {}::{}: forbidden character '{:?}'",
258                    object_name, function_name, c
259                );
260                return false;
261            }
262        }
263    }
264    true
265}
266
267#[derive(Clone, Debug)]
268pub struct Function {
269    pub ident: Ident,
270    pub status: GStatus,
271    pub version: Option<Version>,
272    pub cfg_condition: Option<String>,
273    pub parameters: Parameters,
274    pub ret: Return,
275    pub doc_hidden: bool,
276    pub doc_ignore_parameters: HashSet<String>,
277    pub disable_length_detect: bool,
278    pub doc_trait_name: Option<String>,
279    pub doc_struct_name: Option<String>,
280    pub no_future: bool,
281    pub unsafe_: bool,
282    pub rename: Option<String>,
283    pub visibility: Option<Visibility>,
284    pub bypass_auto_rename: bool,
285    pub is_constructor: Option<bool>,
286    pub assertion: Option<SafetyAssertionMode>,
287    pub generate_doc: bool,
288}
289
290impl Parse for Function {
291    fn parse(toml: &Value, object_name: &str) -> Option<Self> {
292        let Some(ident) = Ident::parse(toml, object_name, "function") else {
293            error!(
294                "No 'name' or 'pattern' given for function for object {}",
295                object_name
296            );
297            return None;
298        };
299        toml.check_unwanted(
300            &[
301                "ignore",
302                "manual",
303                "version",
304                "cfg_condition",
305                "parameter",
306                "return",
307                "name",
308                "doc_hidden",
309                "doc_ignore_parameters",
310                "disable_length_detect",
311                "pattern",
312                "doc_trait_name",
313                "doc_struct_name",
314                "no_future",
315                "unsafe",
316                "rename",
317                "bypass_auto_rename",
318                "constructor",
319                "assertion",
320                "visibility",
321                "generate_doc",
322            ],
323            &format!("function {object_name}"),
324        );
325
326        let status = {
327            if toml
328                .lookup("ignore")
329                .and_then(Value::as_bool)
330                .unwrap_or(false)
331            {
332                GStatus::Ignore
333            } else if toml
334                .lookup("manual")
335                .and_then(Value::as_bool)
336                .unwrap_or(false)
337            {
338                GStatus::Manual
339            } else {
340                GStatus::Generate
341            }
342        };
343        let version = toml
344            .lookup("version")
345            .and_then(Value::as_str)
346            .and_then(|s| s.parse().ok());
347        let cfg_condition = toml
348            .lookup("cfg_condition")
349            .and_then(Value::as_str)
350            .map(ToOwned::to_owned);
351        let parameters = Parameters::parse(toml.lookup("parameter"), object_name);
352        let ret = Return::parse(toml.lookup("return"), object_name);
353        let doc_hidden = toml
354            .lookup("doc_hidden")
355            .and_then(Value::as_bool)
356            .unwrap_or(false);
357        let doc_ignore_parameters = toml
358            .lookup_vec("doc_ignore_parameters", "Invalid doc_ignore_parameters")
359            .map(|v| {
360                v.iter()
361                    .filter_map(|v| v.as_str().map(String::from))
362                    .collect()
363            })
364            .unwrap_or_default();
365        let disable_length_detect = toml
366            .lookup("disable_length_detect")
367            .and_then(Value::as_bool)
368            .unwrap_or(false);
369        let doc_trait_name = toml
370            .lookup("doc_trait_name")
371            .and_then(Value::as_str)
372            .map(ToOwned::to_owned);
373        let doc_struct_name = toml
374            .lookup("doc_struct_name")
375            .and_then(Value::as_str)
376            .map(ToOwned::to_owned);
377        let no_future = toml
378            .lookup("no_future")
379            .and_then(Value::as_bool)
380            .unwrap_or(false);
381        let unsafe_ = toml
382            .lookup("unsafe")
383            .and_then(Value::as_bool)
384            .unwrap_or(false);
385        let rename = toml
386            .lookup("rename")
387            .and_then(Value::as_str)
388            .map(ToOwned::to_owned);
389        if !check_rename(&rename, object_name, &ident) {
390            return None;
391        }
392        let bypass_auto_rename = toml
393            .lookup("bypass_auto_rename")
394            .and_then(Value::as_bool)
395            .unwrap_or(false);
396        let is_constructor = toml.lookup("constructor").and_then(Value::as_bool);
397        let assertion = toml
398            .lookup("assertion")
399            .and_then(Value::as_str)
400            .map(|s| s.parse::<SafetyAssertionMode>())
401            .transpose();
402        if let Err(ref err) = assertion {
403            error!("{}", err);
404        }
405        let assertion = assertion.ok().flatten();
406        let visibility = toml
407            .lookup("visibility")
408            .and_then(Value::as_str)
409            .map(std::str::FromStr::from_str)
410            .transpose();
411        if let Err(ref err) = visibility {
412            error!("{}", err);
413        }
414        let visibility = visibility.ok().flatten();
415        let generate_doc = toml
416            .lookup("generate_doc")
417            .and_then(Value::as_bool)
418            .unwrap_or(true);
419        Some(Self {
420            ident,
421            status,
422            version,
423            cfg_condition,
424            parameters,
425            ret,
426            doc_hidden,
427            doc_ignore_parameters,
428            disable_length_detect,
429            doc_trait_name,
430            doc_struct_name,
431            no_future,
432            unsafe_,
433            rename,
434            visibility,
435            bypass_auto_rename,
436            is_constructor,
437            assertion,
438            generate_doc,
439        })
440    }
441}
442
443impl Functionlike for Function {
444    type Parameter = self::Parameter;
445
446    fn parameters(&self) -> &[Self::Parameter] {
447        &self.parameters
448    }
449}
450
451impl AsRef<Ident> for Function {
452    fn as_ref(&self) -> &Ident {
453        &self.ident
454    }
455}
456
457pub type Functions = Vec<Function>;
458
459#[cfg(test)]
460mod tests {
461    use super::{
462        super::{
463            ident::Ident,
464            matchable::Matchable,
465            parameter_matchable::ParameterMatchable,
466            parsable::{Parsable, Parse},
467        },
468        *,
469    };
470    use crate::{library::Nullable, version::Version};
471
472    fn functions_toml(input: &str) -> ::toml::Value {
473        let mut value: ::toml::value::Table = ::toml::from_str(input).unwrap();
474        value.remove("f").unwrap()
475    }
476
477    fn toml(input: &str) -> ::toml::Value {
478        let value = ::toml::from_str(input);
479        assert!(value.is_ok());
480        value.unwrap()
481    }
482
483    #[test]
484    fn function_parse_ignore() {
485        let toml = toml(
486            r#"
487name = "func1"
488ignore = true
489"#,
490        );
491        let f = Function::parse(&toml, "a").unwrap();
492        assert_eq!(f.ident, Ident::Name("func1".into()));
493        assert!(f.status.ignored());
494    }
495
496    #[test]
497    fn function_parse_manual() {
498        let toml = toml(
499            r#"
500name = "func1"
501manual = true
502"#,
503        );
504        let f = Function::parse(&toml, "a").unwrap();
505        assert_eq!(f.ident, Ident::Name("func1".into()));
506        assert!(f.status.manual());
507    }
508
509    #[test]
510    fn function_parse_version_default() {
511        let toml = toml(
512            r#"
513name = "func1"
514"#,
515        );
516        let f = Function::parse(&toml, "a").unwrap();
517        assert_eq!(f.version, None);
518        assert!(f.status.need_generate());
519    }
520
521    #[test]
522    fn function_parse_version() {
523        let toml = toml(
524            r#"
525name = "func1"
526version = "3.20"
527"#,
528        );
529        let f = Function::parse(&toml, "a").unwrap();
530        assert_eq!(f.version, Some(Version::new(3, 20, 0)));
531    }
532
533    #[test]
534    fn function_parse_cfg_condition_default() {
535        let toml = toml(
536            r#"
537name = "func1"
538"#,
539        );
540        let f = Function::parse(&toml, "a").unwrap();
541        assert_eq!(f.cfg_condition, None);
542    }
543
544    #[test]
545    fn function_parse_cfg_condition() {
546        let toml = toml(
547            r#"
548name = "func1"
549cfg_condition = 'unix'
550"#,
551        );
552        let f = Function::parse(&toml, "a").unwrap();
553        assert_eq!(f.cfg_condition, Some("unix".to_string()));
554    }
555
556    #[test]
557    fn function_parse_return_nullable_default1() {
558        let toml = toml(
559            r#"
560name = "func1"
561"#,
562        );
563        let f = Function::parse(&toml, "a").unwrap();
564        assert_eq!(f.ret.nullable, None);
565    }
566
567    #[test]
568    fn function_parse_return_nullable_default2() {
569        let toml = toml(
570            r#"
571name = "func1"
572[return]
573"#,
574        );
575        let f = Function::parse(&toml, "a").unwrap();
576        assert_eq!(f.ret.nullable, None);
577    }
578
579    #[test]
580    fn function_parse_parameters() {
581        let toml = toml(
582            r#"
583name = "func1"
584[[parameter]]
585name = "par1"
586[[parameter]]
587name = "par2"
588const = false
589nullable = false
590[[parameter]]
591name = "par3"
592const = true
593nullable = true
594[[parameter]]
595pattern = "par4"
596const = true
597"#,
598        );
599        let f = Function::parse(&toml, "a").unwrap();
600        let pars = f.parameters;
601        assert_eq!(pars.len(), 4);
602        assert_eq!(pars[0].ident, Ident::Name("par1".into()));
603        assert!(!pars[0].constant);
604        assert_eq!(pars[0].nullable, None);
605        assert_eq!(pars[1].ident, Ident::Name("par2".into()));
606        assert!(!pars[1].constant);
607        assert_eq!(pars[1].nullable, Some(Nullable(false)));
608        assert_eq!(pars[2].ident, Ident::Name("par3".into()));
609        assert!(pars[2].constant);
610        assert_eq!(pars[2].nullable, Some(Nullable(true)));
611        assert!(matches!(pars[3].ident, Ident::Pattern(_)));
612        assert!(pars[3].constant);
613        assert_eq!(pars[3].nullable, None);
614    }
615
616    #[test]
617    fn function_parse_return_nullable_false() {
618        let toml = toml(
619            r#"
620name = "func1"
621[return]
622nullable = false
623"#,
624        );
625        let f = Function::parse(&toml, "a").unwrap();
626        assert_eq!(f.ret.nullable, Some(Nullable(false)));
627    }
628
629    #[test]
630    fn function_parse_return_nullable_true() {
631        let toml = toml(
632            r#"
633name = "func1"
634[return]
635nullable = true
636"#,
637        );
638        let f = Function::parse(&toml, "a").unwrap();
639        assert_eq!(f.ret.nullable, Some(Nullable(true)));
640    }
641
642    #[test]
643    fn function_parse_generate_doc() {
644        let r = toml(
645            r#"
646name = "prop"
647generate_doc = false
648"#,
649        );
650        let f = Function::parse(&r, "a").unwrap();
651        assert!(!f.generate_doc);
652
653        // Ensure that the default value is "true".
654        let r = toml(
655            r#"
656name = "prop"
657"#,
658        );
659        let f = Function::parse(&r, "a").unwrap();
660        assert!(f.generate_doc);
661    }
662
663    #[test]
664    fn functions_parse_empty_for_none() {
665        let fns = Functions::parse(None, "a");
666        assert!(fns.is_empty());
667    }
668
669    #[test]
670    fn functions_parse_ident() {
671        let toml = functions_toml(
672            r#"
673[[f]]
674name = "func1"
675[[f]]
676not_name = "func1.5"
677[[f]]
678name = "func2"
679[[f]]
680pattern = 'func3\w+'
681[[f]]
682pattern = 'bad_func4[\w+'
683"#,
684        );
685        let fns = Functions::parse(Some(&toml), "a");
686        assert_eq!(fns.len(), 3);
687        assert_eq!(fns[0].ident, Ident::Name("func1".into()));
688        assert_eq!(fns[1].ident, Ident::Name("func2".into()));
689        assert!(matches!(fns[2].ident, Ident::Pattern(_)));
690    }
691
692    #[test]
693    fn functions_parse_matches() {
694        let toml = functions_toml(
695            r#"
696[[f]]
697name = "func1"
698[[f]]
699name = "f1.5"
700[[f]]
701name = "func2"
702[[f]]
703pattern = 'func\d+'
704"#,
705        );
706        let fns = Functions::parse(Some(&toml), "a");
707        assert_eq!(fns.len(), 3);
708
709        assert_eq!(fns.matched("func1").len(), 2);
710        assert_eq!(fns.matched("func2").len(), 2);
711        assert_eq!(fns.matched("func3").len(), 1);
712        // "f1.5" is not a valid name
713        assert_eq!(fns.matched("f1.5").len(), 0);
714        assert_eq!(fns.matched("none").len(), 0);
715    }
716
717    #[test]
718    fn functions_parse_matched_parameters() {
719        let toml = functions_toml(
720            r#"
721[[f]]
722name = "func"
723[[f.parameter]]
724name="par1"
725[[f.parameter]]
726name="par2"
727[[f.parameter]]
728pattern='par\d+'
729[[f]]
730name = "func"
731[[f.parameter]]
732name="par2"
733[[f.parameter]]
734name="par3"
735[[f.parameter]]
736pattern='par\d+'
737"#,
738        );
739        let fns = Functions::parse(Some(&toml), "a");
740        assert_eq!(fns.len(), 2);
741        let m = fns.matched("func");
742        assert_eq!(m.len(), 2);
743
744        assert_eq!(m.matched_parameters("param").len(), 0);
745        assert_eq!(m.matched_parameters("par1").len(), 3);
746        assert_eq!(m.matched_parameters("par2").len(), 4);
747        assert_eq!(m.matched_parameters("par3").len(), 3);
748        assert_eq!(m.matched_parameters("par4").len(), 2);
749    }
750
751    #[test]
752    fn functions_parse_rename() {
753        let toml = toml(
754            r#"
755name = "func1"
756rename = "another"
757"#,
758        );
759        let f = Function::parse(&toml, "a").unwrap();
760        assert_eq!(f.rename, Some("another".to_owned()));
761    }
762
763    #[test]
764    fn functions_parse_rename_fail() {
765        let toml = toml(
766            r#"
767name = "func1"
768rename = "anoth er"
769"#,
770        );
771        let f = Function::parse(&toml, "a");
772        assert!(f.is_none());
773    }
774
775    #[test]
776    fn function_bypass_auto_rename() {
777        let toml = toml(
778            r#"
779name = "func1"
780bypass_auto_rename = true
781"#,
782        );
783        let f = Function::parse(&toml, "a").unwrap();
784        assert_eq!(f.ident, Ident::Name("func1".into()));
785        assert!(f.bypass_auto_rename);
786    }
787
788    #[test]
789    fn parse_return_mandatory_default() {
790        let toml = toml(
791            r#"
792name = "func1"
793"#,
794        );
795        let f = Function::parse(&toml, "a");
796        let f = f.unwrap();
797        assert!(f.ret.mandatory.is_none());
798    }
799
800    #[test]
801    fn parse_return_mandatory() {
802        let toml = toml(
803            r#"
804name = "func1"
805    [return]
806    mandatory = true
807"#,
808        );
809        let f = Function::parse(&toml, "a");
810        let f = f.unwrap();
811        assert_eq!(f.ret.mandatory, Some(Mandatory(true)));
812    }
813
814    #[test]
815    fn parse_return_non_mandatory() {
816        let toml = toml(
817            r#"
818name = "func1"
819    [return]
820    mandatory = false
821"#,
822        );
823        let f = Function::parse(&toml, "a");
824        let f = f.unwrap();
825        assert_eq!(f.ret.mandatory, Some(Mandatory(false)));
826    }
827
828    #[test]
829    fn parse_parameter_mandatory_default() {
830        let toml = toml(
831            r#"
832name = "func1"
833    [[parameter]]
834    name = "param1"
835"#,
836        );
837        let f = Function::parse(&toml, "a");
838        let f = f.unwrap();
839        let param1 = &f.parameters[0];
840        assert!(param1.mandatory.is_none());
841    }
842
843    #[test]
844    fn parse_parameter_mandatory() {
845        let toml = toml(
846            r#"
847name = "func1"
848    [[parameter]]
849    name = "param1"
850    mandatory = true
851"#,
852        );
853        let f = Function::parse(&toml, "a");
854        let f = f.unwrap();
855        let param1 = &f.parameters[0];
856        assert_eq!(param1.mandatory, Some(Mandatory(true)));
857    }
858
859    #[test]
860    fn parse_parameter_non_mandatory() {
861        let toml = toml(
862            r#"
863name = "func1"
864    [[parameter]]
865    name = "param1"
866    mandatory = false
867"#,
868        );
869        let f = Function::parse(&toml, "a");
870        let f = f.unwrap();
871        let param1 = &f.parameters[0];
872        assert_eq!(param1.mandatory, Some(Mandatory(false)));
873    }
874
875    #[test]
876    fn parse_return_infallible_default() {
877        let toml = toml(
878            r#"
879name = "func1"
880"#,
881        );
882        let f = Function::parse(&toml, "a");
883        let f = f.unwrap();
884        assert!(f.ret.infallible.is_none());
885    }
886
887    #[test]
888    fn parse_return_infallible() {
889        let toml = toml(
890            r#"
891name = "func1"
892    [return]
893    infallible = true
894"#,
895        );
896        let f = Function::parse(&toml, "a");
897        let f = f.unwrap();
898        assert_eq!(f.ret.infallible, Some(Infallible(true)));
899    }
900
901    #[test]
902    fn parse_return_faillible() {
903        let toml = toml(
904            r#"
905name = "func1"
906    [return]
907    infallible = false
908"#,
909        );
910        let f = Function::parse(&toml, "a");
911        let f = f.unwrap();
912        assert_eq!(f.ret.infallible, Some(Infallible(false)));
913    }
914
915    #[test]
916    fn parse_parameter_infallible_default() {
917        let toml = toml(
918            r#"
919name = "func1"
920    [[parameter]]
921    name = "param1"
922"#,
923        );
924        let f = Function::parse(&toml, "a");
925        let f = f.unwrap();
926        let param1 = &f.parameters[0];
927        assert!(param1.infallible.is_none());
928    }
929
930    #[test]
931    fn parse_parameter_infallible() {
932        let toml = toml(
933            r#"
934name = "func1"
935    [[parameter]]
936    name = "param1"
937    infallible = true
938"#,
939        );
940        let f = Function::parse(&toml, "a");
941        let f = f.unwrap();
942        let param1 = &f.parameters[0];
943        assert_eq!(param1.infallible, Some(Infallible(true)));
944    }
945
946    #[test]
947    fn parse_parameter_faillible() {
948        let toml = toml(
949            r#"
950name = "func1"
951    [[parameter]]
952    name = "param1"
953    infallible = false
954"#,
955        );
956        let f = Function::parse(&toml, "a");
957        let f = f.unwrap();
958        let param1 = &f.parameters[0];
959        assert_eq!(param1.infallible, Some(Infallible(false)));
960    }
961}