rs_sb3/
block.rs

1//! Module to deal with Scratch block
2
3use crate::prelude::*;
4use serde_tuple::{Deserialize_tuple, Serialize_tuple};
5use utils::{deserialize_json_str, serialize_json_str};
6
7/// Scratch scripting block
8#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
9#[serde(rename_all = "camelCase")]
10pub struct BlockNormal {
11    /// A string naming the block.
12    pub opcode: OpCode,
13
14    /// Wiki says nothing about this, probably comment id that this block attached to.
15    #[serde(default, skip_serializing_if = "Option::is_none")]
16    pub comment: Option<Uid>,
17
18    /// The Id of the next block or null.
19    pub next: Option<Uid>,
20
21    /// If the block is a stack block and is preceded, this is the Id of the preceding block.
22    /// If the block is the first stack block in a C mouth, this is the Id of the C block.
23    /// If the block is an input to another block, this is the Id of that other block.
24    /// Otherwise it is none.
25    pub parent: Option<Uid>,
26
27    /// See [`BlockInput`]
28    pub inputs: StringHashMap<BlockInput>,
29
30    /// See [`BlockField`]
31    pub fields: StringHashMap<BlockField>,
32
33    /// True if this is a shadow block and false otherwise.
34    pub shadow: bool,
35
36    /// False if the block has a parent and true otherwise.
37    pub top_level: bool,
38
39    /// Mutations are present some blocks that has a certain opcode.
40    /// See [`BlockMutationEnum`] for availiable mutations.
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub mutation: Option<BlockMutation>,
43
44    /// X Position of the top level block.
45    #[serde(skip_serializing_if = "Option::is_none", default)]
46    pub x: Option<Number>,
47
48    /// Y Position of the top level block.
49    #[serde(skip_serializing_if = "Option::is_none", default)]
50    pub y: Option<Number>,
51}
52
53/// This is a reporter of list or variable when it's at the top.
54#[derive(Debug, PartialEq, Clone, Deserialize_tuple, Serialize_tuple)]
55pub struct BlockVarListReporterTop {
56    pub kind: ListOrVariable,
57    /// Name of the variable
58    pub name: Name,
59    /// Id of the variable
60    pub id: Uid,
61    /// Position X of the reporter
62    pub x: Number,
63    /// Position y of the reporter
64    pub y: Number,
65}
66
67#[derive(Debug, PartialEq, Clone)]
68pub enum ListOrVariable {
69    Variable,
70    List,
71}
72
73#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
74#[serde(untagged)]
75pub enum Block {
76    Normal(BlockNormal),
77    VarList(BlockVarListReporterTop),
78}
79
80/// A struct representing inputs into which other blocks may be dropped, including C mouths.
81/// idk if is this possible without vec
82#[derive(Debug, Default, Clone, PartialEq)]
83pub struct BlockInput {
84    /// See [`ShadowInputType`]
85    pub shadow: ShadowInputType,
86
87    /// Inputs
88    pub inputs: Vec<Option<UidOrValue>>,
89}
90
91/// Used for [`BlockInput`]
92/// When the input could be either [`Uid`] or [`BlockInputValue`]
93#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
94#[serde(untagged)]
95pub enum UidOrValue {
96    /// When it's [`Uid`]
97    Uid(Uid),
98    /// When it's [`BlockInputValue`]
99    Value(BlockInputValue),
100}
101
102/// Field of the block
103#[derive(Debug, Clone, PartialEq)]
104pub enum BlockField {
105    /// Field when Id are sometimes needed
106    WithId {
107        /// Value of the field
108        value: Value,
109
110        /// For certain fields,
111        /// such as variable and broadcast dropdown menus,
112        /// there is also a second element, which is the Id of the field's value.
113        id: Option<Uid>,
114    },
115    /// Field with no Id needed
116    NoId {
117        /// Value of the field
118        value: Value,
119    },
120}
121
122/// Mutation for procedural block (custom block) or stop block
123#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
124#[serde(rename_all = "camelCase")]
125pub struct BlockMutation {
126    /// Always equal to "mutation".
127    /// Don't know if there any other tag
128    /// Wiki says there's only "mutation" though
129    pub tag_name: String,
130
131    /// Seems to always be an empty array.
132    pub children: Vec<Json>,
133
134    /// See [`BlockMutationEnum`]
135    #[serde(flatten)]
136    pub mutation_enum: BlockMutationEnum,
137}
138
139/// Different mutation has different properties.
140/// This enum define them.
141#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
142#[serde(untagged)]
143pub enum BlockMutationEnum {
144    /// opcode is `"procedures_prototype"` mutations have the following additional properties
145    ProceduresPrototype {
146        /// The name of the custom block, including inputs: %s for string/number inputs and %b for boolean inputs.
147        proccode: String,
148
149        /// An array of the ids of the arguments; these can also be found in the input property of the main block.
150        #[serde(
151            deserialize_with = "deserialize_json_str",
152            serialize_with = "serialize_json_str"
153        )]
154        argumentids: Vec<Uid>,
155
156        /// An array of the names of the arguments.
157        #[serde(
158            deserialize_with = "deserialize_json_str",
159            serialize_with = "serialize_json_str"
160        )]
161        argumentnames: Vec<Name>,
162
163        /// An array of the defaults of the arguments.
164        ///  - String default is an empty string
165        ///  - bool default is `false`
166        #[serde(
167            deserialize_with = "deserialize_json_str",
168            serialize_with = "serialize_json_str"
169        )]
170        argumentdefaults: Vec<ValueWithBool>,
171
172        /// Whether to run the block without screen refresh or not.
173        #[serde(
174            deserialize_with = "deserialize_json_str",
175            serialize_with = "serialize_json_str"
176        )]
177        warp: Option<bool>,
178    },
179
180    /// opcode is `"procedures_call"` mutations have the following additional properties
181    ProceduresCall {
182        /// The name of the custom block, including inputs: %s for string/number inputs and %b for boolean inputs.
183        proccode: String,
184
185        /// An array of the ids of the arguments; these can also be found in the input property of the main block.
186        #[serde(
187            deserialize_with = "deserialize_json_str",
188            serialize_with = "serialize_json_str"
189        )]
190        argumentids: Vec<Uid>,
191
192        /// Whether to run the block without screen refresh or not.
193        #[serde(
194            deserialize_with = "deserialize_json_str",
195            serialize_with = "serialize_json_str"
196        )]
197        warp: Option<bool>,
198    },
199
200    /// opcode is `"control_stop"` mutations have the following additional property
201    ControlStop {
202        /// Whether the block has a block following it or not
203        ///  - false for stop all and stop all in sprite
204        ///  - true for stop other scripts in sprite)
205        #[serde(
206            deserialize_with = "deserialize_json_str",
207            serialize_with = "serialize_json_str"
208        )]
209        hasnext: bool,
210    },
211}
212
213/// Shadow enum for [`BlockInput`]
214///
215/// Shadow is area inside block input/arg/param or whatever you wanted to call it.
216/// It's consisting of:
217///  - raw input field where you just type stuff in and optionally can put a reporter in
218///  - menu that you can choose but cannot put a reporter in
219///  - menu that you can chose and optionally can put a reporter in
220///  - or others I might not catch while developing this
221///
222/// This documentation might not be completed or is completed, idk.
223/// Scratch wiki didn't tell anything about this.
224#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize_repr, Serialize_repr)]
225#[repr(u8)]
226pub enum ShadowInputType {
227    /// There is a shadow
228    Shadow = 1,
229
230    /// There is no shadow
231    #[default]
232    NoShadow = 2,
233
234    /// There is a shadow but obscured by the input.
235    /// The shadow is obscured when reporter is inserted.
236    ShadowObscured = 3,
237}
238
239/// Input of the BlockInput
240#[derive(Debug, Clone, PartialEq)]
241pub enum BlockInputValue {
242    /// Number input
243    Number {
244        /// The value
245        value: Value,
246    },
247
248    /// Postive number input
249    PositiveNumber {
250        /// The value
251        value: Value,
252    },
253
254    /// Postive integer input
255    PositiveInteger {
256        /// The value
257        value: Value,
258    },
259
260    /// Integer input
261    Integer {
262        /// The value
263        value: Value,
264    },
265
266    /// Angle input
267    Angle {
268        /// The value
269        value: Value,
270    },
271
272    /// Color input
273    Color {
274        /// Value, a `#` followed by a hexadecimal numeral representing the color
275        value: Value,
276    },
277
278    /// String input
279    String {
280        /// The value
281        value: Value,
282    },
283
284    /// Broadcast input
285    Broadcast {
286        /// Name of the broadcast
287        name: Name,
288
289        /// Id of the broadcast
290        id: Uid,
291    },
292
293    /// Variable input
294    Variable {
295        /// Name of the variable
296        name: Name,
297        /// Id of the variable
298        id: Uid,
299    },
300
301    /// List input
302    List {
303        /// Name of the list
304        name: Name,
305        /// Id of the list
306        id: Uid,
307    },
308}
309
310impl Default for BlockNormal {
311    /// This create new block that act like it's a top most block
312    fn default() -> Self {
313        BlockNormal {
314            opcode: OpCode::default(),
315            comment: None,
316            next: None,
317            parent: None,
318            inputs: StringHashMap::default(),
319            fields: StringHashMap::default(),
320            shadow: false,
321            top_level: true,
322            mutation: None,
323            x: Some(0.into()),
324            y: Some(0.into()),
325        }
326    }
327}
328
329// Serde impl ==================================================================
330
331macro_rules! list_or_variable_vistor_types {
332    ($($fn_name:ident, $ty:ty, $sign:ident, $unexpty:ty;)*) => {
333        $(
334            fn $fn_name<E>(self, v: $ty) -> Result<Self::Value, E>
335            where
336                E: serde::de::Error,
337            {
338                match v {
339                    12 => Ok(ListOrVariable::Variable),
340                    13 => Ok(ListOrVariable::List),
341                    v => Err(E::invalid_value(
342                        Unexpected::$sign(v as $unexpty),
343                        &"12 for variable, 13 for list",
344                    )),
345                }
346            }
347        )*
348    };
349}
350
351struct ListOrVariableVisitor;
352
353impl<'de> Visitor<'de> for ListOrVariableVisitor {
354    type Value = ListOrVariable;
355
356    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
357        formatter.write_str("12 for variable, 13 for list")
358    }
359
360    list_or_variable_vistor_types! {
361        visit_i8, i8, Signed, i64;
362        visit_i16, i16, Signed, i64;
363        visit_i32, i32, Signed, i64;
364        visit_i64, i64, Signed, i64;
365
366        visit_u8, u8, Unsigned, u64;
367        visit_u16, u16, Unsigned, u64;
368        visit_u32, u32, Unsigned, u64;
369        visit_u64, u64, Unsigned, u64;
370    }
371}
372
373impl<'de> Deserialize<'de> for ListOrVariable {
374    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
375    where
376        D: Deserializer<'de>,
377    {
378        deserializer.deserialize_i64(ListOrVariableVisitor)
379    }
380}
381
382impl Serialize for ListOrVariable {
383    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
384    where
385        S: Serializer,
386    {
387        serializer.serialize_i64(match self {
388            ListOrVariable::Variable => 12,
389            ListOrVariable::List => 13,
390        })
391    }
392}
393
394impl BlockInput {
395    /// Use for serializing
396    fn size_hint(&self) -> usize {
397        1 + self.inputs.len()
398    }
399}
400
401struct BlockInputVisitor;
402
403impl<'de> Visitor<'de> for BlockInputVisitor {
404    type Value = BlockInput;
405
406    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
407        formatter.write_str("list that is a block input")
408    }
409
410    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
411    where
412        A: serde::de::SeqAccess<'de>,
413    {
414        use serde::de::Error;
415
416        let shadow = seq.next_element::<ShadowInputType>()?.ok_or_else(|| {
417            A::Error::invalid_length(0, &"Expected 2 or more elements for block input")
418        })?;
419
420        let mut inputs = vec![];
421        while let Some(v) = seq.next_element::<Option<UidOrValue>>()? {
422            inputs.push(v)
423        }
424
425        Ok(BlockInput { shadow, inputs })
426    }
427}
428
429impl<'de> Deserialize<'de> for BlockInput {
430    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
431    where
432        D: Deserializer<'de>,
433    {
434        deserializer.deserialize_seq(BlockInputVisitor)
435    }
436}
437
438impl Serialize for BlockInput {
439    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
440    where
441        S: Serializer,
442    {
443        use serde::ser::SerializeSeq;
444        let mut s = serializer.serialize_seq(Some(self.size_hint()))?;
445        s.serialize_element(&self.shadow)?;
446        for v in &self.inputs {
447            s.serialize_element(&v)?;
448        }
449        s.end()
450    }
451}
452
453impl BlockInputValue {
454    fn get_id(&self) -> u8 {
455        use BlockInputValue::*;
456
457        match self {
458            Number { value: _ } => 4,
459            PositiveNumber { value: _ } => 5,
460            PositiveInteger { value: _ } => 6,
461            Integer { value: _ } => 7,
462            Angle { value: _ } => 8,
463            Color { value: _ } => 9,
464            String { value: _ } => 10,
465            Broadcast { name: _, id: _ } => 11,
466            Variable { name: _, id: _ } => 12,
467            List { name: _, id: _ } => 13,
468        }
469    }
470
471    fn hint_size(&self) -> usize {
472        use BlockInputValue::*;
473
474        match self {
475            Number { value: _ } => 1,
476            PositiveNumber { value: _ } => 1,
477            PositiveInteger { value: _ } => 1,
478            Integer { value: _ } => 1,
479            Angle { value: _ } => 1,
480            Color { value: _ } => 1,
481            String { value: _ } => 1,
482            Broadcast { name: _, id: _ } => 2,
483            Variable { name: _, id: _ } => 2,
484            List { name: _, id: _ } => 2,
485        }
486    }
487}
488
489struct BlockInputValueVisitor;
490
491impl<'de> Visitor<'de> for BlockInputValueVisitor {
492    type Value = BlockInputValue;
493
494    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
495        formatter.write_str("list that is a block input value")
496    }
497
498    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
499    where
500        A: serde::de::SeqAccess<'de>,
501    {
502        use serde::de::Error;
503        use BlockInputValue::{
504            Angle, Broadcast, Color, Integer, List, Number as BlockInputNumber, PositiveInteger,
505            PositiveNumber, String, Variable,
506        };
507
508        fn seq_next_element_error<'de, T, A>(
509            seq: &mut A,
510            len: usize,
511            error: &str,
512        ) -> Result<T, A::Error>
513        where
514            A: serde::de::SeqAccess<'de>,
515            T: Deserialize<'de>,
516        {
517            seq.next_element::<T>()?
518                .ok_or_else(|| A::Error::invalid_length(len, &error))
519        }
520
521        let vtype: u8 = seq_next_element_error(
522            &mut seq,
523            0,
524            "Expecting 2 or more elements for block input value with any Id",
525        )?;
526
527        let value = seq_next_element_error(
528            &mut seq,
529            1,
530            "Expecting 2 or more elements for block input value with any Id",
531        )?;
532
533        let res = match vtype {
534            4 => BlockInputNumber { value },
535            5 => PositiveNumber { value },
536            6 => PositiveInteger { value },
537            7 => Integer { value },
538            8 => Angle { value },
539            9 => Color { value },
540            10 => String { value },
541            11 => {
542                let id = seq_next_element_error(
543                    &mut seq,
544                    3,
545                    "Expecting 3 or more elements for block input value with Id 11",
546                )?;
547
548                let name = match value {
549                    Value::Text(s) => s,
550                    Value::Number(_) => {
551                        return Err(A::Error::invalid_value(
552                            serde::de::Unexpected::Other("number"),
553                            &"a string",
554                        ))
555                    }
556                };
557
558                Broadcast { name, id }
559            }
560            12 => {
561                let id = seq_next_element_error(
562                    &mut seq, 3,
563                    "Expecting 3 or 5 or more elements for block input value with Id 12 - 13 inclusive"
564                )?;
565                let x = seq.next_element::<Number>()?;
566                let y = seq.next_element::<Number>()?;
567                let name = match value {
568                    Value::Text(s) => s,
569                    Value::Number(_) => {
570                        return Err(A::Error::invalid_value(
571                            serde::de::Unexpected::Other("number"),
572                            &"a string",
573                        ))
574                    }
575                };
576                Variable { name, id }
577            }
578            13 => {
579                let id = seq_next_element_error(
580                    &mut seq, 3,
581                    "Expecting 3 or 5 or more elements for block input value with Id 12 - 13 inclusive"
582                )?;
583                let x = seq.next_element::<Number>()?;
584                let y = seq.next_element::<Number>()?;
585                let name = match value {
586                    Value::Text(s) => s,
587                    Value::Number(_) => {
588                        return Err(A::Error::invalid_value(
589                            serde::de::Unexpected::Other("number"),
590                            &"a string",
591                        ))
592                    }
593                };
594                List { name, id }
595            }
596            v => {
597                return Err(A::Error::invalid_value(
598                    serde::de::Unexpected::Unsigned(v.into()),
599                    &"Expecting a type id between 4 - 13 inclusive",
600                ))
601            }
602        };
603
604        Ok(res)
605    }
606}
607
608impl<'de> Deserialize<'de> for BlockInputValue {
609    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
610    where
611        D: Deserializer<'de>,
612    {
613        deserializer.deserialize_seq(BlockInputValueVisitor)
614    }
615}
616
617impl Serialize for BlockInputValue {
618    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
619    where
620        S: Serializer,
621    {
622        use serde::ser::SerializeSeq;
623        use BlockInputValue::*;
624
625        let mut s = serializer.serialize_seq(Some(self.hint_size()))?;
626        s.serialize_element(&self.get_id())?;
627        match self {
628            Number { value }
629            | PositiveNumber { value }
630            | PositiveInteger { value }
631            | Integer { value }
632            | Angle { value }
633            | Color { value }
634            | String { value } => {
635                s.serialize_element(value)?;
636            }
637            Broadcast { name, id } => {
638                s.serialize_element(name)?;
639                s.serialize_element(id)?;
640            }
641            Variable { name, id } | List { name, id } => {
642                s.serialize_element(name)?;
643                s.serialize_element(id)?;
644            }
645        }
646        s.end()
647    }
648}
649
650impl BlockField {
651    /// Value of the field
652    #[inline(always)]
653    pub fn value(&self) -> &Value {
654        match self {
655            BlockField::WithId { value, id: _ } => value,
656            BlockField::NoId { value } => value,
657        }
658    }
659
660    /// For certain fields,
661    /// such as variable and broadcast dropdown menus,
662    /// there is also a second element, which is the Id of the field's value.
663    #[inline(always)]
664    pub fn id(&self) -> Option<&Uid> {
665        match self {
666            BlockField::WithId { value: _, id } => id.as_ref(),
667            BlockField::NoId { value: _ } => None,
668        }
669    }
670}
671
672struct BlockFieldVisitor;
673
674impl<'de> Visitor<'de> for BlockFieldVisitor {
675    type Value = BlockField;
676
677    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
678        formatter.write_str("sequence of values that is a blockfield")
679    }
680
681    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
682    where
683        A: serde::de::SeqAccess<'de>,
684    {
685        use serde::de::Error;
686
687        let value = seq
688            .next_element::<Value>()?
689            .ok_or_else(|| A::Error::invalid_length(1, &"length 1 or 2 for BlockField"))?;
690        let id = seq.next_element::<Option<Uid>>()?;
691
692        Ok(match id {
693            Some(id) => BlockField::WithId { value, id },
694            None => BlockField::NoId { value },
695        })
696    }
697}
698
699impl<'de> Deserialize<'de> for BlockField {
700    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
701    where
702        D: Deserializer<'de>,
703    {
704        deserializer.deserialize_seq(BlockFieldVisitor)
705    }
706}
707
708impl Serialize for BlockField {
709    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
710    where
711        S: Serializer,
712    {
713        use serde::ser::SerializeSeq;
714
715        match self {
716            BlockField::WithId { value, id } => {
717                let mut seq = serializer.serialize_seq(Some(2))?;
718                seq.serialize_element(value)?;
719                seq.serialize_element(id)?;
720                seq.end()
721            }
722            BlockField::NoId { value } => {
723                let mut seq = serializer.serialize_seq(Some(1))?;
724                seq.serialize_element(value)?;
725                seq.end()
726            }
727        }
728    }
729}