From a9c4c9c2cbf70686d5f21f6bd1dd5c477f4a5085 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 19 Nov 2025 11:50:43 -0800 Subject: Read side is almost done, just packet work to go. --- rust/src/lib.rs | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 283 insertions(+), 4 deletions(-) (limited to 'rust') diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 88b999d..300fa99 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -3,7 +3,9 @@ use std::vec::Vec; use std::io::{Write,Read}; use std::num::FpCategory; use std::sync::LazyLock; +use std::io::Cursor; +#[derive(PartialEq)] pub enum Value { Integer(i64), ByteString(Vec), @@ -14,6 +16,44 @@ pub enum Value { Nothing, } +pub enum ValueParse { + Value(Value), + EndMarker, +} + +impl PartialEq for Value { + fn eq(&self, other: &i64) -> bool { + if let Value::Integer(x) = self { + x == other + } else { + false + } + } +} + +impl PartialEq> for Value { + fn eq(&self, other: &Vec) -> bool { + if let Value::ByteString(x) = self { + x == other + } else { + false + } + } +} + +impl PartialEq for Value { + fn eq(&self, other: &bool) -> bool { + if let Value::Boolean(x) = self { + x == other + } else { + false + } + } +} + +impl std::cmp::Eq for Value { +} + static FLOAT_DIVISOR: LazyLock = LazyLock::new(|| (256_f64).ln()); fn write_packed_int( x: i64 ) -> Vec @@ -154,15 +194,149 @@ impl Value { Ok(()) } - pub fn write_packet( &self, w: &mut W ) -> Result<(), std::io::Error> { + fn read_parse(r: &mut R) -> Result { + let it = { + let mut it = [0u8]; + r.read_exact( &mut it )?; + it[0] + }; + match it as char { + '0' => Ok(ValueParse::Value(Value::Boolean(false))), + '1' => Ok(ValueParse::Value(Value::Boolean(true))), + 'n' => Ok(ValueParse::Value(Value::Nothing)), + 'e' => Ok(ValueParse::EndMarker), + 'i' => Ok(ValueParse::Value(Value::Integer(read_packed_int(r)?))), + 's' => { + let len = read_packed_int(r)?; + let mut body = vec![0; len as usize]; + r.read_exact( &mut body )?; + Ok(ValueParse::Value(Value::ByteString(body))) + } + 'l' => { + let mut body = Vec::::new(); + loop { + match Value::read_parse(r)? { + ValueParse::Value(v) => body.push(v), + ValueParse::EndMarker => break, + } + } + Ok(ValueParse::Value(Value::List(body))) + } + 'f' => { + let (lng, neg) = { + let lng = read_packed_int( r )?; + if lng < 0 { + (-lng, true) + } else { + (lng, false) + } + }; + let mut value = 0.0f64; + let mut buf = vec![0u8; lng as usize]; + r.read_exact( &mut buf )?; + for b in buf[1..].iter().rev() { + value = (value+(*b as f64))*(1.0/256.0); + } + value += buf[0] as f64; + let scale = read_packed_int( r )?; + value *= 256.0f64.powi( scale as i32 ); + if neg { + Ok(ValueParse::Value(Value::Float(-value))) + } else { + Ok(ValueParse::Value(Value::Float(value))) + } + } + 'F' => { + let st = { + let mut st = [0u8]; + r.read_exact( &mut st )?; + st[0] + }; + match st as char { + 'N' => Ok(ValueParse::Value(Value::Float(f64::NAN))), + 'n' => Ok(ValueParse::Value(Value::Float(f64::NAN))), + 'I' => Ok(ValueParse::Value(Value::Float(f64::NEG_INFINITY))), + 'i' => Ok(ValueParse::Value(Value::Float(f64::INFINITY))), + 'Z' => Ok(ValueParse::Value(Value::Float(-0.0f64))), + 'z' => Ok(ValueParse::Value(Value::Float(0.0f64))), + _ => { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Unknown exceptional float subtype found.")); + } + } + } + 'd' => { + let mut body = HashMap::new(); + loop { + let k = match Value::read_parse(r)? { + ValueParse::Value(v) => { + if let Value::ByteString(s) = v { + if let Ok(s) = String::from_utf8(s) { + s + } else { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Keys must be utf8 compatbile strings.")); + } + } else { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Non-string cannot be dictionary key.")); + } + }, + ValueParse::EndMarker => break, + }; + let v = match Value::read_parse(r)? { + ValueParse::Value(v) => v, + ValueParse::EndMarker => { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Premature end marker in dictionary.")); + } + }; + body.insert( k, v ); + } + Ok(ValueParse::Value(Value::Dictionary(body))) + } + _ => { + Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid data type specified.")) + } + } + } + + pub fn read(r: &mut R) -> Result { + match Value::read_parse(r) { + Ok(ValueParse::Value(v)) => Ok(v), + Ok(ValueParse::EndMarker) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Unexpecetd EndMarker while parsing structure.")), + Err(e) => Err(e) + } + } + + pub fn to_packet( &self ) -> Result, std::io::Error> { let mut body : Vec = vec![1u8,0u8,0u8,0u8,0u8]; self.write( &mut body )?; let len = body.len() as u32; body[1..5].copy_from_slice( &len.to_be_bytes() ); - w.write_all( &body ) + Ok(body) } + pub fn write_packet( &self, w: &mut W ) -> Result<(), std::io::Error> { + match self.to_packet() { + Ok(body) => { + w.write_all( &body ) + } + Err(e) => { + Err(e) + } + } + } + pub fn from_packet( r: &mut R ) -> Result { + let mut ver = [0u8]; + let mut size = [0u8; 4]; + r.read_exact( &mut ver )?; + if ver[0] != 1 { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid gats packet version.")); + } + r.read_exact( &mut size )?; + let size = i32::from_be_bytes( size ); + let mut buf = vec![0u8; size as usize -5]; + r.read_exact( &mut buf )?; + Ok(Value::read( &mut Cursor::new( buf ) )?) + } } #[cfg(test)] @@ -170,7 +344,7 @@ mod tests { use super::*; use core::error::Error; use std::fs::File; - use std::io::prelude::*; + use std::io::Cursor; #[test] fn write_file1() -> Result<(),Box> { @@ -187,7 +361,112 @@ mod tests { ("null".to_string(), Value::Nothing), ("float".to_string(), Value::Float(123.456)), ])); - v.write_packet( &mut f ); + v.write_packet( &mut f )?; + Ok(()) + } + + #[test] + fn round_int() -> Result<(),Box> { + let v = Value::Integer(555666); + let mut buf = Vec::::new(); + v.write( &mut buf )?; + let v2 = Value::read( &mut Cursor::new(buf) )?; + assert!( v == v2 ); + assert!( v == 555666 ); + Ok(()) + } + + #[test] + fn round_str() -> Result<(),Box> { + let v = Value::ByteString(vec![1,1,2,3,5,8,13,21,34]); + let mut buf = Vec::::new(); + v.write( &mut buf )?; + let v2 = Value::read( &mut Cursor::new(buf) )?; + let v3 = Value::ByteString(vec![1,1,2,3,5,8,13,21,35]); + assert!( v == v2 ); + assert!( v != v3 ); + assert!( v == vec![1,1,2,3,5,8,13,21,34] ); + Ok(()) + } + + #[test] + fn round_bool_true() -> Result<(),Box> { + let v = Value::Boolean(true); + let mut buf = Vec::::new(); + v.write( &mut buf )?; + let v2 = Value::read( &mut Cursor::new(buf) )?; + let v3 = Value::Boolean(false); + assert!( v == v2 ); + assert!( v != v3 ); + assert!( v == true ); + Ok(()) + } + + #[test] + fn round_bool_false() -> Result<(),Box> { + let v = Value::Boolean(false); + let mut buf = Vec::::new(); + v.write( &mut buf )?; + let v2 = Value::read( &mut Cursor::new(buf) )?; + let v3 = Value::Boolean(true); + assert!( v == v2 ); + assert!( v != v3 ); + assert!( v == false ); + Ok(()) + } + + #[test] + fn round_list() -> Result<(),Box> { + let v = Value::List(vec![ + Value::Integer(1), Value::Integer(1), Value::Integer(2), + Value::Integer(3), Value::Integer(5), Value::Integer(8), + Value::Integer(13), Value::Integer(21), Value::Integer(34), + ]); + let mut buf = Vec::::new(); + v.write( &mut buf )?; + let v2 = Value::read( &mut Cursor::new(buf) )?; + assert!( v == v2 ); + Ok(()) + } + + #[test] + fn round_dictionary() -> Result<(), Box> { + let v = Value::Dictionary(HashMap::from([ + ("biggerint".to_string(), Value::Integer(98765)), + ("negint".to_string(), Value::Integer(-98765)), + ("integer".to_string(), Value::Integer(44)), + ("boolean".to_string(), Value::Boolean(true)), + ("list".to_string(), Value::List(vec![ + Value::Integer(1), Value::Integer(1), Value::Integer(2), + Value::Integer(3), Value::Integer(5), Value::Integer(8), + ])), + ("null".to_string(), Value::Nothing), + ("float".to_string(), Value::Float(123.456)), + ])); + let mut buf = Vec::::new(); + v.write( &mut buf )?; + let v2 = Value::read( &mut Cursor::new(buf) )?; + assert!( v == v2 ); + Ok(()) + } + + #[test] + fn round_null() -> Result<(), Box> { + let v = Value::Nothing; + let mut buf = Vec::::new(); + v.write( &mut buf )?; + let v2 = Value::read( &mut Cursor::new(buf) )?; + assert!( v == v2 ); + Ok(()) + } + + #[test] + fn round_float() -> Result<(), Box> { + let v = Value::Float(123.456); + let mut buf = Vec::::new(); + v.write( &mut buf )?; + let v2 = Value::read( &mut Cursor::new(buf) )?; + assert!( v == v2 ); Ok(()) } } -- cgit v1.2.3