diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2021-04-24 14:04:36 +0200 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2021-04-24 17:18:01 +0200 |
commit | fd62a6064b265678b0da67a53a110fccee6e134c (patch) | |
tree | a1259db85ae57dbed51cfccbcad4ba6079d45034 | |
parent | fb2bc2e64cda462a8be0acb19863796647d180d6 (diff) |
Struct support
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r-- | src/backend/dialoguer.rs | 18 | ||||
-rw-r--r-- | src/backend/mod.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 166 |
3 files changed, 188 insertions, 0 deletions
diff --git a/src/backend/dialoguer.rs b/src/backend/dialoguer.rs index ec1f5b8..6b08507 100644 --- a/src/backend/dialoguer.rs +++ b/src/backend/dialoguer.rs @@ -1,6 +1,7 @@ use crate::error::Result; use crate::Backend; use crate::BuildableValue; +use crate::BuildableCollection; use crate::CollectionBuilder; use crate::ValueBuilder; @@ -84,6 +85,12 @@ impl Backend for DialoguerBackend { fn option_builder<T: 'static + BuildableValue>(&self) -> Box<dyn CollectionBuilder<Output = Option<T>>> { Box::new(DialoguerOptionValueBuilder::<T>(std::marker::PhantomData)) } + + fn struct_builder<T>(&self) -> Box<dyn CollectionBuilder<Output = T>> + where T: 'static + BuildableCollection + { + Box::new(DialoguerStructBuilder::<T>(std::marker::PhantomData)) + } } pub struct DialoguerValueBuilder<T: Sized>(std::marker::PhantomData<T>); @@ -144,3 +151,14 @@ impl<T> CollectionBuilder for DialoguerVecBuilder<T> } } + +pub struct DialoguerStructBuilder<T: 'static + BuildableCollection>(std::marker::PhantomData<T>); +impl<T> CollectionBuilder for DialoguerStructBuilder<T> + where T: 'static + BuildableCollection +{ + type Output = T; + + fn build_collection(&self, value_desc: &str) -> Result<Self::Output> { + T::builder(DialoguerBackend).build_collection(value_desc) + } +} diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 5884726..bd5bc58 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,6 +1,7 @@ pub mod dialoguer; use crate::BuildableValue; +use crate::BuildableCollection; use crate::CollectionBuilder; use crate::ValueBuilder; @@ -28,6 +29,9 @@ pub trait Backend { fn vec_builder<T>(&self) -> Box<dyn CollectionBuilder<Output = Vec<T>>> where T: 'static + BuildableValue; + + fn struct_builder<T>(&self) -> Box<dyn CollectionBuilder<Output = T>> + where T: 'static + BuildableCollection; } @@ -81,6 +81,10 @@ mod dummy_bool_test { { unimplemented!() } + + fn struct_builder<T: Sized>(&self) -> Box<dyn CollectionBuilder<Output = T>> { + unimplemented!() + } } struct BoolValBuilder; @@ -165,6 +169,9 @@ mod vec_test { { Box::new(VecBuilder::<T>(std::marker::PhantomData)) } + fn struct_builder<T: Sized>(&self) -> Box<dyn CollectionBuilder<Output = T>> { + unimplemented!() + } } struct BoolValBuilder; @@ -202,3 +209,162 @@ mod vec_test { assert_eq!(v, vec![true, true, true]); } } + + +#[cfg(test)] +mod struct_test { + use super::*; + + struct DummyBackend; + impl Backend for DummyBackend { + fn bool_builder(&self) -> Box<dyn ValueBuilder<Output = bool>> { + Box::new(BoolValBuilder) + } + fn u8_builder(&self) -> Box<dyn ValueBuilder<Output = u8>> { + Box::new(U8ValueBuilder) + } + fn u16_builder(&self) -> Box<dyn ValueBuilder<Output = u16>> { + unimplemented!() + } + fn u32_builder(&self) -> Box<dyn ValueBuilder<Output = u32>> { + unimplemented!() + } + fn u64_builder(&self) -> Box<dyn ValueBuilder<Output = u64>> { + unimplemented!() + } + fn u128_builder(&self) -> Box<dyn ValueBuilder<Output = u128>> { + unimplemented!() + } + fn i8_builder(&self) -> Box<dyn ValueBuilder<Output = i8>> { + unimplemented!() + } + fn i16_builder(&self) -> Box<dyn ValueBuilder<Output = i16>> { + unimplemented!() + } + fn i32_builder(&self) -> Box<dyn ValueBuilder<Output = i32>> { + unimplemented!() + } + fn i64_builder(&self) -> Box<dyn ValueBuilder<Output = i64>> { + unimplemented!() + } + fn i128_builder(&self) -> Box<dyn ValueBuilder<Output = i128>> { + unimplemented!() + } + fn usize_builder(&self) -> Box<dyn ValueBuilder<Output = usize>> { + unimplemented!() + } + fn isize_builder(&self) -> Box<dyn ValueBuilder<Output = isize>> { + unimplemented!() + } + fn f32_builder(&self) -> Box<dyn ValueBuilder<Output = f32>> { + unimplemented!() + } + fn f64_builder(&self) -> Box<dyn ValueBuilder<Output = f64>> { + unimplemented!() + } + fn char_builder(&self) -> Box<dyn ValueBuilder<Output = char>> { + unimplemented!() + } + fn string_builder(&self) -> Box<dyn ValueBuilder<Output = String>> { + unimplemented!() + } + fn option_builder<T: 'static + BuildableValue>(&self) -> Box<dyn CollectionBuilder<Output = Option<T>>> { + unimplemented!() + } + fn vec_builder<T>(&self) -> Box<dyn CollectionBuilder<Output = Vec<T>>> + where T: 'static + BuildableValue + { + Box::new(VecBuilder::<T>(std::marker::PhantomData)) + } + + fn struct_builder<T>(&self) -> Box<dyn CollectionBuilder<Output = T>> + where T: 'static + BuildableCollection + { + Box::new(StructBuilder::<T>(std::marker::PhantomData)) + } + } + + struct BoolValBuilder; + impl ValueBuilder for BoolValBuilder { + type Output = bool; + + fn build_value(&self, _question: &str) -> Result<Self::Output> { + Ok(true) + } + } + + struct U8ValueBuilder; + impl ValueBuilder for U8ValueBuilder { + type Output = u8; + + fn build_value(&self, _question: &str) -> Result<Self::Output> { + Ok(42) + } + } + + pub struct VecBuilder<T: 'static + BuildableValue>(std::marker::PhantomData<T>); + impl<T: BuildableValue> CollectionBuilder for VecBuilder<T> { + type Output = Vec<T>; + + fn build_collection(&self, value_desc: &str) -> Result<Self::Output> { + let mut buf = vec![]; + + loop { + let v: T = T::builder(DummyBackend).build_value(value_desc)?; + buf.push(v); + + if buf.len() == 3 { + break + } + } + + Ok(buf) + } + } + + pub struct StructBuilder<T: BuildableCollection>(std::marker::PhantomData<T>); + impl<T: BuildableCollection> CollectionBuilder for StructBuilder<T> { + type Output = T; + + fn build_collection(&self, value_desc: &str) -> Result<Self::Output> { + T::builder(DummyBackend).build_collection(value_desc) + } + } + + pub struct Configuration { + verbose: bool, + values: Vec<u8>, + } + + impl BuildableCollection for Configuration { + fn builder<B>(_backend: B) -> Box<dyn CollectionBuilder<Output = Self>> + where B: Backend + { + Box::new(ConfigStructBuilder) + } + } + + pub struct ConfigStructBuilder; + impl CollectionBuilder for ConfigStructBuilder { + type Output = Configuration; + + fn build_collection(&self, value_desc: &str) -> Result<Self::Output> { + println!("Building {}", value_desc); + + let verbose = bool::builder(DummyBackend).build_value(value_desc)?; + let values = Vec::<u8>::builder(DummyBackend).build_collection(value_desc)?; + + Ok(Configuration { + verbose, + values, + }) + } + } + + #[test] + fn test_struct() { + let c = Configuration::builder(DummyBackend).build_collection("config").unwrap(); + assert!(c.verbose); + assert_eq!(c.values, [42, 42, 42]); + } +} |