use std::sync::Mutex;
use crate::blocks::EncryptionAlgorithm;
use crate::crypto::KeyRing;
use crate::engine::Emoji;
use crate::error::MeshError;
use crate::render::{CpuRenderer, Renderer};
#[derive(Debug, thiserror::Error)]
pub enum EngineError {
#[error("engine not initialized")]
NotInitialized,
#[error("crypto error: {0}")]
Crypto(String),
#[error("render error: {0}")]
Render(String),
#[error("unsupported: {0}")]
Unsupported(String),
#[error(transparent)]
Mesh(#[from] MeshError),
}
pub trait CombsEngineCore: Send + Sync {
fn init(&self, key: &[u8]) -> Result<(), EngineError>;
fn infer(&self, prompt: &str) -> Result<String, EngineError>;
fn encrypt_memory(&self, data: &[u8]) -> Result<Vec<u8>, EngineError>;
fn decrypt_memory(&self, data: &[u8]) -> Result<Vec<u8>, EngineError>;
fn render_sprite(&self, emoji: &Emoji, frame_index: u32) -> Result<Vec<u8>, EngineError>;
fn shutdown(&self) -> Result<(), EngineError>;
}
pub struct DefaultEngine {
keyring: Mutex<Option<KeyRing>>,
renderer: CpuRenderer,
}
impl DefaultEngine {
#[must_use]
pub fn new() -> Self {
DefaultEngine {
keyring: Mutex::new(None),
renderer: CpuRenderer::new(),
}
}
}
impl Default for DefaultEngine {
fn default() -> Self {
Self::new()
}
}
impl CombsEngineCore for DefaultEngine {
fn init(&self, key: &[u8]) -> Result<(), EngineError> {
let mut guard = self
.keyring
.lock()
.map_err(|_| EngineError::Crypto("keyring lock poisoned".into()))?;
*guard = Some(KeyRing::new(Some(key)));
Ok(())
}
fn infer(&self, _prompt: &str) -> Result<String, EngineError> {
Err(EngineError::Unsupported(
"inference requires the `engine` feature".into(),
))
}
fn encrypt_memory(&self, data: &[u8]) -> Result<Vec<u8>, EngineError> {
let guard = self
.keyring
.lock()
.map_err(|_| EngineError::Crypto("keyring lock poisoned".into()))?;
let keyring = guard.as_ref().ok_or(EngineError::NotInitialized)?;
Ok(keyring.encrypt(data, EncryptionAlgorithm::Aes256Gcm)?)
}
fn decrypt_memory(&self, data: &[u8]) -> Result<Vec<u8>, EngineError> {
let guard = self
.keyring
.lock()
.map_err(|_| EngineError::Crypto("keyring lock poisoned".into()))?;
let keyring = guard.as_ref().ok_or(EngineError::NotInitialized)?;
Ok(keyring.decrypt(data, EncryptionAlgorithm::Aes256Gcm)?)
}
fn render_sprite(&self, emoji: &Emoji, frame_index: u32) -> Result<Vec<u8>, EngineError> {
let image = emoji.get_image().ok_or(EngineError::Render(
"emoji has no image block".into(),
))?;
Ok(self.renderer.render_frame(&image.atlas, frame_index)?)
}
fn shutdown(&self) -> Result<(), EngineError> {
let mut guard = self
.keyring
.lock()
.map_err(|_| EngineError::Crypto("keyring lock poisoned".into()))?;
*guard = None;
Ok(())
}
}