oo_bindgen/backend/dotnet/
wrappers.rs1use crate::backend::dotnet::*;
2
3fn filter_has_error(
4 x: &Handle<Function<Validated>>,
5) -> Option<(Handle<Function<Validated>>, ErrorType<Validated>)> {
6 x.error_type.get().map(|err| (x.clone(), err.clone()))
7}
8
9pub(crate) fn generate_native_functions_class(
10 f: &mut dyn Printer,
11 lib: &Library,
12 config: &DotnetBindgenConfig,
13) -> FormattingResult<()> {
14 print_license(f, &lib.info.license_description)?;
15 print_imports(f)?;
16 f.newline()?;
17
18 doxygen(f, |f| {
19 f.writeln("@mainpage")?;
21 f.newline()?;
22 f.writeln(&lib.info.description)?;
23 f.newline()?;
24 f.writeln(&format!(
25 "For complete documentation, see @ref {} namespace",
26 lib.settings.name
27 ))?;
28 f.newline()?;
29 f.writeln("@section license License")?;
30 f.newline()?;
31 for line in &lib.info.license_description {
32 f.writeln(line)?;
33 }
34
35 Ok(())
36 })?;
37 f.newline()?;
38
39 namespaced(f, &lib.settings.name, |f| {
40 f.writeln(&format!("internal class {NATIVE_FUNCTIONS_CLASSNAME}"))?;
41 blocked(f, |f| {
42 f.writeln(&format!("const string VERSION = \"{}\";", lib.version))?;
43
44 f.writeln(&format!("static {NATIVE_FUNCTIONS_CLASSNAME}()"))?;
46 blocked(f, |f| {
47 f.writeln("var loadedVersion = Helpers.RustString.FromNative(Version());")?;
48 f.writeln("if (loadedVersion != VERSION)")?;
49 blocked(f, |f| {
50 f.writeln(&format!("throw new Exception(\"{} module version mismatch. Expected \" + VERSION + \" but loaded \" + loadedVersion);", lib.settings.name))
51 })
52 })?;
53
54 f.newline()?;
55
56 for func in lib.functions() {
57 f.newline()?;
58 write_conversion_wrapper(f, func)?;
59 }
60
61 Ok(())
62 })?;
63
64 f.newline()?;
65 f.writeln("internal class ExceptionWrappers")?;
66 blocked(f, |f| {
67 for (func, err) in lib.functions().filter_map(filter_has_error) {
68 f.newline()?;
69 write_exception_wrapper(f, &func, &err)?;
70 }
71 Ok(())
72 })?;
73
74 f.newline()?;
75
76 f.writeln("internal class PInvoke")?;
77 blocked(f, |f| {
78 for func in lib.functions() {
79 write_pinvoke_signature(f, func, &lib.settings.c_ffi_prefix, config)?;
80 }
81 Ok(())
82 })
83 })
84}
85
86fn write_exception_and_return_blocks(
87 f: &mut dyn Printer,
88 err: &ErrorType<Validated>,
89 func: &Handle<Function<Validated>>,
90 params: &str,
91) -> FormattingResult<()> {
92 match func.return_type.get() {
93 Some(ret) => {
94 f.writeln(&format!(
95 "var _error_result = PInvoke.{}({}, out {} _return_value);",
96 func.name.camel_case(),
97 params,
98 ret.value.get_native_type()
99 ))?;
100 f.writeln(&format!(
101 "if(_error_result != {}.Ok)",
102 err.inner.name.camel_case()
103 ))?;
104 blocked(f, |f| {
105 f.writeln(&format!(
106 "throw new {}(_error_result);",
107 err.exception_name.camel_case()
108 ))
109 })?;
110 f.writeln("return _return_value;")
111 }
112 None => {
113 f.writeln(&format!(
114 "var error = PInvoke.{}({});",
115 func.name.camel_case(),
116 params
117 ))?;
118 f.writeln(&format!("if(error != {}.Ok)", err.inner.name.camel_case()))?;
119 blocked(f, |f| {
120 f.writeln(&format!(
121 "throw new {}(error);",
122 err.exception_name.camel_case()
123 ))
124 })
125 }
126 }
127}
128
129fn write_conversion_wrapper(
130 f: &mut dyn Printer,
131 func: &Handle<Function<Validated>>,
132) -> FormattingResult<()> {
133 f.write(&format!(
134 "internal static {} {}(",
135 func.return_type.get_native_type(),
136 func.name.camel_case()
137 ))?;
138
139 f.write(
140 &func
141 .arguments
142 .iter()
143 .map(|param| format!("{} {}", param.arg_type.get_native_type(), param.name))
144 .collect::<Vec<String>>()
145 .join(", "),
146 )?;
147
148 f.write(")")?;
149
150 let params = func
151 .arguments
152 .iter()
153 .map(|p| p.name.to_string())
154 .collect::<Vec<String>>()
155 .join(", ");
156
157 let target = if func.error_type.is_some() {
158 "ExceptionWrappers"
159 } else {
160 "PInvoke"
161 };
162
163 blocked(f, |f| {
164 f.newline()?;
165 if func.return_type.is_some() {
166 f.write("return ")?;
167 }
168 f.write(&format!(
169 "{}.{}({});",
170 target,
171 func.name.camel_case(),
172 params
173 ))
174 })
175}
176
177fn write_exception_wrapper(
178 f: &mut dyn Printer,
179 func: &Handle<Function<Validated>>,
180 err: &ErrorType<Validated>,
181) -> FormattingResult<()> {
182 f.write(&format!(
183 "internal static {} {}(",
184 func.return_type.get_native_type(),
185 func.name.camel_case(),
186 ))?;
187
188 f.write(
189 &func
190 .arguments
191 .iter()
192 .map(|param| format!("{} {}", param.arg_type.get_native_type(), param.name))
193 .collect::<Vec<String>>()
194 .join(", "),
195 )?;
196
197 f.write(")")?;
198
199 let params = func
200 .arguments
201 .iter()
202 .map(|p| p.name.to_string())
203 .collect::<Vec<String>>()
204 .join(", ");
205
206 blocked(f, |f| {
207 write_exception_and_return_blocks(f, err, func, ¶ms)
208 })
209}
210
211fn write_pinvoke_signature(
212 f: &mut dyn Printer,
213 handle: &Handle<Function<Validated>>,
214 prefix: &str,
215 config: &DotnetBindgenConfig,
216) -> FormattingResult<()> {
217 f.writeln(&format!(
218 "[DllImport(\"{}\", CallingConvention = CallingConvention.Cdecl, EntryPoint = \"{}_{}\")]",
219 config.ffi_name, prefix, handle.name
220 ))?;
221 f.newline()?;
222
223 if let Some(err) = handle.error_type.get() {
224 f.write(&format!(
225 "internal static extern {} {}(",
226 err.inner.get_native_type(),
227 handle.name.camel_case(),
228 ))?;
229 } else {
230 f.write(&format!(
231 "internal static extern {} {}(",
232 handle.return_type.get_native_type(),
233 handle.name.camel_case()
234 ))?;
235 }
236
237 f.write(
238 &handle
239 .arguments
240 .iter()
241 .map(|param| format!("{} {}", param.arg_type.get_native_type(), param.name))
242 .collect::<Vec<String>>()
243 .join(", "),
244 )?;
245
246 if let SignatureType::ErrorWithReturn(_, ret, _) = handle.get_signature_type() {
247 if !handle.arguments.is_empty() {
248 f.write(", ")?;
249 }
250 f.write(&format!("out {} @out", ret.get_native_type()))?
251 }
252
253 f.write(");")
254}