1use crate::errors::{BuildError, ValidationError};
2pub mod implementations;
3
4pub trait Validate {
7 fn validate(self) -> Result<Self, ValidationError> where Self: Sized;
8}
9
10pub trait AddField<T> {
14 fn add_field(&mut self, field: T);
15}
16
17pub trait BackIntoBuilder<T: crate::builder::Validate, U: ParentBuilder + BackIntoBuilder<T, U>> {
20 fn add_field(self, field: T) -> Self;
21 fn sub_builder_from(self, body: T) -> Builder<T, U>;
22}
23
24pub struct Builder<T, U>
27 where T: Validate,
28 U: ParentBuilder
29{
30 pub(crate) body: T,
31 pub(crate) parent_builder: Option<U>
32}
33
34pub struct Nil;
35
36pub trait ParentBuilder {}
38
39impl ParentBuilder for Nil {}
42
43impl<T: Validate, U: ParentBuilder> ParentBuilder for Builder<T, U> {}
44
45pub trait Buildable<T> {
46 fn build(self) -> Result<T, BuildError>;
47}
48
49impl<T: Validate> Buildable<T> for Builder<T, Nil> {
51 fn build(self) -> Result<T, BuildError> {
52 match self.body.validate() {
53 Ok(body) => Ok(body),
54 Err(_) => Err(BuildError)
55 }
56 }
57}
58
59impl<T: Validate, V: ParentBuilder + BackIntoBuilder<T, V>> Buildable<V> for Builder<T, V> {
63 fn build(self) -> Result<V, BuildError> {
64 match self.body.validate() {
65 Ok(body) => {
66 Ok(self.parent_builder.unwrap().add_field(body))
67 },
68 Err(_) => Err(BuildError)
69 }
70 }
71}
72
73impl<V: AddField<T> + Validate, U: ParentBuilder, T: Validate> BackIntoBuilder<T, Builder<V, U>> for Builder<V, U> {
76 fn add_field(mut self, field: T) -> Self {
77 self.body.add_field(field);
78
79 self
80 }
81
82 fn sub_builder_from(self, body: T) -> Builder<T, Builder<V, U>> {
83 Builder {
84 body,
85 parent_builder: Some(self),
86 }
87 }
88}
89
90impl<T: Validate> From<T> for Builder<T, Nil> {
93 fn from(body: T) -> Self {
94 Builder {
95 body,
96 parent_builder: None::<Nil>
97 }
98 }
99}
100
101#[cfg(test)]
102mod builder_tests {
103 use super::*;
104 use square_ox_derive::Builder;
105
106 #[tokio::test]
107 async fn test_derive() {
108 #[derive(Default, Debug, Builder)]
109 struct Example {
110 #[builder_into]
111 field_0: String,
112 field_1: Option<i32>,
113 #[builder_into]
114 field_2: Option<String>
115 }
116
117 let sut = Builder::from(Example::default())
118 .field_0("a real String".to_string())
119 .field_1(54)
120 .field_2("just a &str")
121 .build();
122
123 assert!(sut.is_ok())
124 }
125}