use serde::Deserialize; use crate::board::Board; #[derive(Debug, Deserialize)] pub struct Chapter { pub title: String, pub levels: Vec, #[serde(default = "default_true")] pub visible: bool, } #[derive(Debug, Clone, Deserialize)] pub struct Level { id: String, name: String, description: String, #[serde(default)] init_board: Option, /// no stages means sandbox #[serde(default)] stages: Vec, } #[derive(Debug, Clone, Deserialize)] pub struct Stage { input: IOData, output: IOData, } #[derive(Debug, Clone, Deserialize)] #[serde(untagged)] pub enum IOData { Bytes(Vec), Text(String), } impl IOData { pub fn as_bytes(&self) -> &[u8] { match self { IOData::Bytes(b) => b, IOData::Text(t) => t.as_bytes(), } } pub fn is_text(&self) -> bool { matches!(self, IOData::Text(_)) } } impl Level { pub fn new_orphan(id: &str) -> Self { Self { id: id.to_owned(), name: id.to_owned(), description: String::from( "No level with this id was found, but there are saved solutions pointing to it.\n Because input values and expected output is not available, this functions as a sandbox.\n This allows you to recover any machines you have built here.", ), init_board: None, stages: Vec::new(), } } pub fn id(&self) -> &str { &self.id } pub fn name(&self) -> &str { &self.name } pub fn description(&self) -> &str { &self.description } pub fn is_sandbox(&self) -> bool { self.stages.is_empty() } pub fn init_board(&self) -> Option { self.init_board.clone() } pub fn stages(&self) -> &[Stage] { &self.stages } } impl Stage { pub fn input(&self) -> &IOData { &self.input } pub fn output(&self) -> &IOData { &self.output } } fn default_true() -> bool { true }