1use super::types::{TypeRef, Visibility};
7
8#[derive(Debug, Clone, PartialEq)]
13pub struct StructSpec {
14 pub name: String,
16 pub doc: Option<String>,
18 pub fields: Vec<FieldSpec>,
20 pub derives: Vec<String>,
22 pub attributes: Vec<AttributeSpec>,
24 pub visibility: Visibility,
26}
27
28impl StructSpec {
29 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 pub fn doc(mut self, doc: impl Into<String>) -> Self {
43 self.doc = Some(doc.into());
44 self
45 }
46
47 pub fn field(mut self, field: FieldSpec) -> Self {
49 self.fields.push(field);
50 self
51 }
52
53 pub fn fields(mut self, fields: impl IntoIterator<Item = FieldSpec>) -> Self {
55 self.fields.extend(fields);
56 self
57 }
58
59 pub fn derive(mut self, name: impl Into<String>) -> Self {
61 self.derives.push(name.into());
62 self
63 }
64
65 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 pub fn attribute(mut self, attr: AttributeSpec) -> Self {
73 self.attributes.push(attr);
74 self
75 }
76
77 pub fn visibility(mut self, vis: Visibility) -> Self {
79 self.visibility = vis;
80 self
81 }
82
83 pub fn private(mut self) -> Self {
85 self.visibility = Visibility::Private;
86 self
87 }
88
89 pub fn has_fields(&self) -> bool {
91 !self.fields.is_empty()
92 }
93}
94
95#[derive(Debug, Clone, PartialEq)]
97pub struct FieldSpec {
98 pub name: String,
100 pub ty: TypeRef,
102 pub doc: Option<String>,
104 pub required: bool,
106 pub attributes: Vec<AttributeSpec>,
108 pub visibility: Visibility,
110}
111
112impl FieldSpec {
113 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 pub fn doc(mut self, doc: impl Into<String>) -> Self {
127 self.doc = Some(doc.into());
128 self
129 }
130
131 pub fn optional(mut self) -> Self {
133 self.required = false;
134 self
135 }
136
137 pub fn attribute(mut self, attr: AttributeSpec) -> Self {
139 self.attributes.push(attr);
140 self
141 }
142
143 pub fn visibility(mut self, vis: Visibility) -> Self {
145 self.visibility = vis;
146 self
147 }
148
149 pub fn private(mut self) -> Self {
151 self.visibility = Visibility::Private;
152 self
153 }
154}
155
156#[derive(Debug, Clone, PartialEq)]
158pub struct EnumSpec {
159 pub name: String,
161 pub doc: Option<String>,
163 pub variants: Vec<VariantSpec>,
165 pub derives: Vec<String>,
167 pub attributes: Vec<AttributeSpec>,
169 pub visibility: Visibility,
171}
172
173impl EnumSpec {
174 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 pub fn doc(mut self, doc: impl Into<String>) -> Self {
188 self.doc = Some(doc.into());
189 self
190 }
191
192 pub fn variant(mut self, variant: VariantSpec) -> Self {
194 self.variants.push(variant);
195 self
196 }
197
198 pub fn variants(mut self, variants: impl IntoIterator<Item = VariantSpec>) -> Self {
200 self.variants.extend(variants);
201 self
202 }
203
204 pub fn unit_variant(mut self, name: impl Into<String>) -> Self {
206 self.variants.push(VariantSpec::unit(name));
207 self
208 }
209
210 pub fn derive(mut self, name: impl Into<String>) -> Self {
212 self.derives.push(name.into());
213 self
214 }
215
216 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 pub fn attribute(mut self, attr: AttributeSpec) -> Self {
224 self.attributes.push(attr);
225 self
226 }
227
228 pub fn visibility(mut self, vis: Visibility) -> Self {
230 self.visibility = vis;
231 self
232 }
233
234 pub fn private(mut self) -> Self {
236 self.visibility = Visibility::Private;
237 self
238 }
239}
240
241#[derive(Debug, Clone, PartialEq)]
243pub struct VariantSpec {
244 pub name: String,
246 pub doc: Option<String>,
248 pub kind: VariantKind,
250 pub attributes: Vec<AttributeSpec>,
252}
253
254impl VariantSpec {
255 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 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 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 pub fn doc(mut self, doc: impl Into<String>) -> Self {
287 self.doc = Some(doc.into());
288 self
289 }
290
291 pub fn attribute(mut self, attr: AttributeSpec) -> Self {
293 self.attributes.push(attr);
294 self
295 }
296}
297
298#[derive(Debug, Clone, PartialEq)]
300pub enum VariantKind {
301 Unit,
303 Tuple(Vec<TypeRef>),
305 Struct(Vec<FieldSpec>),
307}
308
309#[derive(Debug, Clone, PartialEq)]
311pub struct AttributeSpec {
312 pub path: String,
314 pub args: Vec<AttributeArg>,
316}
317
318impl AttributeSpec {
319 pub fn simple(path: impl Into<String>) -> Self {
321 Self {
322 path: path.into(),
323 args: Vec::new(),
324 }
325 }
326
327 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 pub fn arg(mut self, value: impl Into<String>) -> Self {
337 self.args.push(AttributeArg::Positional(value.into()));
338 self
339 }
340
341 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 pub fn flag(mut self, name: impl Into<String>) -> Self {
350 self.args.push(AttributeArg::Flag(name.into()));
351 self
352 }
353}
354
355#[derive(Debug, Clone, PartialEq)]
357pub enum AttributeArg {
358 Positional(String),
360 Named(String, String),
362 Flag(String),
364}
365
366pub trait StructureRenderer {
371 fn render_struct(&self, spec: &StructSpec) -> String;
373
374 fn render_enum(&self, spec: &EnumSpec) -> String;
376
377 fn render_field(&self, spec: &FieldSpec) -> String;
379
380 fn render_variant(&self, spec: &VariantSpec) -> String;
382
383 fn render_attribute(&self, spec: &AttributeSpec) -> String;
385
386 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}