use std::iter::zip; use interim_models::presentation::{DropdownOption, Presentation, RFC_3339_S, TextInputMode}; use serde::Deserialize; use crate::errors::AppError; /// A subset of an HTTP form that represents a [`Presentation`] in its component /// parts. It may be merged into a larger HTTP form using `serde(flatten)`. #[derive(Clone, Debug, Deserialize)] pub(crate) struct PresentationForm { pub(crate) presentation_tag: String, #[serde(default)] pub(crate) dropdown_option_colors: Vec, #[serde(default)] pub(crate) dropdown_option_values: Vec, #[serde(default)] pub(crate) text_input_mode: String, #[serde(default)] pub(crate) timestamp_format: String, } impl TryFrom for Presentation { type Error = AppError; fn try_from(form_value: PresentationForm) -> Result { // Parses the presentation tag into the correct enum variant, but without // meaningful inner value(s). Match arms should all use the // `MyVariant { .. }` pattern to pay attention to only the tag. let presentation_default = Presentation::try_from(form_value.presentation_tag.as_str())?; Ok(match presentation_default { Presentation::Dropdown { .. } => Presentation::Dropdown { allow_custom: false, options: zip( form_value.dropdown_option_colors, form_value.dropdown_option_values, ) .map(|(color, value)| DropdownOption { color, value }) .collect(), }, Presentation::Text { .. } => Presentation::Text { input_mode: TextInputMode::try_from(form_value.text_input_mode.as_str())?, }, Presentation::Timestamp { .. } => Presentation::Timestamp { format: if form_value.timestamp_format.is_empty() { RFC_3339_S.to_owned() } else { form_value.timestamp_format }, }, Presentation::Uuid { .. } => Presentation::Uuid {}, }) } }