1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use std::io::Write;
6
7use crate::bindgen::config::{Config, Language};
8use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver;
9use crate::bindgen::dependencies::Dependencies;
10use crate::bindgen::ir::{
11 AnnotationSet, Cfg, ConditionWrite, Documentation, GenericArgument, GenericParams, Item,
12 ItemContainer, Path, ToCondition,
13};
14use crate::bindgen::library::Library;
15use crate::bindgen::mangle;
16use crate::bindgen::monomorph::Monomorphs;
17use crate::bindgen::writer::{Source, SourceWriter};
18
19#[derive(Debug, Clone)]
20pub struct OpaqueItem {
21 pub path: Path,
22 pub export_name: String,
23 pub generic_params: GenericParams,
24 pub cfg: Option<Cfg>,
25 pub annotations: AnnotationSet,
26 pub documentation: Documentation,
27}
28
29impl OpaqueItem {
30 pub fn load(
31 path: Path,
32 generics: &syn::Generics,
33 attrs: &[syn::Attribute],
34 mod_cfg: Option<&Cfg>,
35 ) -> Result<OpaqueItem, String> {
36 Ok(Self::new(
37 path,
38 GenericParams::load(generics)?,
39 Cfg::append(mod_cfg, Cfg::load(attrs)),
40 AnnotationSet::load(attrs).unwrap_or_else(|_| AnnotationSet::new()),
41 Documentation::load(attrs),
42 ))
43 }
44
45 pub fn new(
46 path: Path,
47 generic_params: GenericParams,
48 cfg: Option<Cfg>,
49 annotations: AnnotationSet,
50 documentation: Documentation,
51 ) -> OpaqueItem {
52 let export_name = path.name().to_owned();
53 Self {
54 path,
55 export_name,
56 generic_params,
57 cfg,
58 annotations,
59 documentation,
60 }
61 }
62}
63
64impl Item for OpaqueItem {
65 fn path(&self) -> &Path {
66 &self.path
67 }
68
69 fn export_name(&self) -> &str {
70 &self.export_name
71 }
72
73 fn cfg(&self) -> Option<&Cfg> {
74 self.cfg.as_ref()
75 }
76
77 fn annotations(&self) -> &AnnotationSet {
78 &self.annotations
79 }
80
81 fn annotations_mut(&mut self) -> &mut AnnotationSet {
82 &mut self.annotations
83 }
84
85 fn container(&self) -> ItemContainer {
86 ItemContainer::OpaqueItem(self.clone())
87 }
88
89 fn collect_declaration_types(&self, resolver: &mut DeclarationTypeResolver) {
90 resolver.add_struct(&self.path);
91 }
92
93 fn rename_for_config(&mut self, config: &Config) {
94 config.export.rename(&mut self.export_name);
95 }
96
97 fn add_dependencies(&self, _: &Library, _: &mut Dependencies) {}
98
99 fn instantiate_monomorph(
100 &self,
101 generic_values: &[GenericArgument],
102 library: &Library,
103 out: &mut Monomorphs,
104 ) {
105 assert!(
106 !self.generic_params.is_empty(),
107 "{} is not generic",
108 self.path
109 );
110
111 // We can be instantiated with less generic params because of default
112 // template parameters, or because of empty types that we remove during
113 // parsing (`()`).
114 assert!(
115 self.generic_params.len() >= generic_values.len(),
116 "{} has {} params but is being instantiated with {} values",
117 self.path,
118 self.generic_params.len(),
119 generic_values.len(),
120 );
121
122 let mangled_path = mangle::mangle_path(
123 &self.path,
124 generic_values,
125 &library.get_config().export.mangle,
126 );
127
128 let monomorph = OpaqueItem::new(
129 mangled_path,
130 GenericParams::default(),
131 self.cfg.clone(),
132 self.annotations.clone(),
133 self.documentation.clone(),
134 );
135
136 out.insert_opaque(self, monomorph, generic_values.to_owned());
137 }
138}
139
140impl Source for OpaqueItem {
141 fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
142 let condition = self.cfg.to_condition(config);
143 condition.write_before(config, out);
144
145 self.documentation.write(config, out);
146
147 self.generic_params.write_with_default(config, out);
148
149 match config.language {
150 Language::C if config.style.generate_typedef() => {
151 write!(
152 out,
153 "typedef struct {} {};",
154 self.export_name(),
155 self.export_name()
156 );
157 }
158 Language::C | Language::Cxx => {
159 write!(out, "struct {};", self.export_name());
160 }
161 Language::Cython => {
162 write!(
163 out,
164 "{}struct {}",
165 config.style.cython_def(),
166 self.export_name()
167 );
168 out.open_brace();
169 out.write("pass");
170 out.close_brace(false);
171 }
172 }
173
174 condition.write_after(config, out);
175 }
176}
177