use crate::common::db::Database; use crate::common::expr::Expr; use crate::common::ip; use std::fmt; #[derive(Debug)] pub enum Error { Empty, Invalid, IP(ip::Error), ExpectedArray(Expr), ExpectedBlob(Expr), InvalidArgsCount { cmd: String, expected: usize, actual: usize, }, } #[derive(Debug)] pub enum Query { Children { ip_block: ip::Block }, Del { ip_block: ip::Block }, Echo { msg: Vec }, Exists { ip_block: ip::Block }, Get { ip_block: ip::Block }, Info { ip_block: ip::Block }, Parent { ip_block: ip::Block }, Set { ip_block: ip::Block, value: Expr }, } impl Query { pub fn from_expr(expr: Expr) -> Result { let mut xs = if let Expr::Array(xs) = expr { xs } else { return Err(Error::ExpectedArray(expr)); }; if xs.is_empty() { return Err(Error::Empty); } let cmd_expr = xs.remove(0); let cmd = if let Expr::Blob(cmd) = cmd_expr { cmd } else { return Err(Error::ExpectedBlob(cmd_expr)); }; match &*cmd { b"ECHO" => build_echo(xs), // ECHO str b"SET" => build_set(xs), // SET ::/32 Expr b"GET" => build_get(xs), // GET ::/32 b"DEL" => build_del(xs), // DEL ::/32 b"EXISTS" => build_exists(xs), // EXISTS ::/32 b"INFO" => build_info(xs), // EXISTS ::/32 b"PARENT" => build_parent(xs), // SUP ::/32 b"CHILDREN" => build_children(xs), // SUB ::/32 _ => Err(Error::Invalid), } } pub fn exec(&self, db: &mut Database) -> Expr { match self { Self::Echo { msg } => Expr::Blob(msg.clone()), Self::Set { ip_block, value: _ } => { db.set(*ip_block, std::collections::HashMap::new()); Expr::Blob(b"OK".to_vec()) } Self::Get { ip_block } => db.get(ip_block).map(|x| x.into()).unwrap_or(Expr::Null), Self::Del { ip_block } => db .del(ip_block) .map_or(Expr::Null, |_| Expr::Blob(b"OK".to_vec())), Self::Exists { ip_block } => Expr::Bool(db.exists(ip_block)), Self::Info { ip_block } => { let info: Vec<(&str, String)> = db.info(ip_block).into(); info.into() } Self::Parent { ip_block } => { db.parent(ip_block).map(|x| x.into()).unwrap_or(Expr::Null) } Self::Children { ip_block } => db.children(ip_block).into(), } } } // Display impl fmt::Display for Query { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let res = match self { Query::Set { ip_block, value } => { format!("SET {} {}", ip_block, value) } Query::Get { ip_block } => { format!("GET {}", ip_block) } Query::Echo { msg } => { format!("ECHO {:?}", String::from_utf8_lossy(msg).into_owned()) } Query::Del { ip_block } => { format!("DEL {}", ip_block) } Query::Exists { ip_block } => { format!("EXISTS {}", ip_block) } Query::Info { ip_block } => { format!("INFO {}", ip_block) } Query::Parent { ip_block } => { format!("PARENT {}", ip_block) } Query::Children { ip_block } => { format!("CHILDREN {}", ip_block) } }; write!(f, "{}", res) } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let res = match self { Error::Empty => "Received an empty query.".to_string(), Error::ExpectedArray(got) => format!("Expected an ARRAY, got: {:?}.", got), Error::ExpectedBlob(got) => format!("Expected a BLOB, got: {:?}.", got), Error::IP(e) => format!("IP error: {e:?}"), Error::Invalid => "Received an invalid query.".to_string(), Error::InvalidArgsCount { cmd, expected, actual, } => format!( "Invalid number of arguments for {:?}. Expected {} but got {}.", cmd, expected, actual ), }; write!(f, "{}", res) } } // Builders fn build_echo(mut args: Vec) -> Result { count_args("ECHO", &args, 1)?; let expr = args.remove(0); let msg = if let Expr::Blob(k) = expr { k } else { return Err(Error::ExpectedBlob(expr)); }; Ok(Query::Echo { msg }) } fn build_get(mut args: Vec) -> Result { count_args("GET", &args, 1)?; let expr = args.remove(0); let ip_block = if let Expr::Blob(ref addr) = expr { ip::Block::from_bytestring(addr).map_err(Error::IP)? } else { return Err(Error::ExpectedBlob(expr)); }; Ok(Query::Get { ip_block }) } fn build_set(mut args: Vec) -> Result { count_args("SET", &args, 2)?; let expr = args.remove(0); let ip_block = if let Expr::Blob(ref addr) = expr { ip::Block::from_bytestring(addr).map_err(Error::IP)? } else { return Err(Error::ExpectedBlob(expr)); }; Ok(Query::Set { ip_block, value: args.remove(0), }) } fn build_del(mut args: Vec) -> Result { count_args("DEL", &args, 1)?; let expr = args.remove(0); let ip_block = if let Expr::Blob(ref addr) = expr { ip::Block::from_bytestring(addr).map_err(Error::IP)? } else { return Err(Error::ExpectedBlob(expr)); }; Ok(Query::Del { ip_block }) } fn build_exists(mut args: Vec) -> Result { count_args("EXISTS", &args, 1)?; let expr = args.remove(0); let ip_block = if let Expr::Blob(ref addr) = expr { ip::Block::from_bytestring(addr).map_err(Error::IP)? } else { return Err(Error::ExpectedBlob(expr)); }; Ok(Query::Exists { ip_block }) } fn build_info(mut args: Vec) -> Result { count_args("INFO", &args, 1)?; let expr = args.remove(0); let ip_block = if let Expr::Blob(ref addr) = expr { ip::Block::from_bytestring(addr).map_err(Error::IP)? } else { return Err(Error::ExpectedBlob(expr)); }; Ok(Query::Info { ip_block }) } fn build_parent(mut args: Vec) -> Result { count_args("PARENT", &args, 1)?; let expr = args.remove(0); let ip_block = if let Expr::Blob(ref addr) = expr { ip::Block::from_bytestring(addr).map_err(Error::IP)? } else { return Err(Error::ExpectedBlob(expr)); }; Ok(Query::Parent { ip_block }) } fn build_children(mut args: Vec) -> Result { count_args("CHILDREN", &args, 1)?; let expr = args.remove(0); let ip_block = if let Expr::Blob(ref addr) = expr { ip::Block::from_bytestring(addr).map_err(Error::IP)? } else { return Err(Error::ExpectedBlob(expr)); }; Ok(Query::Children { ip_block }) } // Helpers fn count_args(cmd: &str, args: &Vec, expected_count: usize) -> Result<(), Error> { let args_count = args.len(); if args_count != expected_count { return Err(Error::InvalidArgsCount { cmd: cmd.to_string(), expected: expected_count, actual: args_count, }); } Ok(()) }