mod api;
mod character;
mod emotion;
mod encryption;
mod function;
mod image;
mod lifecycle;
mod orchestration;
mod text;
mod todo;
pub use api::{ApiBlock, ApiEndpoint};
pub use character::CharacterBlock;
pub use emotion::{EmotionBlock, EmotionState};
pub use encryption::{EncryptionAlgorithm, EncryptionBlock};
pub use function::{FunctionBlock, FunctionDef, FunctionKind};
pub use image::{ImageBlock, SpriteAtlas};
pub use lifecycle::{LifecycleBlock, LifecycleState, LifecycleTransition};
pub use orchestration::{DirectiveKind, OrchestrationBlock, OrchestrationDirective};
pub use text::TextBlock;
pub use todo::{TodoBlock, TodoItem, TodoStatus};
use serde::{Deserialize, Serialize};
use crate::error::Result;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum BlockTag {
Txt,
Img,
Tdo,
Fnc,
Api,
Lfc,
Chr,
Emo,
Enc,
Orc,
}
impl BlockTag {
pub const ALL: [BlockTag; 10] = [
BlockTag::Txt,
BlockTag::Img,
BlockTag::Tdo,
BlockTag::Fnc,
BlockTag::Api,
BlockTag::Lfc,
BlockTag::Chr,
BlockTag::Emo,
BlockTag::Enc,
BlockTag::Orc,
];
#[must_use]
pub fn tag_bytes(self) -> [u8; 3] {
match self {
BlockTag::Txt => *b"txt",
BlockTag::Img => *b"img",
BlockTag::Tdo => *b"tdo",
BlockTag::Fnc => *b"fnc",
BlockTag::Api => *b"api",
BlockTag::Lfc => *b"lfc",
BlockTag::Chr => *b"chr",
BlockTag::Emo => *b"emo",
BlockTag::Enc => *b"enc",
BlockTag::Orc => *b"orc",
}
}
#[must_use]
pub fn index(self) -> u8 {
match self {
BlockTag::Txt => 0,
BlockTag::Img => 1,
BlockTag::Tdo => 2,
BlockTag::Fnc => 3,
BlockTag::Api => 4,
BlockTag::Lfc => 5,
BlockTag::Chr => 6,
BlockTag::Emo => 7,
BlockTag::Enc => 8,
BlockTag::Orc => 9,
}
}
#[must_use]
pub fn from_index(index: u8) -> Option<Self> {
BlockTag::ALL.iter().copied().find(|t| t.index() == index)
}
#[must_use]
pub fn from_tag_bytes(tag: &[u8; 3]) -> Option<Self> {
BlockTag::ALL.iter().copied().find(|t| &t.tag_bytes() == tag)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum Block {
Txt(TextBlock),
Img(ImageBlock),
Tdo(TodoBlock),
Fnc(FunctionBlock),
Api(ApiBlock),
Lfc(LifecycleBlock),
Chr(CharacterBlock),
Emo(EmotionBlock),
Enc(EncryptionBlock),
Orc(OrchestrationBlock),
}
impl Block {
#[must_use]
pub fn tag(&self) -> BlockTag {
match self {
Block::Txt(_) => BlockTag::Txt,
Block::Img(_) => BlockTag::Img,
Block::Tdo(_) => BlockTag::Tdo,
Block::Fnc(_) => BlockTag::Fnc,
Block::Api(_) => BlockTag::Api,
Block::Lfc(_) => BlockTag::Lfc,
Block::Chr(_) => BlockTag::Chr,
Block::Emo(_) => BlockTag::Emo,
Block::Enc(_) => BlockTag::Enc,
Block::Orc(_) => BlockTag::Orc,
}
}
pub fn payload(&self) -> Result<Vec<u8>> {
let json = match self {
Block::Txt(b) => serde_json::to_vec(b),
Block::Img(b) => serde_json::to_vec(b),
Block::Tdo(b) => serde_json::to_vec(b),
Block::Fnc(b) => serde_json::to_vec(b),
Block::Api(b) => serde_json::to_vec(b),
Block::Lfc(b) => serde_json::to_vec(b),
Block::Chr(b) => serde_json::to_vec(b),
Block::Emo(b) => serde_json::to_vec(b),
Block::Enc(b) => serde_json::to_vec(b),
Block::Orc(b) => serde_json::to_vec(b),
}?;
Ok(json)
}
pub fn from_payload(tag: BlockTag, bytes: &[u8]) -> Result<Block> {
let block = match tag {
BlockTag::Txt => Block::Txt(serde_json::from_slice(bytes)?),
BlockTag::Img => Block::Img(serde_json::from_slice(bytes)?),
BlockTag::Tdo => Block::Tdo(serde_json::from_slice(bytes)?),
BlockTag::Fnc => Block::Fnc(serde_json::from_slice(bytes)?),
BlockTag::Api => Block::Api(serde_json::from_slice(bytes)?),
BlockTag::Lfc => Block::Lfc(serde_json::from_slice(bytes)?),
BlockTag::Chr => Block::Chr(serde_json::from_slice(bytes)?),
BlockTag::Emo => Block::Emo(serde_json::from_slice(bytes)?),
BlockTag::Enc => Block::Enc(serde_json::from_slice(bytes)?),
BlockTag::Orc => Block::Orc(serde_json::from_slice(bytes)?),
};
Ok(block)
}
#[must_use]
pub fn as_encryption(&self) -> Option<&EncryptionBlock> {
match self {
Block::Enc(b) => Some(b),
_ => None,
}
}
}
pub(crate) fn validate_block(block: &Block) -> Result<()> {
if let Block::Img(img) = block {
img.atlas.validate()?;
}
Ok(())
}