Skip to main content

rust_pattern_components/
builder.rs

1/// 为构建器模式提供辅助方法的宏。
2///
3/// 此宏为指定的构建器类型添加一个 `when_some` 方法,允许条件性地设置可选值。
4/// 当 `Option<T>` 为 `Some` 时,会调用提供的函数来设置值;当为 `None` 时,直接返回构建器本身。
5///
6/// # 用法
7///
8/// 有两种调用方式:
9/// 1. 为 `Self` 类型实现:
10///    ```rust
11///    use rust_patterns_components::builder_helper;
12///
13///    struct MyBuilder1;
14///    struct MyBuilder2;
15///
16///    builder_helper!(Self, MyBuilder1, MyBuilder2);
17///
18///    // 现在 MyBuilder1 和 MyBuilder2 都有 when_some 方法
19///    ```
20/// 2. 为 `&mut Self` 类型实现:
21///    ```rust
22///    use rust_patterns_components::builder_helper;
23///
24///    struct MyBuilder1;
25///    struct MyBuilder2;
26///
27///    builder_helper!(&mut Self, MyBuilder1, MyBuilder2);
28///
29///    // 现在 MyBuilder1 和 MyBuilder2 都有 when_some 方法
30///    ```
31///
32/// # 生成的方法
33///
34/// 宏会为每个指定的构建器类型生成一个 `when_some` 方法:
35/// ```rust
36/// # use rust_patterns_components::builder_helper;
37/// # struct MyBuilder;
38/// # builder_helper!(Self, MyBuilder);
39/// # impl MyBuilder {
40/// fn when_some<T>(self, value: Option<T>, func: impl FnOnce(Self, T) -> Self) -> Self
41/// where
42///     Self: Sized,
43/// {
44///     match value {
45///         Some(v) => func(self, v),
46///         None => self,
47///     }
48/// }
49/// # }
50/// ```
51///
52/// 或者对于 `&mut Self` 版本:
53/// ```rust
54/// # use rust_patterns_components::builder_helper;
55/// # struct MyBuilder;
56/// # builder_helper!(&mut Self, MyBuilder);
57/// # impl MyBuilder {
58/// fn when_some<T>(&mut self, value: Option<T>, func: impl FnOnce(&mut Self, T) -> &mut Self) -> &mut Self
59/// where
60///     Self: Sized,
61/// {
62///     match value {
63///         Some(v) => func(self, v),
64///         None => self,
65///     }
66/// }
67/// # }
68/// ```
69#[macro_export]
70macro_rules! builder_helper {
71    (@ { $self:ty, $($builder:ty),+ }) => {
72        /// 构建器辅助 trait,提供条件性设置值的方法。
73        trait Builder {
74            #[inline]
75            fn when_some<T>(self: $self, value: Option<T>, func: impl FnOnce($self, T) -> $self) -> $self
76            where
77                Self: Sized,
78            {
79                match value {
80                    Some(v) => func(self, v),
81                    None => self,
82                }
83            }
84        }
85
86        $(impl Builder for $builder {})+
87    };
88
89    (Self, $($builder:ty),+ $(,)?) => {
90        $crate::builder_helper!(@ {Self, $($builder),+});
91    };
92
93    (&mut Self, $($builder:ty),+ $(,)?) => {
94        $crate::builder_helper!(@ {&mut Self, $($builder),+});
95    };
96}
97
98#[cfg(test)]
99mod tests {
100    // 不需要导入 super::*,因为宏已经在当前作用域
101
102    #[test]
103    fn test_builder_helper_self() {
104        // 测试 Self 版本的构建器
105        struct TestBuilder {
106            value: Option<String>,
107            count: Option<u32>,
108        }
109
110        impl TestBuilder {
111            fn new() -> Self {
112                Self {
113                    value: None,
114                    count: None,
115                }
116            }
117
118            fn set_value(mut self, value: String) -> Self {
119                self.value = Some(value);
120                self
121            }
122
123            fn set_count(mut self, count: u32) -> Self {
124                self.count = Some(count);
125                self
126            }
127
128            fn build(self) -> (Option<String>, Option<u32>) {
129                (self.value, self.count)
130            }
131        }
132
133        // 为 TestBuilder 实现 builder_helper
134        builder_helper!(Self, TestBuilder);
135
136        // 测试 when_some 方法
137        let builder = TestBuilder::new()
138            .when_some(Some("test".to_string()), |b, v| b.set_value(v))
139            .when_some(None::<u32>, |b, _| b.set_count(0))
140            .when_some(Some(42), |b, c| b.set_count(c));
141
142        let (value, count) = builder.build();
143        assert_eq!(value, Some("test".to_string()));
144        assert_eq!(count, Some(42));
145    }
146
147    #[test]
148    fn test_builder_helper_mut_self() {
149        // 测试 &mut Self 版本的构建器
150        struct MutTestBuilder {
151            value: Option<String>,
152            count: Option<u32>,
153        }
154
155        impl MutTestBuilder {
156            fn new() -> Self {
157                Self {
158                    value: None,
159                    count: None,
160                }
161            }
162
163            fn set_value(&mut self, value: String) -> &mut Self {
164                self.value = Some(value);
165                self
166            }
167
168            fn set_count(&mut self, count: u32) -> &mut Self {
169                self.count = Some(count);
170                self
171            }
172
173            fn build(&self) -> (Option<String>, Option<u32>) {
174                (self.value.clone(), self.count)
175            }
176        }
177
178        // 为 MutTestBuilder 实现 builder_helper
179        builder_helper!(&mut Self, MutTestBuilder);
180
181        // 测试 when_some 方法
182        let mut builder = MutTestBuilder::new();
183        builder
184            .when_some(Some("mut_test".to_string()), |b, v| b.set_value(v))
185            .when_some(None::<u32>, |b, _| b.set_count(0))
186            .when_some(Some(99), |b, c| b.set_count(c));
187
188        let (value, count) = builder.build();
189        assert_eq!(value, Some("mut_test".to_string()));
190        assert_eq!(count, Some(99));
191    }
192
193    #[test]
194    fn test_builder_helper_multiple_types() {
195        // 测试为多个类型同时实现
196        struct Builder1 {
197            value: Option<String>,
198        }
199
200        struct Builder2 {
201            value: Option<String>,
202        }
203
204        impl Builder1 {
205            fn new() -> Self {
206                Self { value: None }
207            }
208
209            fn set_value(mut self, value: String) -> Self {
210                self.value = Some(value);
211                self
212            }
213
214            fn build(self) -> Option<String> {
215                self.value
216            }
217        }
218
219        impl Builder2 {
220            fn new() -> Self {
221                Self { value: None }
222            }
223
224            fn set_value(mut self, value: String) -> Self {
225                self.value = Some(value);
226                self
227            }
228
229            fn build(self) -> Option<String> {
230                self.value
231            }
232        }
233
234        // 为两个构建器同时实现
235        builder_helper!(Self, Builder1, Builder2);
236
237        // 测试 Builder1
238        let builder1 =
239            Builder1::new().when_some(Some("builder1".to_string()), |b, v| b.set_value(v));
240        assert_eq!(builder1.build(), Some("builder1".to_string()));
241
242        // 测试 Builder2
243        let builder2 =
244            Builder2::new().when_some(Some("builder2".to_string()), |b, v| b.set_value(v));
245        assert_eq!(builder2.build(), Some("builder2".to_string()));
246    }
247
248    #[test]
249    fn test_when_some_with_none() {
250        struct SimpleBuilder {
251            value: Option<String>,
252        }
253
254        impl SimpleBuilder {
255            fn new() -> Self {
256                Self { value: None }
257            }
258
259            fn set_value(mut self, value: String) -> Self {
260                self.value = Some(value);
261                self
262            }
263
264            fn build(self) -> Option<String> {
265                self.value
266            }
267        }
268
269        builder_helper!(Self, SimpleBuilder);
270
271        // 当值为 None 时,应该直接返回构建器而不调用函数
272        let builder = SimpleBuilder::new().when_some(None::<String>, |b, _| {
273            b.set_value("should not be set".to_string())
274        });
275
276        assert_eq!(builder.build(), None);
277    }
278
279    #[test]
280    fn test_when_some_with_some() {
281        struct SimpleBuilder {
282            value: Option<String>,
283        }
284
285        impl SimpleBuilder {
286            fn new() -> Self {
287                Self { value: None }
288            }
289
290            fn set_value(mut self, value: String) -> Self {
291                self.value = Some(value);
292                self
293            }
294
295            fn build(self) -> Option<String> {
296                self.value
297            }
298        }
299
300        builder_helper!(Self, SimpleBuilder);
301
302        // 当值为 Some 时,应该调用函数
303        let builder =
304            SimpleBuilder::new().when_some(Some("test_value".to_string()), |b, v| b.set_value(v));
305
306        assert_eq!(builder.build(), Some("test_value".to_string()));
307    }
308
309    #[test]
310    fn test_chaining_with_when_some() {
311        struct ChainBuilder {
312            value1: Option<String>,
313            value2: Option<String>,
314            count: Option<u32>,
315        }
316
317        impl ChainBuilder {
318            fn new() -> Self {
319                Self {
320                    value1: None,
321                    value2: None,
322                    count: None,
323                }
324            }
325
326            fn set_value1(mut self, value: String) -> Self {
327                self.value1 = Some(value);
328                self
329            }
330
331            fn set_value2(mut self, value: String) -> Self {
332                self.value2 = Some(value);
333                self
334            }
335
336            fn set_count(mut self, count: u32) -> Self {
337                self.count = Some(count);
338                self
339            }
340
341            fn build(self) -> (Option<String>, Option<String>, Option<u32>) {
342                (self.value1, self.value2, self.count)
343            }
344        }
345
346        builder_helper!(Self, ChainBuilder);
347
348        // 测试链式调用
349        let builder = ChainBuilder::new()
350            .set_value1("value1".to_string())
351            .when_some(Some("value2".to_string()), |b, v| b.set_value2(v))
352            .when_some(Some(100), |b, c| b.set_count(c))
353            .when_some(None::<String>, |b, _| b.set_value1("ignored".to_string()));
354
355        let (value1, value2, count) = builder.build();
356        assert_eq!(value1, Some("value1".to_string()));
357        assert_eq!(value2, Some("value2".to_string()));
358        assert_eq!(count, Some(100));
359    }
360}