openai_rust_sdk/macros/
builder_patterns.rs

1//! Builder pattern macros for reducing boilerplate in builder implementations
2
3/// Macro to generate builder methods for optional string fields
4#[macro_export]
5macro_rules! impl_string_setters {
6    ($($field:ident),* $(,)?) => {
7        $(
8            #[doc = concat!("Set the ", stringify!($field))]
9            pub fn $field<S: Into<String>>(mut self, value: S) -> Self {
10                self.$field = Some(value.into());
11                self
12            }
13        )*
14    };
15}
16
17/// Macro to generate builder methods for optional non-string fields
18#[macro_export]
19macro_rules! impl_option_setters {
20    ($($field:ident: $type:ty),* $(,)?) => {
21        $(
22            #[doc = concat!("Set the ", stringify!($field))]
23            pub fn $field(mut self, value: $type) -> Self {
24                self.$field = Some(value);
25                self
26            }
27        )*
28    };
29}
30
31/// Macro to generate builder methods for vector fields
32#[macro_export]
33macro_rules! impl_vec_setters {
34    ($($field:ident: $type:ty),* $(,)?) => {
35        $(
36            #[doc = concat!("Add a ", stringify!($field))]
37            pub fn $field(mut self, value: $type) -> Self {
38                self.$field.get_or_insert_with(Vec::new).push(value);
39                self
40            }
41
42            #[doc = concat!("Set all ", stringify!($field))]
43            pub fn set_all_$field(mut self, values: Vec<$type>) -> Self {
44                self.$field = Some(values);
45                self
46            }
47        )*
48    };
49}
50
51/// Macro to generate builder methods for `HashMap` fields
52#[macro_export]
53macro_rules! impl_map_setters {
54    ($($field:ident),* $(,)?) => {
55        $(
56            #[doc = concat!("Set the ", stringify!($field))]
57            pub fn $field(mut self, value: std::collections::HashMap<String, String>) -> Self {
58                self.$field = Some(value);
59                self
60            }
61
62            #[doc = concat!("Add a ", stringify!($field), " key-value pair")]
63            pub fn add_$field<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
64                self.$field
65                    .get_or_insert_with(std::collections::HashMap::new)
66                    .insert(key.into(), value.into());
67                self
68            }
69        )*
70    };
71}
72
73/// Macro to generate standard builder `build()` methods with field validation
74///
75/// This macro generates a `build()` method that validates required fields using `ok_or()`
76/// and returns a `Result<T, String>`. It supports both required fields validation and
77/// optional final validation on the constructed object.
78///
79/// # Basic usage with required fields only:
80/// ```rust,ignore
81/// impl_builder_build! {
82///     MyBuilder => MyRequest {
83///         required: [field1: "field1 is required", field2: "field2 is required"],
84///         optional: [opt_field1, opt_field2, opt_field3]
85///     }
86/// }
87/// ```
88///
89/// # Usage with additional validation:
90/// ```rust,ignore  
91/// impl_builder_build! {
92///     MyBuilder => MyRequest {
93///         required: [field1: "field1 is required"],
94///         optional: [opt_field],
95///         validate: true
96///     }
97/// }
98/// ```
99#[macro_export]
100macro_rules! impl_builder_build {
101    // Pattern for builders with required fields, optional fields, and post-construction validation
102    ($builder:ident => $target:ident {
103        required: [$( $req_field:ident: $req_msg:literal ),* $(,)?],
104        optional: [$( $opt_field:ident ),* $(,)?],
105        validate: true
106    }) => {
107        impl $builder {
108            /// Build the request
109            pub fn build(self) -> std::result::Result<$target, String> {
110                $(
111                    let $req_field = self.$req_field.ok_or($req_msg)?;
112                )*
113
114                let request = $target {
115                    $( $req_field, )*
116                    $( $opt_field: self.$opt_field, )*
117                };
118
119                request.validate()?;
120                Ok(request)
121            }
122        }
123    };
124
125    // Pattern for builders with required fields and optional fields (no post-validation)
126    ($builder:ident => $target:ident {
127        required: [$( $req_field:ident: $req_msg:literal ),* $(,)?],
128        optional: [$( $opt_field:ident ),* $(,)?]
129    }) => {
130        impl $builder {
131            /// Build the request
132            pub fn build(self) -> std::result::Result<$target, String> {
133                $(
134                    let $req_field = self.$req_field.ok_or($req_msg)?;
135                )*
136
137                Ok($target {
138                    $( $req_field, )*
139                    $( $opt_field: self.$opt_field, )*
140                })
141            }
142        }
143    };
144
145    // Pattern for builders with only required fields (no optional fields or validation)
146    ($builder:ident => $target:ident {
147        required: [$( $req_field:ident: $req_msg:literal ),* $(,)?]
148    }) => {
149        impl $builder {
150            /// Build the request
151            pub fn build(self) -> std::result::Result<$target, String> {
152                $(
153                    let $req_field = self.$req_field.ok_or($req_msg)?;
154                )*
155
156                Ok($target {
157                    $( $req_field, )*
158                })
159            }
160        }
161    };
162}
163
164/// Macro to generate RunConfigurationBuilder trait implementations
165#[macro_export]
166macro_rules! impl_run_config_builder {
167    ($struct_name:ident) => {
168        impl RunConfigurationBuilder for $struct_name {
169            fn get_model_mut(&mut self) -> &mut Option<String> {
170                &mut self.model
171            }
172
173            fn get_instructions_mut(&mut self) -> &mut Option<String> {
174                &mut self.instructions
175            }
176
177            fn get_tools_mut(
178                &mut self,
179            ) -> &mut Option<Vec<$crate::models::assistants::AssistantTool>> {
180                &mut self.tools
181            }
182
183            fn get_file_ids_mut(&mut self) -> &mut Option<Vec<String>> {
184                &mut self.file_ids
185            }
186
187            fn get_metadata_mut(
188                &mut self,
189            ) -> &mut Option<std::collections::HashMap<String, String>> {
190                &mut self.metadata
191            }
192        }
193    };
194}
195
196/// Macro to generate run builder methods that delegate to RunConfigurationBuilder trait
197#[macro_export]
198macro_rules! impl_run_builder_methods {
199    () => {
200        /// Set the model
201        pub fn model<S: Into<String>>(self, model: S) -> Self {
202            RunConfigurationBuilder::model(self, model)
203        }
204
205        /// Set the instructions
206        pub fn instructions<S: Into<String>>(self, instructions: S) -> Self {
207            RunConfigurationBuilder::instructions(self, instructions)
208        }
209
210        /// Add a tool
211        pub fn tool(self, tool: $crate::models::assistants::AssistantTool) -> Self {
212            RunConfigurationBuilder::tool(self, tool)
213        }
214
215        /// Set tools
216        #[must_use]
217        pub fn tools(self, tools: Vec<$crate::models::assistants::AssistantTool>) -> Self {
218            RunConfigurationBuilder::tools(self, tools)
219        }
220
221        /// Add a file ID
222        pub fn file_id<S: Into<String>>(self, file_id: S) -> Self {
223            RunConfigurationBuilder::file_id(self, file_id)
224        }
225
226        /// Set file IDs
227        #[must_use]
228        pub fn file_ids(self, file_ids: Vec<String>) -> Self {
229            RunConfigurationBuilder::file_ids(self, file_ids)
230        }
231
232        /// Add metadata key-value pair
233        pub fn metadata_pair<K: Into<String>, V: Into<String>>(self, key: K, value: V) -> Self {
234            RunConfigurationBuilder::metadata_pair(self, key, value)
235        }
236
237        /// Set metadata
238        #[must_use]
239        pub fn metadata(self, metadata: std::collections::HashMap<String, String>) -> Self {
240            RunConfigurationBuilder::metadata(self, metadata)
241        }
242    };
243}
244
245/// Macro to generate fluent setter methods for builders
246#[macro_export]
247macro_rules! impl_fluent_setters {
248    (
249        $self:ident;
250        string: [$($string_field:ident),* $(,)?];
251        option: [$($option_field:ident : $option_type:ty),* $(,)?];
252        vec: [$($vec_field:ident : $vec_type:ty),* $(,)?];
253        map: [$($map_field:ident),* $(,)?];
254    ) => {
255        $(
256            /// Set the field (string)
257            pub fn $string_field(mut $self, value: impl Into<String>) -> Self {
258                $self.$string_field = Some(value.into());
259                $self
260            }
261        )*
262
263        $(
264            /// Set the field (option)
265            #[must_use]
266            pub fn $option_field(mut $self, value: $option_type) -> Self {
267                $self.$option_field = Some(value);
268                $self
269            }
270        )*
271
272        $(
273            /// Add to the vector field
274            pub fn $vec_field(mut $self, value: $vec_type) -> Self {
275                if $self.$vec_field.is_none() {
276                    $self.$vec_field = Some(Vec::new());
277                }
278                $self.$vec_field.as_mut().unwrap().push(value);
279                $self
280            }
281
282            /// Set all values for the vector field
283            #[must_use]
284            pub fn set_$vec_field(mut $self, values: Vec<$vec_type>) -> Self {
285                $self.$vec_field = Some(values);
286                $self
287            }
288        )*
289
290        $(
291            /// Set the map field
292            #[must_use]
293            pub fn $map_field(mut $self, value: std::collections::HashMap<String, String>) -> Self {
294                $self.$map_field = Some(value);
295                $self
296            }
297
298            /// Add a key-value pair to the map field
299            pub fn add_$map_field(mut $self, key: impl Into<String>, value: impl Into<String>) -> Self {
300                if $self.$map_field.is_none() {
301                    $self.$map_field = Some(std::collections::HashMap::new());
302                }
303                $self.$map_field
304                    .as_mut()
305                    .unwrap()
306                    .insert(key.into(), value.into());
307                $self
308            }
309        )*
310    };
311}