Skip to main content

scratch_test_model/attrs/dropdowns/
dropdown_menu_of.rs

1use super::AnyDropdownOf;
2use crate::{
3    _exports::ParseJsonBlock,
4    attrs::{AttributeContentError as A, ParseJsonBlockAttribute},
5};
6
7/// This defines a strategy how to parse a dropdown menu block
8/// that should hold values of type `For`.
9///
10/// This trait is generic so that a strategy can support multiple option sets.
11/// It's meant as a separate strategy type so that one and the same value set
12/// can be parsed in multiple ways.
13pub trait ExtraMenuDropdownParseStrat<For> {
14    const VALID_HINT: &'static str;
15    type MenuBlock: ParseJsonBlock;
16
17    /// Converts an external menu block to the requested value set type `For`.
18    ///
19    /// If it is an invalid value the function shall return a [`String`]
20    /// representing the found value that is considered invalid
21    fn from_menu_block(block: Self::MenuBlock) -> Result<For, String>
22    where
23        Self: Sized;
24}
25
26// represents a dropdown where an extra menu block is introduced as indirection
27#[derive(Debug, PartialEq, Clone, derive_more::Deref)]
28pub struct DropdownMenuOf<T, S = T> {
29    #[deref]
30    data: AnyDropdownOf<T>,
31    marker: std::marker::PhantomData<S>,
32}
33
34impl<T, S: ExtraMenuDropdownParseStrat<T>> ParseJsonBlockAttribute for DropdownMenuOf<T, S> {
35    fn parse_json_block_attr_without_expecting_shadow<'a>(
36        all_target_blocks: crate::_exports::JsonBlocks<'a>,
37        attribute_value: &'a serde_json::Value,
38    ) -> Result<Self, crate::aux::errors::AttributeContentError<'a>>
39    where
40        Self: Sized,
41    {
42        if let Some(block_reference) = attribute_value.as_str() {
43            let block = S::MenuBlock::ctx_parse_json_block(all_target_blocks, block_reference)
44                .map_err(|b| A::Subblock(b.into()))?;
45            let selected = S::from_menu_block(block);
46
47            let value = selected.map_err(|invalid| A::InvalidOptionForDropdown {
48                invalid,
49                hint_list: S::VALID_HINT,
50            })?;
51            let any_dropdown = AnyDropdownOf(value);
52            Ok(Self {
53                data: any_dropdown,
54                marker: std::marker::PhantomData,
55            })
56        } else {
57            Err(A::ExternalDropdownMenuReferenceNotString(attribute_value))
58        }
59    }
60}