use crate::blocks::{
Block, EncryptionBlock, ImageBlock, LifecycleBlock, LifecycleState, LifecycleTransition,
SpriteAtlas, TextBlock, TodoBlock, TodoItem, TodoStatus,
};
#[derive(Debug, Clone, PartialEq)]
pub struct Emoji {
pub name: String,
pub blocks: Vec<Block>,
}
impl Emoji {
#[must_use]
pub fn get_text(&self) -> Option<&TextBlock> {
self.blocks.iter().find_map(|b| match b {
Block::Txt(t) => Some(t),
_ => None,
})
}
#[must_use]
pub fn get_image(&self) -> Option<&ImageBlock> {
self.blocks.iter().find_map(|b| match b {
Block::Img(i) => Some(i),
_ => None,
})
}
#[must_use]
pub fn get_encryption(&self) -> Option<&EncryptionBlock> {
self.blocks.iter().find_map(Block::as_encryption)
}
pub fn iter(&self) -> impl Iterator<Item = &Block> {
self.blocks.iter()
}
pub(crate) fn from_blocks(blocks: Vec<Block>) -> Emoji {
let name = blocks
.iter()
.find_map(|b| match b {
Block::Txt(t) => Some(t.name.clone()),
_ => None,
})
.unwrap_or_default();
Emoji { name, blocks }
}
}
#[derive(Debug, Clone)]
pub struct EmojiBuilder {
emoji: Emoji,
}
impl EmojiBuilder {
#[must_use]
pub fn new(name: &str) -> Self {
EmojiBuilder {
emoji: Emoji {
name: name.to_string(),
blocks: vec![Block::Txt(TextBlock {
name: name.to_string(),
description: String::new(),
specs: Vec::new(),
})],
},
}
}
#[must_use]
pub fn description(mut self, description: &str) -> Self {
if let Some(Block::Txt(t)) = self
.emoji
.blocks
.iter_mut()
.find(|b| matches!(b, Block::Txt(_)))
{
t.description = description.to_string();
}
self
}
#[must_use]
pub fn add_todo(mut self, key: &str, value: &str) -> Self {
let item = TodoItem {
key: key.to_string(),
value: value.to_string(),
status: TodoStatus::Pending,
depends_on: Vec::new(),
};
if let Some(Block::Tdo(t)) = self
.emoji
.blocks
.iter_mut()
.find(|b| matches!(b, Block::Tdo(_)))
{
t.items.push(item);
} else {
self.emoji.blocks.push(Block::Tdo(TodoBlock {
items: vec![item],
}));
}
self
}
#[must_use]
pub fn add_image_rgba(mut self, width: u32, height: u32, mut rgba: Vec<u8>) -> Self {
rgba.resize(width as usize * height as usize * 4, 0);
self.emoji.blocks.push(Block::Img(ImageBlock {
name: String::new(),
atlas: SpriteAtlas {
width,
height,
frame_width: width.max(1),
frame_height: height.max(1),
frame_count: 1,
rgba,
},
}));
self
}
#[must_use]
pub fn with_agent_lifecycle(mut self) -> Self {
self.emoji.blocks.push(Block::Lfc(LifecycleBlock {
states: vec![
LifecycleState {
name: "idle".into(),
initial: true,
},
LifecycleState {
name: "active".into(),
initial: false,
},
LifecycleState {
name: "sleeping".into(),
initial: false,
},
],
transitions: vec![
LifecycleTransition {
from: "idle".into(),
to: "active".into(),
event: "activate".into(),
},
LifecycleTransition {
from: "active".into(),
to: "idle".into(),
event: "deactivate".into(),
},
LifecycleTransition {
from: "active".into(),
to: "sleeping".into(),
event: "sleep".into(),
},
LifecycleTransition {
from: "sleeping".into(),
to: "idle".into(),
event: "wake".into(),
},
],
}));
self
}
#[must_use]
pub fn encryption(mut self, encryption: EncryptionBlock) -> Self {
self.emoji.blocks.push(Block::Enc(encryption));
self
}
#[must_use]
pub fn add_block(mut self, block: Block) -> Self {
self.emoji.blocks.push(block);
self
}
#[must_use]
pub fn build(self) -> Emoji {
self.emoji
}
}