libgir/codegen/
translate_from_glib.rs

1use crate::{
2    analysis::{
3        self, conversion_type::ConversionType, rust_type::RustType, try_from_glib::TryFromGlib,
4    },
5    chunk::conversion_from_glib::Mode,
6    env::Env,
7    library,
8    nameutil::use_glib_type,
9    traits::*,
10};
11
12pub trait TranslateFromGlib {
13    fn translate_from_glib_as_function(
14        &self,
15        env: &Env,
16        array_length: Option<&str>,
17    ) -> (String, String);
18}
19
20impl TranslateFromGlib for Mode {
21    fn translate_from_glib_as_function(
22        &self,
23        env: &Env,
24        array_length: Option<&str>,
25    ) -> (String, String) {
26        use crate::analysis::conversion_type::ConversionType::*;
27        match ConversionType::of(env, self.typ) {
28            Direct => (String::new(), String::new()),
29            Scalar => match env.library.type_(self.typ) {
30                library::Type::Basic(library::Basic::UniChar) => (
31                    "std::convert::TryFrom::try_from(".into(),
32                    ").expect(\"conversion from an invalid Unicode value attempted\")".into(),
33                ),
34                _ => ("from_glib(".into(), ")".into()),
35            },
36            Option => {
37                let (pre, post) = match &self.try_from_glib {
38                    TryFromGlib::Option => ("from_glib(", ")"),
39                    TryFromGlib::OptionMandatory => (
40                        "try_from_glib(",
41                        ").expect(\"mandatory glib value is None\")",
42                    ),
43                    other => panic!("Unexpected {other:?} for ConversionType::Option"),
44                };
45                (pre.to_string(), post.to_string())
46            }
47            Result { .. } => {
48                let (pre, post) = match &self.try_from_glib {
49                    TryFromGlib::Result { .. } => ("try_from_glib(", ")"),
50                    TryFromGlib::ResultInfallible { .. } => (
51                        "try_from_glib(",
52                        ").unwrap_or_else(|err| panic!(\"infallible {}\", err))",
53                    ),
54                    other => panic!("Unexpected {other:?} for ConversionType::Result"),
55                };
56                (pre.to_string(), post.to_string())
57            }
58            Pointer => {
59                let trans = from_glib_xxx(self.transfer, array_length);
60                match env.type_(self.typ) {
61                    library::Type::List(..)
62                    | library::Type::SList(..)
63                    | library::Type::PtrArray(..)
64                    | library::Type::CArray(..) => {
65                        if array_length.is_some() {
66                            (format!("FromGlibContainer::{}", trans.0), trans.1)
67                        } else {
68                            (format!("FromGlibPtrContainer::{}", trans.0), trans.1)
69                        }
70                    }
71                    _ => trans,
72                }
73            }
74            Borrow => ("/*TODO: conversion Borrow*/".into(), String::new()),
75            Unknown => ("/*Unknown conversion*/".into(), String::new()),
76        }
77    }
78}
79
80impl TranslateFromGlib for analysis::return_value::Info {
81    fn translate_from_glib_as_function(
82        &self,
83        env: &Env,
84        array_length: Option<&str>,
85    ) -> (String, String) {
86        match self.parameter {
87            Some(ref par) => match self.base_tid {
88                Some(tid) => {
89                    let rust_type = RustType::builder(env, tid)
90                        .direction(par.lib_par.direction)
91                        .try_from_glib(&par.try_from_glib)
92                        .try_build();
93                    let from_glib_xxx = from_glib_xxx(par.lib_par.transfer, None);
94
95                    let prefix = if *par.lib_par.nullable {
96                        format!("Option::<{}>::{}", rust_type.into_string(), from_glib_xxx.0)
97                    } else {
98                        format!("{}::{}", rust_type.into_string(), from_glib_xxx.0)
99                    };
100                    let suffix_function = if *par.lib_par.nullable {
101                        "map(|o| o.unsafe_cast())"
102                    } else {
103                        "unsafe_cast()"
104                    };
105
106                    if let Some(ref msg) = self.nullable_return_is_error {
107                        assert!(*par.lib_par.nullable);
108                        (
109                            prefix,
110                            format!(
111                                "{}.{}.ok_or_else(|| {}(\"{}\"))",
112                                from_glib_xxx.1,
113                                suffix_function,
114                                use_glib_type(env, "bool_error!"),
115                                msg
116                            ),
117                        )
118                    } else {
119                        (prefix, format!("{}.{}", from_glib_xxx.1, suffix_function))
120                    }
121                }
122                None if self.bool_return_is_error.is_some() => (
123                    use_glib_type(env, "result_from_gboolean!("),
124                    format!(", \"{}\")", self.bool_return_is_error.as_ref().unwrap()),
125                ),
126                None if self.nullable_return_is_error.is_some() => {
127                    let res = Mode::from(par).translate_from_glib_as_function(env, array_length);
128                    if let Some(ref msg) = self.nullable_return_is_error {
129                        assert!(*par.lib_par.nullable);
130                        (
131                            format!("Option::<_>::{}", res.0),
132                            format!(
133                                "{}.ok_or_else(|| {}(\"{}\"))",
134                                res.1,
135                                use_glib_type(env, "bool_error!"),
136                                msg
137                            ),
138                        )
139                    } else {
140                        res
141                    }
142                }
143                None => Mode::from(par).translate_from_glib_as_function(env, array_length),
144            },
145            None => (String::new(), ";".into()),
146        }
147    }
148}
149
150fn from_glib_xxx(transfer: library::Transfer, array_length: Option<&str>) -> (String, String) {
151    use crate::library::Transfer;
152    let good_print = |name: &str| format!(", {name}.assume_init() as _)");
153    match (transfer, array_length) {
154        (Transfer::None, None) => ("from_glib_none(".into(), ")".into()),
155        (Transfer::Full, None) => ("from_glib_full(".into(), ")".into()),
156        (Transfer::Container, None) => ("from_glib_container(".into(), ")".into()),
157        (Transfer::None, Some(array_length_name)) => {
158            ("from_glib_none_num(".into(), good_print(array_length_name))
159        }
160        (Transfer::Full, Some(array_length_name)) => {
161            ("from_glib_full_num(".into(), good_print(array_length_name))
162        }
163        (Transfer::Container, Some(array_length_name)) => (
164            "from_glib_container_num(".into(),
165            good_print(array_length_name),
166        ),
167    }
168}