rs_sb3/
monitor.rs

1//! Module to deal with Scratch monitor
2
3use crate::prelude::*;
4use serde::ser::SerializeMap;
5
6/// A Stage monitor, sometimes called a watcher, is a display on the Stage that shows the value of a variable, boolean, or a list.
7#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
8#[serde(rename_all = "camelCase")]
9pub struct Monitor {
10    /// The Id.
11    pub id: Uid,
12
13    /// See [`Mode`]
14    pub mode: Mode,
15
16    /// What "thing" is this monitor refering to
17    pub opcode: OpCode,
18
19    /// See [`Parameter`]
20    #[serde(rename = "params")]
21    pub params: Parameter,
22
23    /// The name of the target the monitor belongs to, if any.
24    /// [`None`] if is global var.
25    pub sprite_name: Option<Name>,
26
27    /// The value appearing on the monitor.
28    pub value: ListOrValue,
29
30    /// The width.
31    pub width: u64,
32
33    /// The height.
34    pub height: u64,
35
36    /// The x-coordinate.
37    pub x: i64,
38
39    /// The y-coordinate.
40    pub y: i64,
41
42    /// True if the monitor is visible and false otherwise.
43    pub visible: bool,
44
45    /// See [`Slider`]
46    /// [`None`] if [`Mode`] is [`Mode::List`]
47    #[serde(flatten)]
48    pub slider: Option<Slider>,
49}
50
51/// Monitor's Mode
52#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
53#[serde(rename_all = "camelCase")]
54pub enum Mode {
55    /// Show value in small display
56    Default,
57
58    /// Show value in large display
59    Large,
60
61    /// Have slider to the monitor
62    Slider,
63
64    /// Display as list
65    List,
66}
67
68/// Name of list or variable that this monitor refering to
69#[derive(Debug, PartialEq, Eq, Clone)]
70pub enum Parameter {
71    /// No parameter
72    None,
73
74    /// Name of a user defined variable
75    Variable(Name),
76
77    /// Name of a user defined list
78    List(Name),
79
80    /// See [`NumberName`]
81    NumberName(NumberName),
82}
83
84/// Enum for monitor value.
85/// The field could be either value or list.
86#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
87#[serde(untagged)]
88pub enum ListOrValue {
89    /// When the field is not a list
90    Value(Value),
91    /// When the field is a list
92    List(Vec<Value>),
93}
94
95/// Show number or name of a chosen variable
96#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
97#[serde(rename_all = "camelCase")]
98pub enum NumberName {
99    /// Show variable as number
100    Number,
101
102    /// Show variable as name
103    Name,
104}
105
106/// Monitors that do not belong to lists also have these properties
107#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
108#[serde(rename_all = "camelCase")]
109pub struct Slider {
110    /// The minimum value of the monitor's slider.
111    slider_min: i64,
112
113    /// The maximum value of the monitor's slider.
114    slider_max: i64,
115
116    /// True if the monitor's slider allows only integer values and false otherwise.
117    is_discrete: bool,
118}
119
120// Serde impl ==================================================================
121
122struct ParameterVisitor;
123
124impl<'de> Visitor<'de> for ParameterVisitor {
125    type Value = Parameter;
126
127    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
128        formatter.write_str("object that is a parameter")
129    }
130
131    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
132    where
133        A: serde::de::MapAccess<'de>,
134    {
135        use serde::de::Error;
136        if let Some((k, v)) = map.next_entry::<&str, &str>()? {
137            Ok(match (k, v) {
138                ("VARIABLE", v) => Parameter::Variable(v.to_owned()),
139                ("LIST", v) => Parameter::List(v.into()),
140                ("NUMBER_NAME", "name") => Parameter::NumberName(NumberName::Name),
141                ("NUMBER_NAME", "number") => Parameter::NumberName(NumberName::Number),
142                (k, _) => {
143                    return Err(A::Error::invalid_value(
144                        serde::de::Unexpected::Str(k),
145                        &"Expected either VARIABLE, LIST, or NUMBER_NAME",
146                    ))
147                }
148            })
149        } else {
150            Ok(Parameter::None)
151        }
152    }
153}
154
155impl<'de> Deserialize<'de> for Parameter {
156    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
157    where
158        D: serde::Deserializer<'de>,
159    {
160        deserializer.deserialize_map(ParameterVisitor)
161    }
162}
163
164impl Serialize for Parameter {
165    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
166    where
167        S: serde::Serializer,
168    {
169        match self {
170            Parameter::None => serializer.serialize_map(Some(0))?.end(),
171            r => {
172                let mut s = serializer.serialize_map(Some(1))?;
173                match r {
174                    Parameter::Variable(n) => s.serialize_entry("VARIABLE", n)?,
175                    Parameter::List(n) => s.serialize_entry("LIST", n)?,
176                    Parameter::NumberName(n) => s.serialize_entry("NUMBER_NAME", n)?,
177                    Parameter::None => unreachable!("There cannot be none in here"),
178                };
179                s.end()
180            }
181        }
182    }
183}