facet_core/types/shape/
shape_builder.rs

1use alloc::alloc::Layout;
2
3use crate::{
4    Attr, ConstTypeId, Def, MarkerTraits, ProxyDef, Shape, ShapeFlags, ShapeLayout, Type,
5    TypeNameFn, TypeOps, TypeOpsDirect, TypeOpsIndirect, TypeParam, VTableDirect, VTableErased,
6    VTableIndirect, Variance,
7};
8
9/// Builder for creating [`Shape`] instances.
10///
11/// This builder provides a convenient way to construct Shape values with
12/// sensible defaults. Many fields can be inferred or have reasonable defaults:
13///
14/// ```ignore
15/// ShapeBuilder::for_sized::<MyType>("MyType")
16///     .def(Def::Scalar)
17///     .vtable(my_vtable)
18///     .build()
19/// ```
20pub struct ShapeBuilder {
21    shape: Shape,
22}
23
24const EMPTY_VESSEL: Shape = Shape {
25    id: ConstTypeId::of::<()>(),
26    layout: ShapeLayout::Sized(Layout::new::<()>()),
27    vtable: VTableErased::Direct(&VTableDirect::empty()),
28    type_ops: None,
29    marker_traits: MarkerTraits::empty(),
30    ty: Type::Undefined,
31    def: Def::Undefined,
32    type_identifier: "‹undefined›",
33    type_params: &[],
34    doc: &[],
35    attributes: &[],
36    type_tag: None,
37    inner: None,
38    type_name: None,
39    proxy: None,
40    variance: Variance::COVARIANT,
41    flags: ShapeFlags::empty(),
42    tag: None,
43    content: None,
44};
45
46impl Shape {
47    /// Create a new builder for a sized type.
48    ///
49    /// The `id` and `layout` are derived from the type parameter.
50    #[inline]
51    pub const fn builder_for_sized<T>(type_identifier: &'static str) -> ShapeBuilder {
52        ShapeBuilder::for_sized::<T>(type_identifier)
53    }
54
55    /// Create a new builder for an unsized type.
56    #[inline]
57    pub const fn builder_for_unsized<T: ?Sized>(type_identifier: &'static str) -> ShapeBuilder {
58        ShapeBuilder::for_unsized::<T>(type_identifier)
59    }
60}
61
62impl ShapeBuilder {
63    /// Create a new builder for a sized type.
64    ///
65    /// The `id` and `layout` are derived from the type parameter.
66    #[inline]
67    pub const fn for_sized<T>(type_identifier: &'static str) -> Self {
68        Self {
69            shape: Shape {
70                id: ConstTypeId::of::<T>(),
71                layout: ShapeLayout::Sized(Layout::new::<T>()),
72                type_identifier,
73                ..EMPTY_VESSEL
74            },
75        }
76    }
77
78    /// Create a new builder for an unsized type.
79    #[inline]
80    pub const fn for_unsized<T: ?Sized>(type_identifier: &'static str) -> Self {
81        Self {
82            shape: Shape {
83                id: ConstTypeId::of::<T>(),
84                layout: ShapeLayout::Unsized,
85                type_identifier,
86                ..EMPTY_VESSEL
87            },
88        }
89    }
90
91    /// Set the vtable (type-erased).
92    #[inline]
93    pub const fn vtable(mut self, vtable: VTableErased) -> Self {
94        self.shape.vtable = vtable;
95        self
96    }
97
98    /// Set the vtable from a direct vtable reference.
99    #[inline]
100    pub const fn vtable_direct(mut self, vtable: &'static VTableDirect) -> Self {
101        self.shape.vtable = VTableErased::Direct(vtable);
102        self
103    }
104
105    /// Set the vtable from an indirect vtable reference.
106    #[inline]
107    pub const fn vtable_indirect(mut self, vtable: &'static VTableIndirect) -> Self {
108        self.shape.vtable = VTableErased::Indirect(vtable);
109        self
110    }
111
112    /// Set the per-type operations (drop, default, clone) using the erased enum.
113    ///
114    /// For generic containers, use this to provide the monomorphized operations
115    /// while sharing the main vtable across all instantiations.
116    #[inline]
117    pub const fn type_ops(mut self, type_ops: TypeOps) -> Self {
118        self.shape.type_ops = Some(type_ops);
119        self
120    }
121
122    /// Set per-type operations for concrete types (uses thin pointers).
123    ///
124    /// Use this for scalars, String, and derived structs/enums.
125    #[inline]
126    pub const fn type_ops_direct(mut self, type_ops: &'static TypeOpsDirect) -> Self {
127        self.shape.type_ops = Some(TypeOps::Direct(type_ops));
128        self
129    }
130
131    /// Set per-type operations for generic containers (uses wide pointers).
132    ///
133    /// Use this for `Vec<T>`, `Option<T>`, `Arc<T>`, etc.
134    #[inline]
135    pub const fn type_ops_indirect(mut self, type_ops: &'static TypeOpsIndirect) -> Self {
136        self.shape.type_ops = Some(TypeOps::Indirect(type_ops));
137        self
138    }
139
140    /// Add a marker trait flag.
141    #[inline]
142    pub const fn add_marker_trait(mut self, trait_flag: MarkerTraits) -> Self {
143        self.shape.marker_traits = self.shape.marker_traits.union(trait_flag);
144        self
145    }
146
147    /// Set all marker traits at once using combined bitflags.
148    #[inline]
149    pub const fn marker_traits(mut self, traits: MarkerTraits) -> Self {
150        self.shape.marker_traits = traits;
151        self
152    }
153
154    /// Mark type as implementing `Eq`.
155    #[inline]
156    pub const fn eq(self) -> Self {
157        self.add_marker_trait(MarkerTraits::EQ)
158    }
159
160    /// Mark type as implementing `Copy`.
161    #[inline]
162    pub const fn copy(self) -> Self {
163        self.add_marker_trait(MarkerTraits::COPY)
164    }
165
166    /// Mark type as implementing `Send`.
167    #[inline]
168    pub const fn send(self) -> Self {
169        self.add_marker_trait(MarkerTraits::SEND)
170    }
171
172    /// Mark type as implementing `Sync`.
173    #[inline]
174    pub const fn sync(self) -> Self {
175        self.add_marker_trait(MarkerTraits::SYNC)
176    }
177
178    /// Mark type as implementing `Unpin`.
179    #[inline]
180    pub const fn unpin(self) -> Self {
181        self.add_marker_trait(MarkerTraits::UNPIN)
182    }
183
184    /// Mark type as implementing `UnwindSafe`.
185    #[inline]
186    pub const fn unwind_safe(self) -> Self {
187        self.add_marker_trait(MarkerTraits::UNWIND_SAFE)
188    }
189
190    /// Mark type as implementing `RefUnwindSafe`.
191    #[inline]
192    pub const fn ref_unwind_safe(self) -> Self {
193        self.add_marker_trait(MarkerTraits::REF_UNWIND_SAFE)
194    }
195
196    /// Set the type.
197    #[inline]
198    pub const fn ty(mut self, ty: Type) -> Self {
199        self.shape.ty = ty;
200        self
201    }
202
203    /// Set the definition.
204    #[inline]
205    pub const fn def(mut self, def: Def) -> Self {
206        self.shape.def = def;
207        self
208    }
209
210    /// Set the type parameters.
211    #[inline]
212    pub const fn type_params(mut self, type_params: &'static [TypeParam]) -> Self {
213        self.shape.type_params = type_params;
214        self
215    }
216
217    /// Set the documentation.
218    #[inline]
219    pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
220        self.shape.doc = doc;
221        self
222    }
223
224    /// Set the attributes.
225    #[inline]
226    pub const fn attributes(mut self, attributes: &'static [Attr]) -> Self {
227        self.shape.attributes = attributes;
228        self
229    }
230
231    /// Set the type tag.
232    #[inline]
233    pub const fn type_tag(mut self, type_tag: &'static str) -> Self {
234        self.shape.type_tag = Some(type_tag);
235        self
236    }
237
238    /// Set the inner shape (for transparent/newtype wrappers).
239    #[inline]
240    pub const fn inner(mut self, inner: &'static Shape) -> Self {
241        self.shape.inner = Some(inner);
242        self
243    }
244
245    /// Set the type name function for formatting generic type names.
246    ///
247    /// For generic types like `Vec<T>`, this function formats the full name
248    /// including type parameters (e.g., `Vec<String>`).
249    #[inline]
250    pub const fn type_name(mut self, type_name: TypeNameFn) -> Self {
251        self.shape.type_name = Some(type_name);
252        self
253    }
254
255    /// Set the container-level proxy for custom serialization/deserialization.
256    ///
257    /// When a proxy is set, the type will be serialized/deserialized through
258    /// the proxy type instead of directly.
259    #[inline]
260    pub const fn proxy(mut self, proxy: &'static ProxyDef) -> Self {
261        self.shape.proxy = Some(proxy);
262        self
263    }
264
265    /// Set the variance function for this type.
266    ///
267    /// For derived types, use `Shape::computed_variance` which walks fields.
268    /// For leaf types, use `Variance::COVARIANT`, `Variance::INVARIANT`, etc.
269    #[inline]
270    pub const fn variance(mut self, variance: fn(&'static Shape) -> Variance) -> Self {
271        self.shape.variance = variance;
272        self
273    }
274
275    /// Set the flags for this shape.
276    #[inline]
277    pub const fn flags(mut self, flags: ShapeFlags) -> Self {
278        self.shape.flags = flags;
279        self
280    }
281
282    /// Mark this enum as untagged.
283    ///
284    /// Untagged enums serialize their content directly without any discriminant.
285    #[inline]
286    pub const fn untagged(mut self) -> Self {
287        self.shape.flags = self.shape.flags.union(ShapeFlags::UNTAGGED);
288        self
289    }
290
291    /// Set the tag field name for internally/adjacently tagged enums.
292    #[inline]
293    pub const fn tag(mut self, tag: &'static str) -> Self {
294        self.shape.tag = Some(tag);
295        self
296    }
297
298    /// Set the content field name for adjacently tagged enums.
299    #[inline]
300    pub const fn content(mut self, content: &'static str) -> Self {
301        self.shape.content = Some(content);
302        self
303    }
304
305    /// Build the Shape.
306    ///
307    /// If `ty` was not explicitly set (still `Type::Undefined`), it will be
308    /// inferred from `def`.
309    #[inline]
310    pub const fn build(self) -> Shape {
311        let ty = match self.shape.ty {
312            Type::Undefined => self.shape.def.default_type(),
313            ty => ty,
314        };
315
316        Shape { ty, ..self.shape }
317    }
318}