sb3_decoder/structs/block/
input.rs

1//! This module defines the structures and enums for handling input values in blocks.
2
3use std::collections::HashMap;
4
5use crate::{decoder::{RawBlock, RawBlockInput}, error::DecodeError, structs::{Block, Value}};
6
7/// Represents the different types of input values that can be associated with a block.
8#[derive(Debug, Clone, PartialEq)]
9pub enum InputValue {
10    /// A literal value, such as a number or string.
11    Literal(Value),
12
13    // A color value.
14    Color(u8, u8, u8),
15
16    /// A reference to a broadcast by its name.
17    Broadcast(String),
18
19    /// A reference to a variable by its name.
20    Variable(String),
21
22    /// A reference to a list by its name.
23    List(String),
24
25    /// A nested block, represented by another [`Block`].
26    Block(Box<Block>),
27}
28
29/// The [`BlockInput`] struct wraps an [`InputValue`].
30///
31/// [`Block`]s contain a map of input names to [`BlockInput`]s.
32#[derive(Debug, Clone, PartialEq)]
33pub struct BlockInput {
34    /// If the block is a shadow block.
35    pub shadow: bool,
36
37    /// The input value, which can be a literal, broadcast, or nested block.
38    pub value: InputValue,
39}
40
41impl BlockInput {
42    /// Creates a new [`BlockInput`] from a [`RawBlockInput`] and the entire map of blocks to
43    /// un-flatten the structure.
44    pub fn new(raw: RawBlockInput, blocks: &HashMap<String, RawBlock>) -> Result<Self, DecodeError> {
45        let shadow = match raw.shadow {
46            1 | 3 => true,
47            2 => false,
48            _ => unreachable!("Invalid shadow value: {}", raw.shadow),
49        };
50
51        let value = match raw.kind {
52            0 => {
53                // Nested block
54                let block_id = raw
55                    .value
56                    .as_str()
57                    .ok_or_else(|| DecodeError::InvalidData("Expected a string".to_string()))?;
58                InputValue::Block(Box::new(Block::new(block_id, blocks)?))
59            }
60            4..=8 => {
61                // Number
62                InputValue::Literal(Value::from(raw.value.clone()))
63            }
64            9 => {
65                // Hex color string
66                let hex_str = raw
67                    .value
68                    .as_str()
69                    .ok_or_else(|| DecodeError::InvalidData("Expected a string".to_string()))?;
70                if !hex_str.starts_with('#') || hex_str.len() != 7 {
71                    return Err(DecodeError::InvalidData(format!(
72                        "Invalid hex color string: {}",
73                        hex_str
74                    )));
75                }
76                let r = u8::from_str_radix(&hex_str[1..3], 16).map_err(|_| {
77                    DecodeError::InvalidData(format!("Invalid red component in hex color: {}", hex_str))
78                })?;
79                let g = u8::from_str_radix(&hex_str[3..5], 16).map_err(|_| {
80                    DecodeError::InvalidData(format!("Invalid green component in hex color: {}", hex_str))
81                })?;
82                let b = u8::from_str_radix(&hex_str[5..7], 16).map_err(|_| {
83                    DecodeError::InvalidData(format!("Invalid blue component in hex color: {}", hex_str))
84                })?;
85                InputValue::Color(r, g, b)
86            }
87            10 => {
88                // String
89                let string = raw
90                    .value
91                    .as_str()
92                    .ok_or_else(|| DecodeError::InvalidData("Expected a string".to_string()))?;
93                InputValue::Literal(Value::String(string.to_string()))
94            }
95            11 => {
96                // Broadcast
97                let broadcast_name = raw
98                    .value
99                    .as_str()
100                    .ok_or_else(|| DecodeError::InvalidData("Expected a string".to_string()))?;
101                InputValue::Broadcast(broadcast_name.to_string())
102            }
103            12 => {
104                // Variable
105                let var_name = raw
106                    .value
107                    .as_str()
108                    .ok_or_else(|| DecodeError::InvalidData("Expected a string".to_string()))?;
109                InputValue::Variable(var_name.to_string())
110            }
111            13 => {
112                // List
113                let list_name = raw
114                    .value
115                    .as_str()
116                    .ok_or_else(|| DecodeError::InvalidData("Expected a string".to_string()))?;
117                InputValue::List(list_name.to_string())
118            }
119            _ => {
120                return Err(DecodeError::InvalidData(format!(
121                    "Unknown kind value: {}",
122                    raw.kind
123                )))
124            }
125        };
126
127        Ok(BlockInput { shadow, value })
128    }
129}