mod handling; mod testing; use litemap::LiteMap; use minicbor::Decoder; use minicbor::data::Type; use minicbor::decode::Error; use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::io::Write; pub enum Command { Unknown, Set(String, StoredData), Define(String, LiteMap), Push(String, StoredData), Alias(String, String), Display(String), SetOutput(fn() -> Box), } #[derive(Clone)] pub enum StoredData { Integer(isize), Float(f64), String(String), Bool(bool), Line(Line), Vec(Vec), } impl Display for StoredData { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { StoredData::Integer(v) => v.fmt(f), StoredData::Float(v) => v.fmt(f), StoredData::String(v) => v.fmt(f), StoredData::Bool(v) => v.fmt(f), StoredData::Line(v) => v.fmt(f), StoredData::Vec(vec) => { vec.iter().enumerate().for_each(|(i, d)| { write!(f, "{}", d).unwrap(); if i != vec.len() - 1 { write!(f, "\n").unwrap(); } }); Ok(()) } } } } #[derive(Clone)] pub struct Line { data: Vec, } impl From> for Line { fn from(value: Vec) -> Self { Self { data: value } } } impl Display for Line { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!( f, "[{}]", self.data .iter() .map(|i| i.to_string()) .collect::>() .join(", ") ) } } impl From<&[u8]> for Command { fn from(value: &[u8]) -> Self { parse_command(value).unwrap_or_else(|e| { println!("{}", e); Command::Unknown }) } } fn parse_command(data: &[u8]) -> Result { if data.starts_with(b"SET:") { let payload = &data[b"SET:".len()..]; let mut decoder = Decoder::new(&payload); decoder.array()?; let id = decoder.str()?.to_string(); let value = decode_value(&mut decoder)?; return Ok(Command::Set(id, value)); } if data.starts_with(b"PUSH:") { let payload = &data[b"PUSH:".len()..]; let mut decoder = Decoder::new(&payload); _ = decoder.array()?; let id = decoder.str()?.to_string(); let value = decode_value(&mut decoder)?; return Ok(Command::Push(id, value)); } if data.starts_with(b"DISPLAY:") { let payload = &data[b"DISPLAY:".len()..]; let mut decoder = Decoder::new(&payload); decoder.array()?; let id = decoder.str()?.to_string(); return Ok(Command::Display(id)); } if data.starts_with(b"ALIAS:") { let payload = &data[b"ALIAS:".len()..]; let mut decoder = Decoder::new(&payload); decoder.array()?; let id = decoder.str()?.to_string(); let alias = decoder.str()?.to_string(); return Ok(Command::Alias(id, alias)); } Ok(Command::Unknown) } fn decode_value(decoder: &mut Decoder) -> Result { Ok(match decoder.datatype()? { Type::Bool => StoredData::Bool(decoder.bool()?), Type::U8 => StoredData::Integer(decoder.u8()? as isize), Type::U16 => StoredData::Integer(decoder.u16()? as isize), Type::U32 => StoredData::Integer(decoder.u32()? as isize), Type::U64 => StoredData::Integer(decoder.u64()? as isize), Type::I8 => StoredData::Integer(decoder.i8()? as isize), Type::I16 => StoredData::Integer(decoder.i16()? as isize), Type::I32 => StoredData::Integer(decoder.i32()? as isize), Type::I64 => StoredData::Integer(decoder.i64()? as isize), Type::Int => StoredData::Integer(decoder.i32()? as isize), Type::F16 => StoredData::Float(decoder.f32()? as f64), Type::F32 => StoredData::Float(decoder.f32()? as f64), Type::F64 => StoredData::Float(decoder.f64()?), Type::String | Type::StringIndef => StoredData::String(decoder.str()?.to_string()), Type::Array | Type::ArrayIndef => { let len = decoder.array()?; let mut array = if let Some(len) = len { Vec::with_capacity(len as usize) } else { vec![] }; if array.capacity() == 0 { loop { let dt = decoder.datatype()?; if let Type::Break = dt { break; } array.push(decode_value(decoder)?); } } else { for _ in 0..array.capacity() { array.push(decode_value(decoder)?); } } StoredData::Line(Line::from(array)) } _ => { decoder.skip()?; StoredData::Bool(false) } }) } pub struct NoteContext { entries: HashMap, aliases: HashMap, output: Box, } impl NoteContext { pub fn default() -> Self { Self { entries: Default::default(), aliases: Default::default(), output: Box::new(std::io::stdout()), } } }