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 let s = format_block_one_line(
35 &prefix,
36 if *ignore_return { ");" } else { ")" },
37 ¶ms.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, ¶ms, "", ", ");
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}