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}