libgir/writer/
to_code.rs

1use std::fmt::Write;
2
3use super::primitives::*;
4use crate::{
5    chunk::{Chunk, Param, TupleMode},
6    codegen::{translate_from_glib::TranslateFromGlib, translate_to_glib::TranslateToGlib},
7    env::Env,
8    nameutil::use_glib_type,
9};
10
11pub trait ToCode {
12    fn to_code(&self, env: &Env) -> Vec<String>;
13}
14
15impl ToCode for Chunk {
16    fn to_code(&self, env: &Env) -> Vec<String> {
17        use crate::chunk::Chunk::*;
18        match *self {
19            Comment(ref chs) => comment_block(&chs.to_code(env)),
20            Chunks(ref chs) => chs.to_code(env),
21            BlockHalf(ref chs) => format_block("", "}", &chs.to_code(env)),
22            UnsafeSmart(ref chs) => {
23                format_block_smart("unsafe {", "}", &chs.to_code(env), " ", " ")
24            }
25            Unsafe(ref chs) => format_block("unsafe {", "}", &chs.to_code(env)),
26            FfiCallTODO(ref name) => vec![format!("TODO: call {name}()")],
27            FfiCall {
28                ref name,
29                ref params,
30                ref ignore_return,
31            } => {
32                let prefix = format!("{name}(");
33                // TODO: change to format_block or format_block_smart
34                let s = format_block_one_line(
35                    &prefix,
36                    if *ignore_return { ");" } else { ")" },
37                    &params.to_code(env),
38                    "",
39                    ", ",
40                );
41                vec![s]
42            }
43            FfiCallParameter {
44                ref transformation_type,
45            } => {
46                let s = transformation_type.translate_to_glib();
47                vec![s]
48            }
49            FfiCallOutParameter { ref par } => {
50                let s = if par.caller_allocates {
51                    format!("{}.to_glib_none_mut().0", par.name)
52                } else if par.is_uninitialized && !par.is_error {
53                    format!("{}.as_mut_ptr()", par.name)
54                } else {
55                    format!("&mut {}", par.name)
56                };
57                vec![s]
58            }
59            FfiCallConversion {
60                ref ret,
61                ref array_length_name,
62                ref call,
63            } => {
64                let call_strings = call.to_code(env);
65                let (prefix, suffix) =
66                    ret.translate_from_glib_as_function(env, array_length_name.as_deref());
67                let s = format_block_one_line(&prefix, &suffix, &call_strings, "", "");
68                vec![s]
69            }
70            Let {
71                ref name,
72                is_mut,
73                ref value,
74                ref type_,
75            } => {
76                let modif = if is_mut { "mut " } else { "" };
77                let type_string = if let Some(type_) = type_ {
78                    let type_strings = type_.to_code(env);
79                    format_block_one_line(": ", "", &type_strings, "", "")
80                } else {
81                    String::new()
82                };
83                let value_strings = value.to_code(env);
84                let prefix = format!("let {modif}{name}{type_string} = ");
85                let s = format_block_one_line(&prefix, ";", &value_strings, "", "");
86                vec![s]
87            }
88            Uninitialized => vec!["std::mem::MaybeUninit::uninit()".into()],
89            UninitializedNamed { ref name } => {
90                let s = format!("{name}::uninitialized()");
91                vec![s]
92            }
93            NullPtr => vec!["std::ptr::null()".into()],
94            NullMutPtr => vec!["std::ptr::null_mut()".into()],
95            Custom(ref string) => vec![string.clone()],
96            Tuple(ref chs, ref mode) => {
97                #[allow(deprecated)]
98                let with_bracket = match mode {
99                    TupleMode::Auto => chs.len() > 1,
100                    TupleMode::WithUnit => chs.len() != 1,
101                    TupleMode::Simple => true,
102                };
103                let (prefix, suffix) = if with_bracket { ("(", ")") } else { ("", "") };
104                let s = format_block_one_line(prefix, suffix, &chs.to_code(env), "", ", ");
105                vec![s]
106            }
107            FromGlibConversion {
108                ref mode,
109                ref array_length_name,
110                ref value,
111            } => {
112                let value_strings = value.to_code(env);
113                let (prefix, suffix) =
114                    mode.translate_from_glib_as_function(env, array_length_name.as_deref());
115                let s = format_block_one_line(&prefix, &suffix, &value_strings, "", "");
116                vec![s]
117            }
118            OptionalReturn {
119                ref condition,
120                ref value,
121            } => {
122                let value_strings = value.to_code(env);
123                let prefix = format!("if {condition} {{ Some(");
124                let suffix = ") } else { None }";
125                let s = format_block_one_line(&prefix, suffix, &value_strings, "", "");
126                vec![s]
127            }
128            AssertErrorSanity => {
129                let assert = format!(
130                    "debug_assert_eq!(is_ok == {}, !error.is_null());",
131                    use_glib_type(env, "ffi::GFALSE")
132                );
133                vec![assert]
134            }
135            ErrorResultReturn { ref ret, ref value } => {
136                let mut lines = match ret {
137                    Some(r) => r.to_code(env),
138                    None => vec![],
139                };
140                let value_strings = value.to_code(env);
141                let prefix = "if error.is_null() { Ok(";
142                let suffix = ") } else { Err(from_glib_full(error)) }";
143                let s = format_block_one_line(prefix, suffix, &value_strings, "", "");
144                lines.push(s);
145                lines
146            }
147            AssertInit(x) => vec![x.to_string()],
148            Connect {
149                ref signal,
150                ref trampoline,
151                in_trait,
152                is_detailed,
153            } => {
154                let mut v: Vec<String> = Vec::with_capacity(6);
155                if is_detailed {
156                    v.push(format!(
157                        r#"let detailed_signal_name = detail.map(|name| {{ format!("{signal}::{{name}}\0") }});"#
158                    ));
159                    v.push(format!(
160                        r#"let signal_name: &[u8] = detailed_signal_name.as_ref().map_or(c"{signal}".to_bytes(), |n| n.as_bytes());"#
161                    ));
162                    v.push(
163                        "connect_raw(self.as_ptr() as *mut _, signal_name.as_ptr() as *const _,"
164                            .to_string(),
165                    );
166                } else {
167                    v.push(format!(
168                        "connect_raw(self.as_ptr() as *mut _, c\"{signal}\".as_ptr() as *const _,"
169                    ));
170                }
171                let self_str = if in_trait { "Self, " } else { "" };
172                v.push(format!(
173                    "\tSome(std::mem::transmute::<*const (), unsafe extern \"C\" fn()>({trampoline}::<{self_str}F> as *const ())), Box_::into_raw(f))"
174                ));
175                v
176            }
177            Name(ref name) => vec![name.clone()],
178            ExternCFunc {
179                ref name,
180                ref parameters,
181                ref body,
182                ref return_value,
183                ref bounds,
184            } => {
185                let prefix = format!(r#"unsafe extern "C" fn {name}{bounds}("#);
186                let suffix = ")".to_string();
187                let params: Vec<_> = parameters
188                    .iter()
189                    .flat_map(|param| param.to_code(env))
190                    .collect();
191                let mut s = format_block_one_line(&prefix, &suffix, &params, "", ", ");
192                if let Some(return_value) = return_value {
193                    write!(s, " -> {return_value}").unwrap();
194                }
195                s.push_str(" {");
196                let mut code = format_block("", "}", &body.to_code(env));
197                code.insert(0, s);
198                code
199            }
200            Cast {
201                ref name,
202                ref type_,
203            } => vec![format!("{name} as {type_}")],
204            Call {
205                ref func_name,
206                ref arguments,
207            } => {
208                let args: Vec<_> = arguments.iter().flat_map(|arg| arg.to_code(env)).collect();
209                let s = format_block_one_line("(", ")", &args, "", ",");
210                vec![format!("{func_name}{s};")]
211            }
212        }
213    }
214}
215
216impl ToCode for Param {
217    fn to_code(&self, _env: &Env) -> Vec<String> {
218        vec![format!("{}: {}", self.name, self.typ)]
219    }
220}
221
222impl ToCode for [Chunk] {
223    fn to_code(&self, env: &Env) -> Vec<String> {
224        let mut v = Vec::new();
225        for ch in self {
226            let strs = ch.to_code(env);
227            v.extend_from_slice(&strs);
228        }
229        v
230    }
231}