builderx_core/
lib.rs

1//! Core traits for the builderx DSL (builder-pattern adapters).
2//!
3//! These traits define how the `bx!` macro talks to concrete UI toolkits. Adapters
4//! bridge between a generic builder syntax and a specific “attach child/children”
5//! API that each toolkit exposes.
6//!
7//! ## Picking an integration style
8//! - If you control the builder type (or it already has attach semantics), implement
9//!   [`AttachChild`] / [`AttachChildren`] and use [`DefaultAdapter`] for the most
10//!   ergonomic path—no adapter type needed.
11//! - If the builder is foreign or needs custom glue, implement [`BxAdapter`] +
12//!   [`CanAttach`] / [`CanAttachMany`] on a small adapter type instead.
13
14/// Adapter hook to make the builder DSL agnostic to concrete APIs.
15///
16/// # Examples
17/// Implement a custom adapter that forwards to methods on your builder type:
18/// ```rust
19/// use builderx_core::{BxAdapter, CanAttach, CanAttachMany};
20///
21/// #[derive(Default, Debug, PartialEq)]
22/// struct MyBuilder(Vec<&'static str>);
23///
24/// impl MyBuilder {
25///     fn push_one(mut self, child: &'static str) -> Self {
26///         self.0.push(child);
27///         self
28///     }
29///
30///     fn push_many<I>(mut self, children: I) -> Self
31///     where
32///         I: IntoIterator<Item = &'static str>,
33///     {
34///         self.0.extend(children);
35///         self
36///     }
37/// }
38///
39/// struct MyAdapter;
40///
41/// impl BxAdapter for MyAdapter {}
42///
43/// impl CanAttach<MyBuilder, &'static str> for MyAdapter {
44///     fn do_attach(builder: MyBuilder, child: &'static str) -> MyBuilder {
45///         builder.push_one(child)
46///     }
47/// }
48///
49/// impl<I> CanAttachMany<MyBuilder, I, &'static str> for MyAdapter
50/// where
51///     I: IntoIterator<Item = &'static str>,
52/// {
53///     fn do_attach_many(builder: MyBuilder, children: I) -> MyBuilder {
54///         builder.push_many(children)
55///     }
56/// }
57///
58/// let built = MyAdapter::attach_many(MyAdapter::attach(MyBuilder::default(), "a"), ["b", "c"]);
59/// assert_eq!(built.0, ["a", "b", "c"]);
60/// ```
61pub trait BxAdapter {
62    /// Build or wrap the initial builder for a tag. Override when the underlying
63    /// toolkit requires additional setup on each new element.
64    fn start<B>(builder: B) -> B {
65        builder
66    }
67
68    /// Attach a single child to the builder using the adapter-specific glue.
69    fn attach<B, C>(builder: B, child: C) -> B
70    where
71        Self: CanAttach<B, C>,
72    {
73        <Self as CanAttach<B, C>>::do_attach(builder, child)
74    }
75
76    /// Attach an iterator of children to the builder using the adapter-specific
77    /// glue. Prefer this for spread (`..iter`) children to avoid intermediate
78    /// allocations where possible.
79    fn attach_many<B, I, C>(builder: B, children: I) -> B
80    where
81        Self: CanAttachMany<B, I, C>,
82    {
83        <Self as CanAttachMany<B, I, C>>::do_attach_many(builder, children)
84    }
85}
86
87/// Trait for builders that can accept a single child value. Implement this on
88/// your toolkit’s builder type when you want to opt into the default adapter.
89pub trait AttachChild<C>: Sized {
90    fn attach_child(self, child: C) -> Self;
91}
92
93/// Trait for builders that can accept an iterator of child values. Implement
94/// alongside [`AttachChild`] to handle spread (`..iter`) children efficiently.
95pub trait AttachChildren<C>: Sized {
96    fn attach_children<I>(self, children: I) -> Self
97    where
98        I: IntoIterator<Item = C>;
99}
100
101/// Marker/behavior for adapter-specific single-child support.
102pub trait CanAttach<B, C> {
103    fn do_attach(builder: B, child: C) -> B;
104}
105
106/// Marker/behavior for adapter-specific multi-child support.
107pub trait CanAttachMany<B, I, C> {
108    fn do_attach_many(builder: B, children: I) -> B;
109}
110
111/// Default adapter that delegates to `AttachChild` / `AttachChildren`. Use this
112/// when your builder already implements those extension traits.
113pub struct DefaultAdapter;
114
115impl BxAdapter for DefaultAdapter {}
116
117impl<B, C> CanAttach<B, C> for DefaultAdapter
118where
119    B: AttachChild<C>,
120{
121    #[inline]
122    fn do_attach(builder: B, child: C) -> B {
123        builder.attach_child(child)
124    }
125}
126
127impl<B, I, C> CanAttachMany<B, I, C> for DefaultAdapter
128where
129    B: AttachChildren<C>,
130    I: IntoIterator<Item = C>,
131{
132    #[inline]
133    fn do_attach_many(builder: B, children: I) -> B {
134        builder.attach_children(children)
135    }
136}