safer_ffi/headers/languages/
mod.rs1#![cfg_attr(rustfmt, rustfmt::skip)]
2#![allow(irrefutable_let_patterns)]
3
4use_prelude!();
5use {
6 ::std::io::{
7 self,
8 Write as _,
9 },
10 super::{
11 Definer,
12 },
13};
14
15pub use c::C;
16mod c;
17
18__cfg_csharp__! {
19 pub use csharp::CSharp;
20 mod csharp;
21}
22
23__cfg_python__! {
24 pub use python::Python;
25 mod python;
26}
27
28pub
29struct Indentation {
30 depth: ::core::cell::Cell<usize>,
31 width: usize,
32}
33
34impl Indentation {
35 pub
36 fn new (width: usize)
37 -> Indentation
38 {
39 Self { depth: 0.into(), width }
40 }
41
42 pub
43 fn scope (self: &'_ Self)
44 -> impl '_ + Sized
45 {
46 self.depth.set(self.depth.get() + 1);
47 ::scopeguard::guard((), move |()| {
48 self.depth.set(self.depth.get() - 1);
49 })
50 }
51}
52
53impl ::core::fmt::Display for Indentation {
54 fn fmt (
55 self: &'_ Indentation,
56 fmt: &'_ mut ::core::fmt::Formatter<'_>,
57 ) -> ::core::fmt::Result
58 {
59 write!(fmt, "{: <indent$}", "", indent = self.depth.get() * self.width)
60 }
61}
62
63type Docs<'lt> = &'lt [&'lt str];
64
65pub
66trait HeaderLanguage : UpcastAny {
67 fn language_name(self: &'_ Self) -> &'static str {
68 ::core::any::type_name::<Self>()
69 }
70
71 fn supports_type_aliases(self: &'_ Self)
72 -> Option<&'_ dyn HeaderLanguageSupportingTypeAliases>
73 {
74 None
75 }
76
77 fn emit_simple_enum (
78 self: &'_ Self,
79 ctx: &'_ mut dyn Definer,
80 docs: Docs<'_>,
81 self_ty: &'_ dyn PhantomCType,
82 backing_integer: Option<&'_ dyn PhantomCType>,
83 variants: &'_ [EnumVariant<'_>],
84 ) -> io::Result<()>
85 ;
86
87 fn emit_struct (
88 self: &'_ Self,
89 ctx: &'_ mut dyn Definer,
90 docs: Docs<'_>,
91 self_ty: &'_ dyn PhantomCType,
92 fields: &'_ [StructField<'_>]
93 ) -> io::Result<()>
94 ;
95
96 fn emit_opaque_type (
97 self: &'_ Self,
98 ctx: &'_ mut dyn Definer,
99 docs: Docs<'_>,
100 self_ty: &'_ dyn PhantomCType,
101 ) -> io::Result<()>
102 ;
103
104 fn emit_function (
105 self: &'_ Self,
106 ctx: &'_ mut dyn Definer,
107 docs: Docs<'_>,
108 fname: &'_ str,
109 args: &'_ [FunctionArg<'_>],
110 ret_ty: &'_ dyn PhantomCType,
111 ) -> io::Result<()>
112 ;
113
114 fn emit_constant (
115 self: &'_ Self,
116 ctx: &'_ mut dyn Definer,
117 docs: Docs<'_>,
118 name: &'_ str,
119 ty: &'_ dyn PhantomCType,
120 skip_type: bool,
121 value: &'_ dyn ::core::fmt::Debug,
122 ) -> io::Result<()>
123 ;
124
125 fn emit_docs (
126 self: &'_ Self,
127 _ctx: &'_ mut dyn Definer,
128 _docs: Docs<'_>,
129 _indentation: &'_ Indentation,
130 ) -> io::Result<()>
131 {
132 Ok(())
135 }
136}
137
138pub
139trait HeaderLanguageSupportingTypeAliases : HeaderLanguage {
140 fn emit_type_alias(
141 self: &'_ Self,
142 ctx: &'_ mut dyn Definer,
143 docs: Docs<'_>,
144 self_ty: &'_ dyn PhantomCType,
145 inner_ty: &'_ dyn PhantomCType,
146 ) -> io::Result<()>
147 ;
148}
149
150pub
151struct EnumVariant<'lt> {
152 pub
153 docs: Docs<'lt>,
154
155 pub
156 name: &'lt str,
157
158 pub
159 discriminant: Option<&'lt dyn ::core::fmt::Debug>,
160}
161
162pub
163struct StructField<'lt> {
164 pub
165 docs: Docs<'lt>,
166
167 pub
168 name: &'lt str,
169
170 pub
171 ty: &'lt dyn PhantomCType,
172}
173
174pub
175struct FunctionArg<'lt> {
176 pub
180 name: &'lt str,
181
182 pub
183 ty: &'lt dyn PhantomCType,
184}
185
186pub
196trait PhantomCType {
197 fn short_name (
198 self: &'_ Self,
199 ) -> String
200 ;
201
202 fn name_wrapping_var (
203 self: &'_ Self,
204 language: &'_ dyn HeaderLanguage,
205 var_name: &'_ str,
206 ) -> String
207 ;
208
209 fn name (
210 self: &'_ Self,
211 language: &'_ dyn HeaderLanguage,
212 ) -> String
213 ;
214
215 fn csharp_marshaler (
216 self: &'_ Self,
217 ) -> Option<String>
218 ;
219
220 fn size (
221 self: &'_ Self,
222 ) -> usize
223 ;
224
225 fn align (
226 self: &'_ Self,
227 ) -> usize
228 ;
229}
230
231impl<T : ?Sized>
232 PhantomCType
233for
234 ::core::marker::PhantomData<T>
235where
236 T : CType,
237{
238 fn short_name (
239 self: &'_ Self,
240 ) -> String
241 {
242 <T as CType>::short_name()
243 }
244
245 fn name_wrapping_var (
246 self: &'_ Self,
247 language: &'_ dyn HeaderLanguage,
248 var_name: &'_ str,
249 ) -> String
250 {
251 T::name_wrapping_var(language, var_name)
252 }
253
254 fn name (
255 self: &'_ Self,
256 language: &'_ dyn HeaderLanguage,
257 ) -> String
258 {
259 T::name(language)
260 }
261
262 fn csharp_marshaler (
263 self: &'_ Self,
264 ) -> Option<String>
265 {
266 T::csharp_marshaler()
267 }
268
269 fn size (
270 self: &'_ Self,
271 ) -> usize
272 {
273 ::core::mem::size_of::<T>()
274 }
275
276 fn align (
277 self: &'_ Self,
278 ) -> usize
279 {
280 ::core::mem::align_of::<T>()
281 }
282}
283
284macro_rules! mk_out {
301 (
302 $indent_name:ident,
303 $out:expr $(,)?
305 ) => (
306 mk_out! { $indent_name $out $ }
307 );
308
309 (
310 $indent_name:tt $out:tt $_:tt
311 ) => (
312 macro_rules! out {
313 (
314 ($_(
315 $line:tt
316 )*) $_($rest:tt)*
317 ) => (
318 ::with_builtin_macros::with_builtin! {
321 let $concat = concat!($_(
322 "{", stringify!($indent_name), "}",
323 $line,
324 "\n",
325 )*) in {
326 ::safer_ffi_proc_macros::__respan! {
327 ( $_($line)* ) (
330 for line in
333 format!(
334 $concat
335 $_($rest)*
336 )
337 .split_inclusive('\n')
338 {
339 let new_line = if line.ends_with('\n') { "\n" } else { "" };
340 write!($out, "{}{new_line}", line.trim_end())?;
341 }
342 )
343 }
344 }
345 }
346 );
360
361 ( $_($tt:tt)* ) => (
362 write!($out, $_($tt)*)?
363 )
364 }
365 );
366} use mk_out;
367
368pub
369trait UpcastAny : 'static {
370 fn upcast_any (self: &'_ Self)
371 -> &'_ dyn ::core::any::Any
372 ;
373}
374impl<T : 'static> UpcastAny for T {
375 fn upcast_any (self: &'_ Self)
376 -> &'_ dyn ::core::any::Any
377 {
378 self
379 }
380}
381
382impl dyn HeaderLanguage {
383 pub
384 fn is<Concrete : HeaderLanguage> (
385 self: &'_ Self,
386 ) -> bool
387 {
388 self.upcast_any().is::<Concrete>()
389 }
390
391 pub
392 fn downcast_ref<Concrete : HeaderLanguage> (
393 self: &'_ Self,
394 ) -> Option<&'_ Concrete>
395 {
396 self.upcast_any()
397 .downcast_ref()
398 }
399}