oo_bindgen/model/builder/
structs.rs1use std::collections::HashSet;
2use std::rc::Rc;
3
4use crate::model::*;
5
6pub type FunctionReturnStructBuilder<'a> = StructFieldBuilder<'a, FunctionReturnStructField>;
7pub type CallbackArgStructBuilder<'a> = StructFieldBuilder<'a, CallbackArgStructField>;
8pub type FunctionArgStructBuilder<'a> = StructFieldBuilder<'a, FunctionArgStructField>;
9pub type UniversalStructBuilder<'a> = StructFieldBuilder<'a, UniversalStructField>;
10
11pub struct StructFieldBuilder<'a, F>
12where
13 F: StructFieldType,
14{
15 lib: &'a mut LibraryBuilder,
16 visibility: Visibility,
17 declaration: TypedStructDeclaration<F>,
18 fields: Vec<StructField<F, Unvalidated>>,
19 field_names: HashSet<String>,
20 doc: Option<Doc<Unvalidated>>,
21}
22
23impl<'a, F> StructFieldBuilder<'a, F>
24where
25 F: StructFieldType,
26{
27 pub(crate) fn new(lib: &'a mut LibraryBuilder, declaration: TypedStructDeclaration<F>) -> Self {
28 Self::new_impl(lib, declaration, Visibility::Public)
29 }
30
31 pub(crate) fn opaque(
32 lib: &'a mut LibraryBuilder,
33 declaration: TypedStructDeclaration<F>,
34 ) -> Self {
35 Self::new_impl(lib, declaration, Visibility::Private)
36 }
37
38 fn new_impl(
39 lib: &'a mut LibraryBuilder,
40 declaration: TypedStructDeclaration<F>,
41 visibility: Visibility,
42 ) -> Self {
43 Self {
44 lib,
45 visibility,
46 declaration,
47 fields: Vec::new(),
48 field_names: HashSet::new(),
49 doc: None,
50 }
51 }
52
53 pub fn add<S: IntoName, V: Into<F>, D: Into<Doc<Unvalidated>>>(
54 mut self,
55 name: S,
56 field_type: V,
57 doc: D,
58 ) -> BindResult<Self> {
59 let name = name.into_name()?;
60 let field_type = field_type.into();
61
62 if self.field_names.insert(name.to_string()) {
63 self.fields.push(StructField {
64 name,
65 field_type,
66 doc: doc.into(),
67 });
68 Ok(self)
69 } else {
70 Err(BindingErrorVariant::StructFieldDuplicateName {
71 handle: self.declaration.inner.clone(),
72 field_name: name,
73 }
74 .into())
75 }
76 }
77
78 pub fn doc<D: Into<Doc<Unvalidated>>>(mut self, doc: D) -> BindResult<Self> {
79 match self.doc {
80 None => {
81 self.doc = Some(doc.into());
82 Ok(self)
83 }
84 Some(_) => Err(BindingErrorVariant::DocAlreadyDefined {
85 symbol_name: self.declaration.name().clone(),
86 }
87 .into()),
88 }
89 }
90
91 pub fn end_fields(self) -> BindResult<StructMethodBuilder<'a, F>> {
92 let doc = match self.doc {
93 Some(doc) => doc,
94 None => {
95 return Err(BindingErrorVariant::DocNotDefined {
96 symbol_name: self.declaration.name().clone(),
97 }
98 .into())
99 }
100 };
101
102 Ok(StructMethodBuilder {
103 lib: self.lib,
104 visibility: self.visibility,
105 declaration: self.declaration,
106 fields: self.fields,
107 initializers: Vec::new(),
108 doc,
109 })
110 }
111}
112
113pub struct StructInitializerBuilder<'a, F>
114where
115 F: StructFieldType,
116{
117 name: Name,
118 initializer_type: InitializerType,
119 builder: StructMethodBuilder<'a, F>,
120 fields: Vec<InitializedValue>,
121 doc: Doc<Unvalidated>,
122}
123
124pub struct StructMethodBuilder<'a, F>
125where
126 F: StructFieldType,
127{
128 lib: &'a mut LibraryBuilder,
129 visibility: Visibility,
130 declaration: TypedStructDeclaration<F>,
131 fields: Vec<StructField<F, Unvalidated>>,
132 initializers: Vec<Handle<Initializer<Unvalidated>>>,
133 doc: Doc<Unvalidated>,
134}
135
136impl<'a, F> StructMethodBuilder<'a, F>
137where
138 F: StructFieldType,
139{
140 pub fn begin_initializer<D: Into<Doc<Unvalidated>>, S: IntoName>(
141 self,
142 name: S,
143 initializer_type: InitializerType,
144 doc: D,
145 ) -> BindResult<StructInitializerBuilder<'a, F>> {
146 let name = name.into_name()?;
147
148 if self.fields.iter().any(|field| name == field.name)
150 || self.initializers.iter().any(|c| name == c.name)
151 {
152 return Err(BindingErrorVariant::StructInitializerDuplicateName {
153 struct_name: self.declaration.name().clone(),
154 initializer_name: name,
155 }
156 .into());
157 }
158
159 Ok(StructInitializerBuilder {
160 name,
161 initializer_type,
162 builder: self,
163 fields: Vec::new(),
164 doc: doc.into(),
165 })
166 }
167
168 pub fn add_full_initializer<S: IntoName>(self, name: S) -> BindResult<Self> {
169 let name = name.into_name()?;
170 let struct_name = self.declaration.name().clone();
171 self.begin_initializer(
172 name,
173 InitializerType::Normal,
174 format!("Fully construct {{struct:{struct_name}}} specifying the value of each field"),
175 )?
176 .end_initializer()
177 }
178
179 pub fn build(self) -> BindResult<Handle<Struct<F, Unvalidated>>> {
180 let handle = Handle::new(Struct {
181 visibility: self.visibility,
182 declaration: self.declaration.clone(),
183 fields: self.fields,
184 initializers: self.initializers,
185 doc: self.doc,
186 });
187
188 self.lib
189 .add_statement(Statement::StructDefinition(F::create_struct_type(
190 handle.clone(),
191 )))?;
192
193 Ok(handle)
194 }
195}
196
197impl<'a, F> StructInitializerBuilder<'a, F>
198where
199 F: StructFieldType,
200{
201 pub fn default<D: Into<InitializerDefault>>(
202 mut self,
203 name: &Name,
204 value: D,
205 ) -> BindResult<Self> {
206 let value = value.into();
207
208 if self.fields.iter().any(|f| f.name == *name) {
210 return Err(BindingErrorVariant::StructInitializerDuplicateField {
211 struct_name: self.builder.declaration.name().clone(),
212 field_name: name.clone(),
213 }
214 .into());
215 }
216
217 let value = match self.builder.fields.iter().find(|f| f.name == *name) {
219 Some(x) => x.field_type.validate_default_value(&value)?,
220 None => {
221 return Err(BindingErrorVariant::StructInitializerUnknownField {
222 struct_name: self.builder.declaration.name().clone(),
223 field_name: name.clone(),
224 }
225 .into());
226 }
227 };
228
229 self.fields.push(InitializedValue {
230 name: name.clone(),
231 value,
232 });
233
234 Ok(self)
235 }
236
237 pub fn default_struct(self, name: &Name) -> BindResult<Self> {
238 self.default(name, InitializerDefault::DefaultStruct)
239 }
240
241 pub fn default_variant<S: Into<String>>(self, name: &Name, variant: S) -> BindResult<Self> {
242 self.default(name, InitializerDefault::Enum(variant.into()))
243 }
244
245 pub fn default_string<S: Into<String>>(self, name: &Name, value: S) -> BindResult<Self> {
246 self.default(name, InitializerDefault::String(value.into()))
247 }
248
249 pub fn end_initializer(mut self) -> BindResult<StructMethodBuilder<'a, F>> {
250 let initializer = Handle::new(Initializer {
251 name: self.name,
252 initializer_type: self.initializer_type,
253 values: Rc::new(self.fields),
254 doc: self.doc,
255 });
256
257 if let Some(x) = self
258 .builder
259 .initializers
260 .iter()
261 .find(|other| initializer.collides_with(other))
262 {
263 return Err(BindingErrorVariant::StructDuplicateInitializerArgs {
264 struct_name: self.builder.declaration.name().clone(),
265 this_initializer: initializer.name.clone(),
266 other_initializer: x.name.clone(),
267 }
268 .into());
269 }
270
271 self.builder.initializers.push(initializer);
272 Ok(self.builder)
273 }
274}