This commit is contained in:
Mitchell Marino 2024-03-26 13:30:14 -05:00
parent 857dcec00f
commit a256e58672
5 changed files with 51 additions and 37 deletions

View File

@ -7,26 +7,15 @@ pub mod submit;
pub mod text_area;
pub mod text_input;
pub trait ValidationFn<FD: FormData>: Fn(&FD) -> Result<(), String> + 'static {}
pub trait ParseFn<FD: FormData, C: ControlData>:
Fn(C::ReturnType, &mut FD) -> Result<(), String> + 'static
{
}
pub trait ValidationFn<FDT>: Fn(&FDT) -> Result<(), String> + 'static {}
pub trait ParseFn<CT, FDT>: Fn(&CT) -> Result<FDT, String> + 'static {}
pub trait FieldFn<FD, FDT>: Fn(&mut FD) -> FDT + 'static {}
// implement the trait for all valid types
impl<FD, T> ValidationFn<FD> for T
where
FD: FormData,
T: Fn(&FD) -> Result<(), String> + 'static,
{
}
impl<FDT, T> ValidationFn<FDT> for T where T: Fn(&FDT) -> Result<(), String> + 'static {}
// implement the trait for all valid types
impl<FD, C, T> ParseFn<FD, C> for T
where
FD: FormData,
C: ControlData,
T: Fn(C::ReturnType, &mut FD) -> Result<(), String> + 'static,
{
}
impl<CR, FDT, F> ParseFn<CR, FDT> for F where F: Fn(&CR) -> Result<FDT, String> + 'static {}
// implement the trait for all valid types
impl<FD, FDT, F> FieldFn<FD, FDT> for F where F: Fn(&mut FD) -> FDT + 'static {}
pub trait VanityControlData: 'static {
fn build_control<FS: FormStyle>(fs: &FS, control: ControlRenderData<FS, Self>) -> View;
@ -69,19 +58,23 @@ impl<FS: FormStyle, C: VanityControlData> VanityControlBuilder<FS, C> {
}
}
pub struct ControlBuilder<FD: FormData, FS: FormStyle, C: ControlData> {
pub(crate) parse_fn: Box<dyn ParseFn<FD, C>>,
pub(crate) validation_fn: Box<dyn ValidationFn<FD>>,
pub struct ControlBuilder<FD: FormData, FS: FormStyle, C: ControlData, FDT> {
pub(crate) field_fn: Option<Box<dyn FieldFn<FD, FDT>>>,
pub(crate) parse_fn: Option<Box<dyn ParseFn<C::ReturnType, FDT>>>,
pub(crate) unparse_fn: Option<Box<dyn ParseFn<FDT, C::ReturnType>>>,
pub(crate) validation_fn: Option<Box<dyn ValidationFn<FD>>>,
pub(crate) style_attributes: Vec<FS::StylingAttributes>,
pub(crate) data: C,
}
impl<FD: FormData, FS: FormStyle, C: ControlData> ControlBuilder<FD, FS, C> {
impl<FD: FormData, FS: FormStyle, C: ControlData, FDT> ControlBuilder<FD, FS, C, FDT> {
pub(crate) fn new(data: C) -> Self {
ControlBuilder {
data,
parse_fn: Box::new(|_, _| Ok(())),
validation_fn: Box::new(|_| Ok(())),
field_fn: None,
parse_fn: None,
unparse_fn: None,
validation_fn: None,
style_attributes: Vec::new(),
}
}
@ -103,6 +96,20 @@ impl<FD: FormData, FS: FormStyle, C: ControlData> ControlBuilder<FD, FS, C> {
)
}
// TODO: add method that automatically does the parse and unparse using
// TryInto<C::ReturnValue> and TryFrom<C::ReturnVlaue>
pub fn field_with(
mut self,
field_fn: impl FieldFn<FD, FDT>,
parse_fn: impl ParseFn<C::ReturnType, FDT>,
unparse_fn: impl ParseFn<FDT, C::ReturnType>,
) -> Self {
self.field_fn = Box::new(field_fn);
self.parse_fn = Box::new(parse_fn);
self.unparse_fn = Box::new(unparse_fn);
self
}
pub fn parse_fn(mut self, parse_fn: impl ParseFn<FD, C>) -> Self {
self.parse_fn = Box::new(parse_fn) as Box<dyn ParseFn<FD, C>>;
self
@ -112,7 +119,7 @@ impl<FD: FormData, FS: FormStyle, C: ControlData> ControlBuilder<FD, FS, C> {
mut self,
validation_fn: impl Fn(&FD) -> Result<(), String> + 'static,
) -> Self {
self.validation_fn = Box::new(validation_fn) as Box<dyn ValidationFn<FD>>;
self.validation_fn = Some(Box::new(validation_fn)) as _;
self
}

View File

@ -25,15 +25,17 @@ impl ControlData for SelectData {
}
impl<FD: FormData, FS: FormStyle> FormBuilder<FD, FS> {
pub fn select(
pub fn select<FDT>(
self,
builder: impl Fn(ControlBuilder<FD, FS, SelectData>) -> ControlBuilder<FD, FS, SelectData>,
builder: impl Fn(
ControlBuilder<FD, FS, SelectData, FDT>,
) -> ControlBuilder<FD, FS, SelectData, FDT>,
) -> Self {
self.new_control(builder)
}
}
impl<FD: FormData, FS: FormStyle> ControlBuilder<FD, FS, SelectData> {
impl<FD: FormData, FS: FormStyle, FDT> ControlBuilder<FD, FS, SelectData, FDT> {
pub fn options(mut self, options: Vec<String>) -> Self {
self.data.options = options;
self

View File

@ -24,15 +24,17 @@ impl ControlData for TextAreaData {
}
impl<FD: FormData, FS: FormStyle> FormBuilder<FD, FS> {
pub fn text_area(
pub fn text_area<FDT>(
self,
builder: impl Fn(ControlBuilder<FD, FS, TextAreaData>) -> ControlBuilder<FD, FS, TextAreaData>,
builder: impl Fn(
ControlBuilder<FD, FS, TextAreaData, FDT>,
) -> ControlBuilder<FD, FS, TextAreaData, FDT>,
) -> Self {
self.new_control(builder)
}
}
impl<FD: FormData, FS: FormStyle> ControlBuilder<FD, FS, TextAreaData> {
impl<FD: FormData, FS: FormStyle, FDT> ControlBuilder<FD, FS, TextAreaData, FDT> {
pub fn placeholder(mut self, placeholder: impl ToString) -> Self {
self.data.placeholder = Some(placeholder.to_string());
self

View File

@ -40,15 +40,17 @@ impl ControlData for TextInputData {
}
impl<FD: FormData, FS: FormStyle> FormBuilder<FD, FS> {
pub fn text_input(
pub fn text_input<FDT>(
self,
builder: impl Fn(ControlBuilder<FD, FS, TextInputData>) -> ControlBuilder<FD, FS, TextInputData>,
builder: impl Fn(
ControlBuilder<FD, FS, TextInputData, FDT>,
) -> ControlBuilder<FD, FS, TextInputData, FDT>,
) -> Self {
self.new_control(builder)
}
}
impl<FD: FormData, FS: FormStyle> ControlBuilder<FD, FS, TextInputData> {
impl<FD: FormData, FS: FormStyle, FDT> ControlBuilder<FD, FS, TextInputData, FDT> {
pub fn placeholder(mut self, placeholder: impl ToString) -> Self {
self.data.placeholder = Some(placeholder.to_string());
self

View File

@ -145,9 +145,9 @@ impl<FD: FormData, FS: FormStyle> FormBuilder<FD, FS> {
self
}
pub(crate) fn new_control<C: ControlData + Default>(
pub(crate) fn new_control<C: ControlData + Default, FDT>(
mut self,
builder: impl Fn(ControlBuilder<FD, FS, C>) -> ControlBuilder<FD, FS, C>,
builder: impl Fn(ControlBuilder<FD, FS, C, FDT>) -> ControlBuilder<FD, FS, C, FDT>,
) -> Self {
let control_builder = ControlBuilder::new(C::default());
let control = builder(control_builder);
@ -165,7 +165,7 @@ impl<FD: FormData, FS: FormStyle> FormBuilder<FD, FS> {
full_builder.views.push(view);
}
fn add_control<C: ControlData>(&mut self, control: ControlBuilder<FD, FS, C>) {
fn add_control<C: ControlData, FDT>(&mut self, control: ControlBuilder<FD, FS, C, FDT>) {
let full_builder = match &mut self.inner {
FormBuilderInner::ValidationBuilder { validations } => {
validations.push(control.validation_fn);
@ -199,6 +199,7 @@ impl<FD: FormData, FS: FormStyle> FormBuilder<FD, FS> {
FormBuilderInner::FullBuilder(full_builder) => Form {
fd: full_builder.fd_get,
validations: full_builder.validations,
// TODO: wrap in the style's form wrapper
view: full_builder.views.into_view(),
},
FormBuilderInner::ValidationBuilder { validations } => Form {