From fd62a6064b265678b0da67a53a110fccee6e134c Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 24 Apr 2021 14:04:36 +0200 Subject: Struct support Signed-off-by: Matthias Beyer --- src/backend/dialoguer.rs | 18 +++++ src/backend/mod.rs | 4 ++ src/lib.rs | 166 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+) 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(&self) -> Box>> { Box::new(DialoguerOptionValueBuilder::(std::marker::PhantomData)) } + + fn struct_builder(&self) -> Box> + where T: 'static + BuildableCollection + { + Box::new(DialoguerStructBuilder::(std::marker::PhantomData)) + } } pub struct DialoguerValueBuilder(std::marker::PhantomData); @@ -144,3 +151,14 @@ impl CollectionBuilder for DialoguerVecBuilder } } + +pub struct DialoguerStructBuilder(std::marker::PhantomData); +impl CollectionBuilder for DialoguerStructBuilder + where T: 'static + BuildableCollection +{ + type Output = T; + + fn build_collection(&self, value_desc: &str) -> Result { + 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(&self) -> Box>> where T: 'static + BuildableValue; + + fn struct_builder(&self) -> Box> + where T: 'static + BuildableCollection; } diff --git a/src/lib.rs b/src/lib.rs index 9a89f37..c649ed8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,6 +81,10 @@ mod dummy_bool_test { { unimplemented!() } + + fn struct_builder(&self) -> Box> { + unimplemented!() + } } struct BoolValBuilder; @@ -165,6 +169,9 @@ mod vec_test { { Box::new(VecBuilder::(std::marker::PhantomData)) } + fn struct_builder(&self) -> Box> { + 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> { + Box::new(BoolValBuilder) + } + fn u8_builder(&self) -> Box> { + Box::new(U8ValueBuilder) + } + fn u16_builder(&self) -> Box> { + unimplemented!() + } + fn u32_builder(&self) -> Box> { + unimplemented!() + } + fn u64_builder(&self) -> Box> { + unimplemented!() + } + fn u128_builder(&self) -> Box> { + unimplemented!() + } + fn i8_builder(&self) -> Box> { + unimplemented!() + } + fn i16_builder(&self) -> Box> { + unimplemented!() + } + fn i32_builder(&self) -> Box> { + unimplemented!() + } + fn i64_builder(&self) -> Box> { + unimplemented!() + } + fn i128_builder(&self) -> Box> { + unimplemented!() + } + fn usize_builder(&self) -> Box> { + unimplemented!() + } + fn isize_builder(&self) -> Box> { + unimplemented!() + } + fn f32_builder(&self) -> Box> { + unimplemented!() + } + fn f64_builder(&self) -> Box> { + unimplemented!() + } + fn char_builder(&self) -> Box> { + unimplemented!() + } + fn string_builder(&self) -> Box> { + unimplemented!() + } + fn option_builder(&self) -> Box>> { + unimplemented!() + } + fn vec_builder(&self) -> Box>> + where T: 'static + BuildableValue + { + Box::new(VecBuilder::(std::marker::PhantomData)) + } + + fn struct_builder(&self) -> Box> + where T: 'static + BuildableCollection + { + Box::new(StructBuilder::(std::marker::PhantomData)) + } + } + + struct BoolValBuilder; + impl ValueBuilder for BoolValBuilder { + type Output = bool; + + fn build_value(&self, _question: &str) -> Result { + Ok(true) + } + } + + struct U8ValueBuilder; + impl ValueBuilder for U8ValueBuilder { + type Output = u8; + + fn build_value(&self, _question: &str) -> Result { + Ok(42) + } + } + + pub struct VecBuilder(std::marker::PhantomData); + impl CollectionBuilder for VecBuilder { + type Output = Vec; + + fn build_collection(&self, value_desc: &str) -> Result { + 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(std::marker::PhantomData); + impl CollectionBuilder for StructBuilder { + type Output = T; + + fn build_collection(&self, value_desc: &str) -> Result { + T::builder(DummyBackend).build_collection(value_desc) + } + } + + pub struct Configuration { + verbose: bool, + values: Vec, + } + + impl BuildableCollection for Configuration { + fn builder(_backend: B) -> Box> + where B: Backend + { + Box::new(ConfigStructBuilder) + } + } + + pub struct ConfigStructBuilder; + impl CollectionBuilder for ConfigStructBuilder { + type Output = Configuration; + + fn build_collection(&self, value_desc: &str) -> Result { + println!("Building {}", value_desc); + + let verbose = bool::builder(DummyBackend).build_value(value_desc)?; + let values = Vec::::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]); + } +} -- cgit v1.2.3