baobao_codegen/builder/
structure.rs

1//! Language-agnostic structure definitions.
2//!
3//! This module provides declarative specifications for structs, enums,
4//! and their members that can be rendered to any target language.
5
6use super::types::{TypeRef, Visibility};
7
8/// A declarative specification for a struct or class.
9///
10/// Represents the *intent* of defining a data structure, independent
11/// of any specific language syntax.
12#[derive(Debug, Clone, PartialEq)]
13pub struct StructSpec {
14    /// Struct/class name.
15    pub name: String,
16    /// Documentation comment.
17    pub doc: Option<String>,
18    /// Fields in the struct.
19    pub fields: Vec<FieldSpec>,
20    /// Derive macros (Rust) or implemented interfaces (TS).
21    pub derives: Vec<String>,
22    /// Attributes (Rust) or decorators (TS/Python).
23    pub attributes: Vec<AttributeSpec>,
24    /// Visibility modifier.
25    pub visibility: Visibility,
26}
27
28impl StructSpec {
29    /// Create a new public struct spec.
30    pub fn new(name: impl Into<String>) -> Self {
31        Self {
32            name: name.into(),
33            doc: None,
34            fields: Vec::new(),
35            derives: Vec::new(),
36            attributes: Vec::new(),
37            visibility: Visibility::Public,
38        }
39    }
40
41    /// Set documentation comment.
42    pub fn doc(mut self, doc: impl Into<String>) -> Self {
43        self.doc = Some(doc.into());
44        self
45    }
46
47    /// Add a field.
48    pub fn field(mut self, field: FieldSpec) -> Self {
49        self.fields.push(field);
50        self
51    }
52
53    /// Add multiple fields.
54    pub fn fields(mut self, fields: impl IntoIterator<Item = FieldSpec>) -> Self {
55        self.fields.extend(fields);
56        self
57    }
58
59    /// Add a derive (Rust) or implement (TS interface).
60    pub fn derive(mut self, name: impl Into<String>) -> Self {
61        self.derives.push(name.into());
62        self
63    }
64
65    /// Add multiple derives.
66    pub fn derives(mut self, names: impl IntoIterator<Item = impl Into<String>>) -> Self {
67        self.derives.extend(names.into_iter().map(Into::into));
68        self
69    }
70
71    /// Add an attribute.
72    pub fn attribute(mut self, attr: AttributeSpec) -> Self {
73        self.attributes.push(attr);
74        self
75    }
76
77    /// Set visibility.
78    pub fn visibility(mut self, vis: Visibility) -> Self {
79        self.visibility = vis;
80        self
81    }
82
83    /// Make this struct private.
84    pub fn private(mut self) -> Self {
85        self.visibility = Visibility::Private;
86        self
87    }
88
89    /// Check if this struct has any fields.
90    pub fn has_fields(&self) -> bool {
91        !self.fields.is_empty()
92    }
93}
94
95/// A field in a struct.
96#[derive(Debug, Clone, PartialEq)]
97pub struct FieldSpec {
98    /// Field name.
99    pub name: String,
100    /// Field type.
101    pub ty: TypeRef,
102    /// Documentation comment.
103    pub doc: Option<String>,
104    /// Whether the field is required (for interfaces/optional types).
105    pub required: bool,
106    /// Attributes on this field.
107    pub attributes: Vec<AttributeSpec>,
108    /// Visibility modifier.
109    pub visibility: Visibility,
110}
111
112impl FieldSpec {
113    /// Create a new required public field.
114    pub fn new(name: impl Into<String>, ty: TypeRef) -> Self {
115        Self {
116            name: name.into(),
117            ty,
118            doc: None,
119            required: true,
120            attributes: Vec::new(),
121            visibility: Visibility::Public,
122        }
123    }
124
125    /// Set documentation comment.
126    pub fn doc(mut self, doc: impl Into<String>) -> Self {
127        self.doc = Some(doc.into());
128        self
129    }
130
131    /// Make this field optional.
132    pub fn optional(mut self) -> Self {
133        self.required = false;
134        self
135    }
136
137    /// Add an attribute.
138    pub fn attribute(mut self, attr: AttributeSpec) -> Self {
139        self.attributes.push(attr);
140        self
141    }
142
143    /// Set visibility.
144    pub fn visibility(mut self, vis: Visibility) -> Self {
145        self.visibility = vis;
146        self
147    }
148
149    /// Make this field private.
150    pub fn private(mut self) -> Self {
151        self.visibility = Visibility::Private;
152        self
153    }
154}
155
156/// A declarative specification for an enum.
157#[derive(Debug, Clone, PartialEq)]
158pub struct EnumSpec {
159    /// Enum name.
160    pub name: String,
161    /// Documentation comment.
162    pub doc: Option<String>,
163    /// Variants in the enum.
164    pub variants: Vec<VariantSpec>,
165    /// Derive macros (Rust).
166    pub derives: Vec<String>,
167    /// Attributes on the enum.
168    pub attributes: Vec<AttributeSpec>,
169    /// Visibility modifier.
170    pub visibility: Visibility,
171}
172
173impl EnumSpec {
174    /// Create a new public enum spec.
175    pub fn new(name: impl Into<String>) -> Self {
176        Self {
177            name: name.into(),
178            doc: None,
179            variants: Vec::new(),
180            derives: Vec::new(),
181            attributes: Vec::new(),
182            visibility: Visibility::Public,
183        }
184    }
185
186    /// Set documentation comment.
187    pub fn doc(mut self, doc: impl Into<String>) -> Self {
188        self.doc = Some(doc.into());
189        self
190    }
191
192    /// Add a variant.
193    pub fn variant(mut self, variant: VariantSpec) -> Self {
194        self.variants.push(variant);
195        self
196    }
197
198    /// Add multiple variants.
199    pub fn variants(mut self, variants: impl IntoIterator<Item = VariantSpec>) -> Self {
200        self.variants.extend(variants);
201        self
202    }
203
204    /// Add a simple unit variant by name.
205    pub fn unit_variant(mut self, name: impl Into<String>) -> Self {
206        self.variants.push(VariantSpec::unit(name));
207        self
208    }
209
210    /// Add a derive.
211    pub fn derive(mut self, name: impl Into<String>) -> Self {
212        self.derives.push(name.into());
213        self
214    }
215
216    /// Add multiple derives.
217    pub fn derives(mut self, names: impl IntoIterator<Item = impl Into<String>>) -> Self {
218        self.derives.extend(names.into_iter().map(Into::into));
219        self
220    }
221
222    /// Add an attribute.
223    pub fn attribute(mut self, attr: AttributeSpec) -> Self {
224        self.attributes.push(attr);
225        self
226    }
227
228    /// Set visibility.
229    pub fn visibility(mut self, vis: Visibility) -> Self {
230        self.visibility = vis;
231        self
232    }
233
234    /// Make this enum private.
235    pub fn private(mut self) -> Self {
236        self.visibility = Visibility::Private;
237        self
238    }
239}
240
241/// A variant in an enum.
242#[derive(Debug, Clone, PartialEq)]
243pub struct VariantSpec {
244    /// Variant name.
245    pub name: String,
246    /// Documentation comment.
247    pub doc: Option<String>,
248    /// Variant kind (unit, tuple, struct).
249    pub kind: VariantKind,
250    /// Attributes on this variant.
251    pub attributes: Vec<AttributeSpec>,
252}
253
254impl VariantSpec {
255    /// Create a unit variant.
256    pub fn unit(name: impl Into<String>) -> Self {
257        Self {
258            name: name.into(),
259            doc: None,
260            kind: VariantKind::Unit,
261            attributes: Vec::new(),
262        }
263    }
264
265    /// Create a tuple variant.
266    pub fn tuple(name: impl Into<String>, fields: Vec<TypeRef>) -> Self {
267        Self {
268            name: name.into(),
269            doc: None,
270            kind: VariantKind::Tuple(fields),
271            attributes: Vec::new(),
272        }
273    }
274
275    /// Create a struct variant.
276    pub fn struct_(name: impl Into<String>, fields: Vec<FieldSpec>) -> Self {
277        Self {
278            name: name.into(),
279            doc: None,
280            kind: VariantKind::Struct(fields),
281            attributes: Vec::new(),
282        }
283    }
284
285    /// Set documentation comment.
286    pub fn doc(mut self, doc: impl Into<String>) -> Self {
287        self.doc = Some(doc.into());
288        self
289    }
290
291    /// Add an attribute.
292    pub fn attribute(mut self, attr: AttributeSpec) -> Self {
293        self.attributes.push(attr);
294        self
295    }
296}
297
298/// Kind of enum variant.
299#[derive(Debug, Clone, PartialEq)]
300pub enum VariantKind {
301    /// Unit variant: `None`, `Empty`.
302    Unit,
303    /// Tuple variant: `Some(T)`, `Pair(A, B)`.
304    Tuple(Vec<TypeRef>),
305    /// Struct variant: `Point { x: i32, y: i32 }`.
306    Struct(Vec<FieldSpec>),
307}
308
309/// An attribute or decorator on a type or member.
310#[derive(Debug, Clone, PartialEq)]
311pub struct AttributeSpec {
312    /// Attribute path (e.g., "serde::rename", "clap::arg").
313    pub path: String,
314    /// Attribute arguments.
315    pub args: Vec<AttributeArg>,
316}
317
318impl AttributeSpec {
319    /// Create a simple attribute with no arguments.
320    pub fn simple(path: impl Into<String>) -> Self {
321        Self {
322            path: path.into(),
323            args: Vec::new(),
324        }
325    }
326
327    /// Create an attribute with a single unnamed argument.
328    pub fn with_value(path: impl Into<String>, value: impl Into<String>) -> Self {
329        Self {
330            path: path.into(),
331            args: vec![AttributeArg::Positional(value.into())],
332        }
333    }
334
335    /// Add a positional argument.
336    pub fn arg(mut self, value: impl Into<String>) -> Self {
337        self.args.push(AttributeArg::Positional(value.into()));
338        self
339    }
340
341    /// Add a named argument.
342    pub fn named(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
343        self.args
344            .push(AttributeArg::Named(name.into(), value.into()));
345        self
346    }
347
348    /// Add a flag argument (name with no value).
349    pub fn flag(mut self, name: impl Into<String>) -> Self {
350        self.args.push(AttributeArg::Flag(name.into()));
351        self
352    }
353}
354
355/// An argument to an attribute.
356#[derive(Debug, Clone, PartialEq)]
357pub enum AttributeArg {
358    /// Positional argument.
359    Positional(String),
360    /// Named argument: `key = value`.
361    Named(String, String),
362    /// Flag (name only, no value).
363    Flag(String),
364}
365
366/// Trait for rendering structure specs to language-specific code.
367///
368/// Implement this trait to support rendering structs and enums
369/// in a new target language.
370pub trait StructureRenderer {
371    /// Render a struct specification to code.
372    fn render_struct(&self, spec: &StructSpec) -> String;
373
374    /// Render an enum specification to code.
375    fn render_enum(&self, spec: &EnumSpec) -> String;
376
377    /// Render a field specification to code.
378    fn render_field(&self, spec: &FieldSpec) -> String;
379
380    /// Render a variant specification to code.
381    fn render_variant(&self, spec: &VariantSpec) -> String;
382
383    /// Render an attribute specification to code.
384    fn render_attribute(&self, spec: &AttributeSpec) -> String;
385
386    /// Render a visibility modifier to code.
387    fn render_visibility(&self, vis: Visibility) -> &'static str;
388}
389
390#[cfg(test)]
391mod tests {
392    use super::*;
393
394    #[test]
395    fn test_struct_spec() {
396        let spec = StructSpec::new("User")
397            .doc("A user in the system")
398            .derive("Debug")
399            .derive("Clone")
400            .field(FieldSpec::new("id", TypeRef::int()))
401            .field(FieldSpec::new("name", TypeRef::string()));
402
403        assert_eq!(spec.name, "User");
404        assert_eq!(spec.doc, Some("A user in the system".into()));
405        assert_eq!(spec.derives, vec!["Debug", "Clone"]);
406        assert_eq!(spec.fields.len(), 2);
407        assert!(spec.has_fields());
408    }
409
410    #[test]
411    fn test_field_spec() {
412        let field = FieldSpec::new("email", TypeRef::string())
413            .doc("User's email address")
414            .optional()
415            .private();
416
417        assert_eq!(field.name, "email");
418        assert!(!field.required);
419        assert!(field.visibility.is_private());
420    }
421
422    #[test]
423    fn test_enum_spec() {
424        let spec = EnumSpec::new("Status")
425            .derive("Debug")
426            .unit_variant("Pending")
427            .unit_variant("Active")
428            .variant(VariantSpec::tuple("Error", vec![TypeRef::string()]));
429
430        assert_eq!(spec.name, "Status");
431        assert_eq!(spec.variants.len(), 3);
432    }
433
434    #[test]
435    fn test_variant_kinds() {
436        let unit = VariantSpec::unit("None");
437        assert!(matches!(unit.kind, VariantKind::Unit));
438
439        let tuple = VariantSpec::tuple("Some", vec![TypeRef::int()]);
440        assert!(matches!(tuple.kind, VariantKind::Tuple(ref fields) if fields.len() == 1));
441
442        let struct_ = VariantSpec::struct_(
443            "Point",
444            vec![
445                FieldSpec::new("x", TypeRef::int()),
446                FieldSpec::new("y", TypeRef::int()),
447            ],
448        );
449        assert!(matches!(struct_.kind, VariantKind::Struct(ref fields) if fields.len() == 2));
450    }
451
452    #[test]
453    fn test_attribute_spec() {
454        let simple = AttributeSpec::simple("derive");
455        assert!(simple.args.is_empty());
456
457        let with_value = AttributeSpec::with_value("serde", "rename_all = \"camelCase\"");
458        assert_eq!(with_value.args.len(), 1);
459
460        let complex = AttributeSpec::simple("clap")
461            .arg("long")
462            .named("short", "'v'")
463            .flag("global");
464        assert_eq!(complex.args.len(), 3);
465    }
466}