diff options
-rw-r--r-- | examples/vec.rs | 10 | ||||
-rw-r--r-- | src/backend/dialoguer.rs | 31 | ||||
-rw-r--r-- | src/backend/mod.rs | 6 | ||||
-rw-r--r-- | src/buildable.rs | 21 | ||||
-rw-r--r-- | src/collection_builder.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 158 |
6 files changed, 227 insertions, 1 deletions
diff --git a/examples/vec.rs b/examples/vec.rs new file mode 100644 index 0000000..6aa10c4 --- /dev/null +++ b/examples/vec.rs @@ -0,0 +1,10 @@ +use interactive_object_builder::*; +use interactive_object_builder::backend::dialoguer::DialoguerBackend; + +fn main() -> Result<(), ()> { + let v = Vec::<bool>::builder(DialoguerBackend).build_collection("yes/no flag") + .map_err(|_| ())?; + + println!("{:?}", v); + Ok(()) +} diff --git a/src/backend/dialoguer.rs b/src/backend/dialoguer.rs index 6689250..11d5349 100644 --- a/src/backend/dialoguer.rs +++ b/src/backend/dialoguer.rs @@ -1,5 +1,7 @@ use crate::Backend; use crate::ValueBuilder; +use crate::BuildableValue; +use crate::CollectionBuilder; pub struct DialoguerBackend; @@ -80,6 +82,12 @@ impl Backend for DialoguerBackend { Box::new(DialoguerValueBuilder::<String>(std::marker::PhantomData)) } + fn vec_builder<T>(&self) -> Box<dyn CollectionBuilder<Output = Vec<T>, Error = Self::Error>> + where T: 'static + BuildableValue + { + Box::new(DialoguerVecBuilder::<T>(std::marker::PhantomData)) + } + } pub struct DialoguerValueBuilder<T: Sized>(std::marker::PhantomData<T>); @@ -99,3 +107,26 @@ impl<T> ValueBuilder for DialoguerValueBuilder<T> } +pub struct DialoguerVecBuilder<T: 'static + BuildableValue>(std::marker::PhantomData<T>); +impl<T> CollectionBuilder for DialoguerVecBuilder<T> + where T: 'static + BuildableValue +{ + type Output = Vec<T>; + type Error = DialoguerBackendError; + + fn build_collection(&self, value_desc: &str) -> Result<Self::Output, Self::Error> { + let mut buf = vec![]; + + loop { + let v: T = T::builder(DialoguerBackend).build_value(value_desc)?; + buf.push(v); + + if !dialoguer::Input::<bool>::new().with_prompt("Another one?").interact_text()? { + break + } + } + + Ok(buf) + } +} + diff --git a/src/backend/mod.rs b/src/backend/mod.rs index dfd77c8..1353a6d 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,6 +1,8 @@ pub mod dialoguer; use crate::ValueBuilder; +use crate::BuildableValue; +use crate::CollectionBuilder; /// A backend can be used to get builders for specific types pub trait Backend { @@ -23,6 +25,10 @@ pub trait Backend { fn f64_builder(&self) -> Box<dyn ValueBuilder<Output = f64, Error = Self::Error>>; fn char_builder(&self) -> Box<dyn ValueBuilder<Output = char, Error = Self::Error>>; fn string_builder(&self) -> Box<dyn ValueBuilder<Output = String, Error = Self::Error>>; + + fn vec_builder<T>(&self) -> Box<dyn CollectionBuilder<Output = Vec<T>, Error = Self::Error>> + where T: 'static + BuildableValue + ; } diff --git a/src/buildable.rs b/src/buildable.rs index 22f6d0a..95382e7 100644 --- a/src/buildable.rs +++ b/src/buildable.rs @@ -1,4 +1,5 @@ use crate::ValueBuilder; +use crate::CollectionBuilder; use crate::Backend; // A value that can be built interactively, using a Backend @@ -162,3 +163,23 @@ impl BuildableValue for String { } } + + +pub trait BuildableCollection { + fn builder<E, B>(backend: B) -> Box<dyn CollectionBuilder<Output = Self, Error = E>> + where E: Sized, + B: Backend<Error = E> + ; +} + +impl<T> BuildableCollection for Vec<T> + where T: 'static + BuildableValue +{ + fn builder<E, B>(backend: B) -> Box<dyn CollectionBuilder<Output = Self, Error = E>> + where E: Sized, + B: Backend<Error = E> + { + backend.vec_builder::<T>() + } +} + diff --git a/src/collection_builder.rs b/src/collection_builder.rs index 3535ee2..70c1ae3 100644 --- a/src/collection_builder.rs +++ b/src/collection_builder.rs @@ -5,6 +5,6 @@ pub trait CollectionBuilder { type Output: Sized; type Error: Sized; - fn build_collection(&self) -> Result<Self::Output, Self::Error>; + fn build_collection(&self, value_desc: &str) -> Result<Self::Output, Self::Error>; } @@ -22,6 +22,60 @@ mod dummy_bool_test { fn bool_builder(&self) -> Box<dyn ValueBuilder<Output = bool, Error = Self::Error>> { Box::new(BoolValBuilder) } + fn u8_builder(&self) -> Box<dyn ValueBuilder<Output = u8, Error = Self::Error>> { + unimplemented!() + } + fn u16_builder(&self) -> Box<dyn ValueBuilder<Output = u16, Error = Self::Error>> { + unimplemented!() + } + fn u32_builder(&self) -> Box<dyn ValueBuilder<Output = u32, Error = Self::Error>> { + unimplemented!() + } + fn u64_builder(&self) -> Box<dyn ValueBuilder<Output = u64, Error = Self::Error>> { + unimplemented!() + } + fn u128_builder(&self) -> Box<dyn ValueBuilder<Output = u128, Error = Self::Error>> { + unimplemented!() + } + fn i8_builder(&self) -> Box<dyn ValueBuilder<Output = i8, Error = Self::Error>> { + unimplemented!() + } + fn i16_builder(&self) -> Box<dyn ValueBuilder<Output = i16, Error = Self::Error>> { + unimplemented!() + } + fn i32_builder(&self) -> Box<dyn ValueBuilder<Output = i32, Error = Self::Error>> { + unimplemented!() + } + fn i64_builder(&self) -> Box<dyn ValueBuilder<Output = i64, Error = Self::Error>> { + unimplemented!() + } + fn i128_builder(&self) -> Box<dyn ValueBuilder<Output = i128, Error = Self::Error>> { + unimplemented!() + } + fn usize_builder(&self) -> Box<dyn ValueBuilder<Output = usize, Error = Self::Error>> { + unimplemented!() + } + fn isize_builder(&self) -> Box<dyn ValueBuilder<Output = isize, Error = Self::Error>> { + unimplemented!() + } + fn f32_builder(&self) -> Box<dyn ValueBuilder<Output = f32, Error = Self::Error>> { + unimplemented!() + } + fn f64_builder(&self) -> Box<dyn ValueBuilder<Output = f64, Error = Self::Error>> { + unimplemented!() + } + fn char_builder(&self) -> Box<dyn ValueBuilder<Output = char, Error = Self::Error>> { + unimplemented!() + } + fn string_builder(&self) -> Box<dyn ValueBuilder<Output = String, Error = Self::Error>> { + unimplemented!() + } + + fn vec_builder<T>(&self) -> Box<dyn CollectionBuilder<Output = Vec<T>, Error = Self::Error>> + where T: 'static + BuildableValue + { + unimplemented!() + } } struct BoolValBuilder; @@ -41,3 +95,107 @@ mod dummy_bool_test { } } + +#[cfg(test)] +mod vec_test { + use super::*; + + struct DummyBackend; + impl Backend for DummyBackend { + type Error = (); + + fn bool_builder(&self) -> Box<dyn ValueBuilder<Output = bool, Error = Self::Error>> { + Box::new(BoolValBuilder) + } + fn u8_builder(&self) -> Box<dyn ValueBuilder<Output = u8, Error = Self::Error>> { + unimplemented!() + } + fn u16_builder(&self) -> Box<dyn ValueBuilder<Output = u16, Error = Self::Error>> { + unimplemented!() + } + fn u32_builder(&self) -> Box<dyn ValueBuilder<Output = u32, Error = Self::Error>> { + unimplemented!() + } + fn u64_builder(&self) -> Box<dyn ValueBuilder<Output = u64, Error = Self::Error>> { + unimplemented!() + } + fn u128_builder(&self) -> Box<dyn ValueBuilder<Output = u128, Error = Self::Error>> { + unimplemented!() + } + fn i8_builder(&self) -> Box<dyn ValueBuilder<Output = i8, Error = Self::Error>> { + unimplemented!() + } + fn i16_builder(&self) -> Box<dyn ValueBuilder<Output = i16, Error = Self::Error>> { + unimplemented!() + } + fn i32_builder(&self) -> Box<dyn ValueBuilder<Output = i32, Error = Self::Error>> { + unimplemented!() + } + fn i64_builder(&self) -> Box<dyn ValueBuilder<Output = i64, Error = Self::Error>> { + unimplemented!() + } + fn i128_builder(&self) -> Box<dyn ValueBuilder<Output = i128, Error = Self::Error>> { + unimplemented!() + } + fn usize_builder(&self) -> Box<dyn ValueBuilder<Output = usize, Error = Self::Error>> { + unimplemented!() + } + fn isize_builder(&self) -> Box<dyn ValueBuilder<Output = isize, Error = Self::Error>> { + unimplemented!() + } + fn f32_builder(&self) -> Box<dyn ValueBuilder<Output = f32, Error = Self::Error>> { + unimplemented!() + } + fn f64_builder(&self) -> Box<dyn ValueBuilder<Output = f64, Error = Self::Error>> { + unimplemented!() + } + fn char_builder(&self) -> Box<dyn ValueBuilder<Output = char, Error = Self::Error>> { + unimplemented!() + } + fn string_builder(&self) -> Box<dyn ValueBuilder<Output = String, Error = Self::Error>> { + unimplemented!() + } + fn vec_builder<T>(&self) -> Box<dyn CollectionBuilder<Output = Vec<T>, Error = Self::Error>> + where T: 'static + BuildableValue + { + Box::new(VecBuilder::<T>(std::marker::PhantomData)) + } + } + + struct BoolValBuilder; + impl ValueBuilder for BoolValBuilder { + type Output = bool; + type Error = (); + + fn build_value(&self, _question: &str) -> Result<Self::Output, Self::Error> { + Ok(true) + } + } + + pub struct VecBuilder<T: 'static + BuildableValue>(std::marker::PhantomData<T>); + impl<T: BuildableValue> CollectionBuilder for VecBuilder<T> { + type Output = Vec<T>; + type Error = (); + + fn build_collection(&self, value_desc: &str) -> Result<Self::Output, Self::Error> { + 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) + } + } + + #[test] + fn test_build_vec() { + let v = Vec::<bool>::builder(DummyBackend).build_collection("flag").unwrap(); + assert_eq!(v, vec![true, true, true]); + } +} |