sb3_decoder/structs/block/
block.rs1use std::collections::HashMap;
4
5use crate::{decoder::RawBlock, error::DecodeError, structs::{BlockInput, Opcode}};
6
7#[derive(Debug, Clone, PartialEq)]
10pub struct Block {
11 pub opcode: Opcode,
13
14 pub inputs: HashMap<String, BlockInput>,
16
17 pub fields: HashMap<String, String>,
19}
20
21impl Block {
22 pub fn new(id: &str, blocks: &HashMap<String, RawBlock>) -> Result<Self, DecodeError> {
25 let raw = blocks
26 .get(id)
27 .ok_or_else(|| DecodeError::NotFound(format!("Block with ID {}", id)))?;
28 let inputs = raw
29 .inputs
30 .iter()
31 .map(|(k, v)| {
32 Ok((
33 k.clone(),
34 BlockInput::new(v.clone(), blocks)?,
35 ))
36 })
37 .collect::<Result<HashMap<String, BlockInput>, DecodeError>>()?;
38 let fields = raw
39 .fields
40 .iter()
41 .map(|(f, (name, _))| (f.clone(), name.clone()))
42 .collect();
43 Ok(Self {
44 opcode: raw.opcode.as_str().parse()?,
45 inputs,
46 fields,
47 })
48 }
49}
50
51pub type Script = Vec<Block>;
52
53pub fn decode_scripts(blocks: &HashMap<String, RawBlock>) -> Result<Vec<Script>, DecodeError> {
55 let mut scripts = Vec::new();
56
57 for (id, raw) in blocks {
58 if raw.top_level && raw.parent.is_none() {
59 let mut script = Vec::new();
60 let mut current_id = Some(id.clone());
61
62 while let Some(cid) = current_id {
63 let block = Block::new(&cid, blocks)?;
64 current_id = blocks.get(&cid).and_then(|b| b.next.clone());
65 script.push(block);
66 }
67
68 scripts.push(script);
69 }
70 }
71
72 Ok(scripts)
73}