Skip to main content

diplomat_tool/c/
mod.rs

1mod formatter;
2pub(crate) mod gen;
3mod header;
4
5pub use self::formatter::CFormatter;
6pub(crate) use self::formatter::CAPI_NAMESPACE;
7pub use self::gen::ItemGenContext;
8pub(crate) use self::header::Header;
9
10use crate::{ErrorStore, FileMap};
11use diplomat_core::hir::BackendAttrSupport;
12use diplomat_core::hir::{self, DocsUrlGenerator};
13
14pub(crate) fn attr_support() -> BackendAttrSupport {
15    let mut a = BackendAttrSupport::default();
16
17    a.namespacing = false;
18    a.memory_sharing = true;
19    a.non_exhaustive_structs = false;
20    a.method_overloading = false;
21    a.utf8_strings = true;
22    a.utf16_strings = true;
23    a.static_slices = true;
24
25    a.constructors = false;
26    a.named_constructors = false;
27    a.fallible_constructors = false;
28    a.accessors = false;
29    a.static_accessors = false;
30    a.comparators = false;
31    a.stringifiers = false;
32    a.iterators = false;
33    a.iterables = false;
34    a.indexing = false;
35    a.arithmetic = false;
36    a.option = true;
37    a.callbacks = true;
38    a.traits = true;
39    a.custom_errors = false;
40    a.traits_are_send = false;
41    a.traits_are_sync = false;
42    a.generate_mocking_interface = false;
43    a.abi_compatibles = true;
44    a.struct_refs = true;
45    a.free_functions = true;
46
47    a
48}
49
50#[derive(askama::Template)]
51#[template(path = "c/runtime.h.jinja", escape = "none")]
52pub struct Runtime;
53
54pub(crate) fn run<'tcx>(
55    tcx: &'tcx hir::TypeContext,
56    config: &crate::Config,
57    docs_url_gen: &'tcx DocsUrlGenerator,
58) -> (FileMap, ErrorStore<'tcx, String>) {
59    let files = FileMap::default();
60    let formatter = CFormatter::new(tcx, false, config, docs_url_gen);
61    let errors = ErrorStore::default();
62
63    files.add_file("diplomat_runtime.h".into(), Runtime.to_string());
64
65    for (id, ty) in tcx.all_types() {
66        if ty.attrs().disable {
67            // Skip type if disabled
68            continue;
69        }
70
71        let decl_header_path = formatter.fmt_decl_header_path(id.into());
72        let impl_header_path = formatter.fmt_impl_header_path(id.into());
73
74        let _guard = errors.set_context_ty(ty.name().as_str().into());
75        let context = ItemGenContext {
76            tcx,
77            formatter: &formatter,
78            errors: &errors,
79            is_for_cpp: false,
80            decl_header_path: &decl_header_path,
81            impl_header_path: &impl_header_path,
82        };
83
84        let decl_header = match id {
85            hir::TypeId::Enum(e) => context.gen_enum_def(e),
86            hir::TypeId::Opaque(o) => context.gen_opaque_def(o),
87            hir::TypeId::Struct(s) => context.gen_struct_def::<hir::Everywhere>(s),
88            hir::TypeId::OutStruct(s) => context.gen_struct_def::<hir::OutputOnly>(s),
89            _ => unreachable!("unknown AST/HIR variant"),
90        };
91
92        let impl_header = context.gen_impl(id);
93
94        files.add_file(decl_header_path, decl_header.to_string());
95        files.add_file(impl_header_path, impl_header.to_string());
96    }
97
98    for (id, trt) in tcx.all_traits() {
99        if trt.attrs.disable {
100            // Skip type if disabled
101            continue;
102        }
103
104        let decl_header_path = formatter.fmt_decl_header_path(id.into());
105        let impl_header_path = formatter.fmt_impl_header_path(id.into());
106
107        let _guard = errors.set_context_ty(trt.name.as_str().into());
108        let context = ItemGenContext {
109            tcx,
110            formatter: &formatter,
111            errors: &errors,
112            is_for_cpp: false,
113            decl_header_path: &decl_header_path,
114            impl_header_path: &impl_header_path,
115        };
116
117        let decl_header = context.gen_trait_def(id);
118        files.add_file(decl_header_path, decl_header.to_string());
119    }
120    // loop over traits too
121
122    let impl_header_path = "free_functions.h".to_string();
123
124    let context = ItemGenContext {
125        tcx,
126        formatter: &formatter,
127        errors: &errors,
128        is_for_cpp: false,
129        decl_header_path: "",
130        impl_header_path: &impl_header_path,
131    };
132
133    let impl_header = context.gen_function_impls(None, tcx.all_free_functions().map(|(_, m)| m));
134
135    if !impl_header.body.is_empty() {
136        files.add_file(impl_header.path.clone(), impl_header.to_string());
137    }
138
139    (files, errors)
140}