sb3_decoder/structs/
variable.rs

1//! Module for handling Scratch 3.0 values and variables.
2//!
3//! This module defines the [`Value`] enum to represent variable values and the [`Variable`] struct to
4//! represent variables in a Scratch 3.0 project. It also includes the [`List`] struct for handling
5//! lists.
6
7/// The [`Value`] enum represents the possible types of values a variable can hold in a Scratch 3.0
8/// project.
9#[derive(Debug, Clone, PartialEq)]
10pub enum Value {
11    Number(f64),
12    String(String),
13}
14
15impl Value {
16    /// Checks if the value is scratch's representation of null.
17    pub fn is_null(&self) -> bool {
18        matches!(self, Value::String(s) if s == "null")
19    }
20}
21
22impl From<serde_json::Value> for Value {
23    fn from(value: serde_json::Value) -> Self {
24        match value {
25            serde_json::Value::Number(num) => {
26                if let Some(n) = num.as_f64() {
27                    Value::Number(n)
28                } else {
29                    Value::String(num.to_string())
30                }
31            }
32            serde_json::Value::String(s) => match s.as_str() {
33                "Infinity" => Value::Number(f64::INFINITY),
34                "-Infinity" => Value::Number(f64::NEG_INFINITY),
35                "NaN" => Value::Number(f64::NAN),
36                _ => {
37                    if let Ok(n) = s.parse::<f64>() {
38                        Value::Number(n)
39                    } else {
40                        Value::String(s)
41                    }
42                }
43            },
44            _ => Value::String(value.to_string()),
45        }
46    }
47}
48
49impl std::fmt::Display for Value {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        match self {
52            Value::Number(n) => write!(f, "{}", n),
53            Value::String(s) => write!(f, "{}", s),
54        }
55    }
56}
57
58impl TryFrom<Value> for bool {
59    type Error = &'static str;
60
61    fn try_from(value: Value) -> Result<Self, Self::Error> {
62        match value {
63            Value::String(s) => match s.to_lowercase().as_str() {
64                "true" => Ok(true),
65                "false" => Ok(false),
66                _ => Err("Cannot convert string to bool"),
67            },
68            _ => Err("Cannot convert non-string to bool"),
69        }
70    }
71}
72
73impl TryFrom<Value> for f64 {
74    type Error = &'static str;
75
76    fn try_from(value: Value) -> Result<Self, Self::Error> {
77        match value {
78            Value::Number(n) => Ok(n),
79            Value::String(s) => s.parse::<f64>().map_err(|_| "Cannot parse string to f64"),
80        }
81    }
82}
83
84/// The [`Variable`] struct represents a variable in a Scratch 3.0 project.
85#[derive(Debug, Clone)]
86pub struct Variable(
87    /// The value of the variable.
88    pub Value,
89);
90
91/// The [`List`] struct represents a list in a Scratch 3.0 project.
92#[derive(Debug, Clone)]
93pub struct List(
94    /// The items in the list.
95    pub Vec<Value>,
96);