Skip to main content

scratch_test_model/blocks/
any.rs

1use crate::{
2    _exports::{AsOpcodeUnit, BlockKindError, ParseJsonBlock},
3    attrs::{DoForAttrs, DoForAttrsStrategy},
4    aux::{JsonBlocks, JsonCtx},
5    blocks::{
6        CmpBlockKind, CmpBlockKindUnit, EventBlockKind, EventBlockKindUnit, ExprBlockKind,
7        ExprBlockKindUnit, ExprOrCmpBlockKind, ExprOrCmpBlockKindUnit, StmtBlockKind,
8        StmtBlockKindUnit,
9        procedures::{ProceduresDefinition, ProceduresPrototype},
10    },
11};
12
13/// opcode block type is [`BlockKindUnit`]
14#[derive(Debug, derive_more::From, PartialEq, Clone)]
15pub enum BlockKind {
16    ProceduresDefinition(ProceduresDefinition),
17    ProceduresPrototype(ProceduresPrototype),
18
19    Event(EventBlockKind),
20    ExprCmp(ExprOrCmpBlockKind),
21    Stmt(StmtBlockKind),
22}
23/// main block type is [`BlockKind`]
24#[derive(
25    Debug,
26    derive_more::From,
27    PartialEq,
28    Clone,
29    Copy,
30    derive_more::Display,
31    Eq,
32    PartialOrd,
33    Ord,
34    Hash,
35)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
38#[cfg_attr(feature = "serde", serde(untagged))]
39#[display("{_variant}")]
40pub enum BlockKindUnit {
41    Event(EventBlockKindUnit),
42    ExprCmp(ExprOrCmpBlockKindUnit),
43    Stmt(StmtBlockKindUnit),
44    Proc(ProcKindUnit),
45}
46
47#[cfg(feature = "utoipa")]
48impl utoipa::PartialSchema for BlockKindUnit {
49    fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
50        let inner = [
51            EventBlockKindUnit::schema(),
52            ExprBlockKindUnit::schema(),
53            CmpBlockKindUnit::schema(),
54            StmtBlockKindUnit::schema(),
55            ProcKindUnit::schema(),
56        ];
57
58        use itertools::Itertools;
59        use utoipa::openapi::RefOr;
60        use utoipa::openapi::schema::Schema;
61
62        let enum_values = inner
63            .into_iter()
64            .flat_map(|s| match s {
65                RefOr::T(Schema::Object(o)) => o.enum_values,
66                _ => panic!("unexpected schema kind"),
67            })
68            .flatten()
69            .sorted_by_key(ToString::to_string)
70            .collect_vec();
71
72        let mut object = utoipa::openapi::schema::Object::new();
73        object.enum_values = Some(enum_values);
74        object.description = Some(r#"For more information see <a href="https://marcel-scherzinger.github.io/scratch-test-model/scratch_test_model/blocks/enum.BlockKindUnit.html">BlockKindUnit</a>"#.to_string());
75
76        RefOr::T(Schema::Object(object))
77    }
78}
79#[cfg(feature = "utoipa")]
80impl utoipa::ToSchema for BlockKindUnit {
81    fn name() -> std::borrow::Cow<'static, str> {
82        "BlockKindUnit".into()
83    }
84}
85
86#[derive(
87    Debug,
88    derive_more::From,
89    PartialEq,
90    Clone,
91    Copy,
92    derive_more::Display,
93    Eq,
94    PartialOrd,
95    Ord,
96    Hash,
97)]
98#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
99#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
100#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
101pub enum ProcKindUnit {
102    #[display("procedures_prototype")]
103    #[cfg_attr(feature = "serde", serde(rename = "procedures_prototype"))]
104    ProceduresPrototype,
105    #[display("procedures_definition")]
106    #[cfg_attr(feature = "serde", serde(rename = "procedures_definition"))]
107    ProceduresDefinition,
108}
109
110impl From<ExprBlockKindUnit> for BlockKindUnit {
111    fn from(value: ExprBlockKindUnit) -> Self {
112        Self::ExprCmp(value.into())
113    }
114}
115impl From<CmpBlockKindUnit> for BlockKindUnit {
116    fn from(value: CmpBlockKindUnit) -> Self {
117        Self::ExprCmp(value.into())
118    }
119}
120impl From<ExprBlockKind> for BlockKind {
121    fn from(value: ExprBlockKind) -> Self {
122        Self::ExprCmp(value.into())
123    }
124}
125impl From<CmpBlockKind> for BlockKind {
126    fn from(value: CmpBlockKind) -> Self {
127        Self::ExprCmp(value.into())
128    }
129}
130
131impl AsOpcodeUnit for BlockKind {
132    type OpcodeUnit = BlockKindUnit;
133
134    fn opcode(&self) -> Self::OpcodeUnit {
135        match self {
136            Self::ExprCmp(ExprOrCmpBlockKind::Cmp(u)) => u.opcode().into(),
137            Self::ExprCmp(ExprOrCmpBlockKind::Expr(u)) => u.opcode().into(),
138            Self::Event(u) => u.opcode().into(),
139            Self::Stmt(u) => u.opcode().into(),
140            Self::ProceduresPrototype(_) => BlockKindUnit::Proc(ProcKindUnit::ProceduresPrototype),
141            Self::ProceduresDefinition(_) => {
142                BlockKindUnit::Proc(ProcKindUnit::ProceduresDefinition)
143            }
144        }
145    }
146}
147
148impl BlockKind {
149    pub(crate) fn from_json<'a>(
150        all_blocks: JsonBlocks<'a>,
151        id: &str,
152    ) -> Result<Self, JsonCtx<'a, BlockKindError<'a>>> {
153        use crate::aux::parse_block::ParseJsonBlock;
154
155        Ok(
156            if let Some(opt) = unknown_no_error::<EventBlockKind>(all_blocks, id)? {
157                opt.into()
158            } else if let Some(opt) = unknown_no_error::<CmpBlockKind>(all_blocks, id)? {
159                opt.into()
160            } else if let Some(opt) = unknown_no_error::<ExprBlockKind>(all_blocks, id)? {
161                opt.into()
162            } else if let Some(opt) = unknown_no_error::<ProceduresDefinition>(all_blocks, id)? {
163                opt.into()
164            } else if let Some(opt) = unknown_no_error::<ProceduresPrototype>(all_blocks, id)? {
165                opt.into()
166            } else {
167                let opt = StmtBlockKind::ctx_parse_json_block(all_blocks, id)?;
168                opt.into()
169            },
170        )
171    }
172}
173
174fn unknown_no_error<'a, T: ParseJsonBlock>(
175    all_blocks: JsonBlocks<'a>,
176    id: &str,
177) -> Result<Option<T>, JsonCtx<'a, BlockKindError<'a>>> {
178    match T::ctx_parse_json_block(all_blocks, id) {
179        Err(ctx) => {
180            let (err, json) = ctx.into_inner();
181            if let BlockKindError::UnknownOpcode(_) = err {
182                return Ok(None);
183            }
184            Err(JsonCtx {
185                inner_error: err,
186                json_ctx: json,
187            })
188        }
189        Ok(ok) => Ok(Some(ok)),
190    }
191}
192
193impl<'a, S: DoForAttrsStrategy<'a>> DoForAttrs<'a, S> for BlockKind
194where
195    ExprOrCmpBlockKind: DoForAttrs<'a, S>,
196    StmtBlockKind: DoForAttrs<'a, S>,
197    EventBlockKind: DoForAttrs<'a, S>,
198    ProceduresPrototype: DoForAttrs<'a, S>,
199    ProceduresDefinition: DoForAttrs<'a, S>,
200{
201    fn do_for_attrs(
202        &'a self,
203        inputs: &<S as DoForAttrsStrategy<'a>>::Inputs,
204        outputs: &mut <S as DoForAttrsStrategy<'a>>::Outputs,
205    ) -> Result<(), <S as DoForAttrsStrategy<'a>>::Error> {
206        match self {
207            Self::ExprCmp(b) => b.do_for_attrs(inputs, outputs),
208            Self::Stmt(b) => b.do_for_attrs(inputs, outputs),
209            Self::Event(b) => b.do_for_attrs(inputs, outputs),
210            Self::ProceduresDefinition(b) => b.do_for_attrs(inputs, outputs),
211            Self::ProceduresPrototype(b) => b.do_for_attrs(inputs, outputs),
212        }
213    }
214}