Skip to main content

sails_type_registry/
builder.rs

1use alloc::{string::String, vec::Vec};
2
3use sails_idl_ast::{
4    Annotation, EnumDef, EnumVariant, StructDef, StructField, Type, TypeDecl, TypeDef,
5    TypeParameter,
6};
7
8/// Builder for a field attached to a composite or variant parent.
9#[derive(Debug, Clone)]
10pub struct FieldBuilder<P> {
11    parent: P,
12    name: Option<String>,
13    metadata: Metadata,
14}
15
16/// Builder for a single enum variant.
17#[derive(Debug, Clone)]
18pub struct VariantBuilder {
19    parent: VariantDefBuilder,
20    name: String,
21    metadata: Metadata,
22    fields: Vec<StructField>,
23}
24
25/// Builder for composite (struct) type definitions.
26#[derive(Debug, Clone)]
27pub struct CompositeBuilder {
28    type_builder: TypeBuilder,
29    fields: Vec<StructField>,
30}
31
32/// Builder for variant (enum) type definitions.
33#[derive(Debug, Clone)]
34pub struct VariantDefBuilder {
35    type_builder: TypeBuilder,
36    variants: Vec<EnumVariant>,
37}
38
39/// Builder for a single declared generic parameter.
40#[derive(Debug, Clone)]
41pub struct ParamBuilder {
42    inner: TypeBuilder,
43    param_name: String,
44}
45
46/// Entry-point builder for named [`Type`] values.
47#[derive(Debug, Clone, Default)]
48pub struct TypeBuilder {
49    name: String,
50    type_params: Vec<TypeParameter>,
51    metadata: Metadata,
52}
53
54#[derive(Debug, Clone, Default)]
55struct Metadata {
56    docs: Vec<String>,
57    annotations: Vec<Annotation>,
58}
59
60/// Helper trait implemented by builders that can receive fields.
61pub trait PushField: Sized {
62    /// Appends a fully built field to the parent.
63    fn push_field(&mut self, field: StructField);
64}
65
66impl<P: PushField> FieldBuilder<P> {
67    /// Completes the field by assigning its type and returning the parent.
68    pub fn ty(mut self, type_decl: TypeDecl) -> P {
69        self.parent.push_field(StructField {
70            name: self.name,
71            type_decl,
72            docs: self.metadata.docs,
73            annotations: self.metadata.annotations,
74        });
75        self.parent
76    }
77}
78
79impl<P> FieldBuilder<P> {
80    /// Appends a documentation line to the field.
81    pub fn doc(mut self, doc: impl Into<String>) -> Self {
82        self.metadata.doc(doc);
83        self
84    }
85
86    /// Starts a new annotation on the field.
87    pub fn annotate(mut self, name: impl Into<String>) -> Self {
88        self.metadata.annotate(name);
89        self
90    }
91
92    /// Sets the value for the most recently added annotation.
93    pub fn value(mut self, value: impl Into<String>) -> Self {
94        self.metadata.value(value);
95        self
96    }
97}
98
99impl VariantBuilder {
100    /// Starts a named field inside the variant.
101    pub fn field(self, name: impl Into<String>) -> FieldBuilder<Self> {
102        FieldBuilder {
103            parent: self,
104            name: Some(name.into()),
105            metadata: Metadata::default(),
106        }
107    }
108
109    /// Starts an unnamed field inside the variant.
110    pub fn unnamed(self) -> FieldBuilder<Self> {
111        FieldBuilder {
112            parent: self,
113            name: None,
114            metadata: Metadata::default(),
115        }
116    }
117
118    /// Appends a documentation line to the variant.
119    pub fn doc(mut self, doc: impl Into<String>) -> Self {
120        self.metadata.doc(doc);
121        self
122    }
123
124    /// Starts a new annotation on the variant.
125    pub fn annotate(mut self, name: impl Into<String>) -> Self {
126        self.metadata.annotate(name);
127        self
128    }
129
130    /// Sets the value for the most recently added annotation.
131    pub fn value(mut self, value: impl Into<String>) -> Self {
132        self.metadata.value(value);
133        self
134    }
135
136    /// Finishes the variant and returns to the enclosing variant builder.
137    pub fn finish_variant(mut self) -> VariantDefBuilder {
138        self.parent.variants.push(EnumVariant {
139            name: self.name,
140            def: StructDef {
141                fields: self.fields,
142            },
143            entry_id: 0,
144            docs: self.metadata.docs,
145            annotations: self.metadata.annotations,
146        });
147        self.parent
148    }
149}
150
151impl CompositeBuilder {
152    /// Starts a named field inside the composite.
153    pub fn field(self, name: impl Into<String>) -> FieldBuilder<Self> {
154        FieldBuilder {
155            parent: self,
156            name: Some(name.into()),
157            metadata: Metadata::default(),
158        }
159    }
160
161    /// Starts an unnamed field inside the composite.
162    pub fn unnamed(self) -> FieldBuilder<Self> {
163        FieldBuilder {
164            parent: self,
165            name: None,
166            metadata: Metadata::default(),
167        }
168    }
169
170    /// Appends a documentation line to the type being built.
171    pub fn doc(mut self, doc: impl Into<String>) -> Self {
172        self.type_builder.metadata.doc(doc);
173        self
174    }
175
176    /// Starts a new annotation on the type being built.
177    pub fn annotate(mut self, name: impl Into<String>) -> Self {
178        self.type_builder.metadata.annotate(name);
179        self
180    }
181
182    /// Sets the value for the most recently added annotation.
183    pub fn value(mut self, value: impl Into<String>) -> Self {
184        self.type_builder.metadata.value(value);
185        self
186    }
187
188    /// Builds the final named struct [`Type`].
189    pub fn build(self) -> Type {
190        self.type_builder.build(TypeDef::Struct(StructDef {
191            fields: self.fields,
192        }))
193    }
194}
195
196impl VariantDefBuilder {
197    /// Starts a new variant inside the enum definition.
198    pub fn add_variant(self, name: impl Into<String>) -> VariantBuilder {
199        VariantBuilder {
200            parent: self,
201            name: name.into(),
202            metadata: Metadata::default(),
203            fields: Vec::new(),
204        }
205    }
206
207    /// Builds the final named enum [`Type`].
208    pub fn build(self) -> Type {
209        self.type_builder.build(TypeDef::Enum(EnumDef {
210            variants: self.variants,
211        }))
212    }
213}
214
215impl ParamBuilder {
216    /// Assigns a default `TypeDecl` to the declared generic parameter.
217    pub fn default_ty(mut self, type_decl: TypeDecl) -> TypeBuilder {
218        self.inner.type_params.push(TypeParameter {
219            name: self.param_name,
220            ty: Some(type_decl),
221        });
222        self.inner
223    }
224
225    /// Completes the parameter declaration with no default.
226    pub fn no_default(mut self) -> TypeBuilder {
227        self.inner.type_params.push(TypeParameter {
228            name: self.param_name,
229            ty: None,
230        });
231        self.inner
232    }
233}
234
235impl TypeBuilder {
236    /// Creates an empty builder.
237    pub fn new() -> Self {
238        Self::default()
239    }
240
241    /// Sets the recorded type name.
242    pub fn name(mut self, name: impl Into<String>) -> Self {
243        self.name = name.into();
244        self
245    }
246
247    /// Declares a generic parameter with no default.
248    pub fn param(mut self, name: impl Into<String>) -> Self {
249        self.type_params.push(TypeParameter {
250            name: name.into(),
251            ty: None,
252        });
253        self
254    }
255
256    /// Declares a generic parameter with a default type.
257    pub fn param_with_default(mut self, name: impl Into<String>, type_decl: TypeDecl) -> Self {
258        self.type_params.push(TypeParameter {
259            name: name.into(),
260            ty: Some(type_decl),
261        });
262        self
263    }
264
265    /// Appends a documentation line to the type.
266    pub fn doc(mut self, doc: impl Into<String>) -> Self {
267        self.metadata.doc(doc);
268        self
269    }
270
271    /// Starts a new annotation on the type.
272    pub fn annotate(mut self, name: impl Into<String>) -> Self {
273        self.metadata.annotate(name);
274        self
275    }
276
277    /// Sets the value for the most recently added annotation.
278    pub fn value(mut self, value: impl Into<String>) -> Self {
279        self.metadata.value(value);
280        self
281    }
282
283    /// Starts building a composite (struct) type definition.
284    pub fn composite(self) -> CompositeBuilder {
285        CompositeBuilder {
286            type_builder: self,
287            fields: Vec::new(),
288        }
289    }
290
291    /// Starts building a variant (enum) type definition.
292    pub fn variant(self) -> VariantDefBuilder {
293        VariantDefBuilder {
294            type_builder: self,
295            variants: Vec::new(),
296        }
297    }
298
299    /// Builds a named alias type definition.
300    pub fn alias(self, target: TypeDecl) -> Type {
301        self.build(TypeDef::Alias(sails_idl_ast::AliasDef { target }))
302    }
303
304    fn build(self, def: TypeDef) -> Type {
305        Type {
306            name: self.name,
307            type_params: self.type_params,
308            def,
309            docs: self.metadata.docs,
310            annotations: self.metadata.annotations,
311        }
312    }
313}
314
315impl Metadata {
316    fn doc(&mut self, doc: impl Into<String>) {
317        self.docs.push(doc.into());
318    }
319
320    fn annotate(&mut self, name: impl Into<String>) {
321        self.annotations.push((name.into(), None));
322    }
323
324    fn value(&mut self, value: impl Into<String>) {
325        if let Some(ann) = self.annotations.last_mut() {
326            ann.1 = Some(value.into());
327        }
328    }
329}
330
331impl PushField for CompositeBuilder {
332    fn push_field(&mut self, field: StructField) {
333        self.fields.push(field);
334    }
335}
336
337impl PushField for VariantBuilder {
338    fn push_field(&mut self, field: StructField) {
339        self.fields.push(field);
340    }
341}