pub trait Builder<T> {
fn build(self) -> Result<T, Box<dyn std::error::Error>>;
}
pub trait ValidatedBuilder<T> {
fn validate(&self) -> Result<(), String>;
fn build(self) -> Result<T, Box<dyn std::error::Error>>
where
Self: Sized,
{
self.validate()?;
self.build_unchecked()
}
fn build_unchecked(self) -> Result<T, Box<dyn std::error::Error>>;
}
#[macro_export]
macro_rules! simple_builder {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident {
$($field:ident: $type:ty),* $(,)?
}
impl {
$($method:item)*
}
) => {
$(#[$meta])*
$vis struct $name {
$($field: $type),*
}
impl $name {
pub fn new() -> Self {
Self {
$($field: None),*
}
}
$($method)*
}
impl Default for $name {
fn default() -> Self {
Self::new()
}
}
};
}
#[cfg(test)]
mod tests {
use super::*;
struct TestStruct {
value: String,
}
struct TestBuilder {
value: Option<String>,
}
impl TestBuilder {
fn new() -> Self {
Self { value: None }
}
fn with_value(mut self, value: String) -> Self {
self.value = Some(value);
self
}
}
impl Builder<TestStruct> for TestBuilder {
fn build(self) -> Result<TestStruct, Box<dyn std::error::Error>> {
Ok(TestStruct {
value: self.value.unwrap_or_else(|| "default".to_string()),
})
}
}
#[test]
fn test_builder() {
let builder = TestBuilder::new().with_value("test".to_string());
let result = builder.build().unwrap();
assert_eq!(result.value, "test");
}
}