From 61d7cdcc9ae82020f61d5c9ac1e8a2123ed7b9ac Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Wed, 19 Nov 2025 13:32:09 -0800 Subject: read/write all work. --- rust/src/lib.rs | 137 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 45 deletions(-) (limited to 'rust') diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 300fa99..5a5f96a 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,9 +1,8 @@ use std::collections::HashMap; use std::vec::Vec; -use std::io::{Write,Read}; +use std::io::{Write,Read,Cursor,Error,ErrorKind}; use std::num::FpCategory; use std::sync::LazyLock; -use std::io::Cursor; #[derive(PartialEq)] pub enum Value { @@ -16,7 +15,12 @@ pub enum Value { Nothing, } -pub enum ValueParse { +pub enum BytesToRead { + Estimate(usize), + Final(usize), +} + +enum ValueParse { Value(Value), EndMarker, } @@ -77,7 +81,7 @@ fn write_packed_int( x: i64 ) -> Vec w } -fn read_packed_int( r: &mut R ) -> Result { +fn read_packed_int( r: &mut R ) -> Result { let mut out : i64; let mut bb = [0u8]; r.read( &mut bb )?; @@ -98,7 +102,7 @@ fn read_packed_int( r: &mut R ) -> Result { } impl Value { - pub fn write(&self, w: &mut W) -> Result<(), std::io::Error> { + pub fn write(&self, w: &mut W) -> Result<(), Error> { match self { Self::Integer(x) => { let bb = ['i' as u8]; @@ -194,7 +198,7 @@ impl Value { Ok(()) } - fn read_parse(r: &mut R) -> Result { + fn read_parse(r: &mut R) -> Result { let it = { let mut it = [0u8]; r.read_exact( &mut it )?; @@ -260,7 +264,7 @@ impl Value { '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.")); + return Err(Error::new(ErrorKind::InvalidData, "Unknown exceptional float subtype found.")); } } } @@ -273,10 +277,10 @@ impl Value { 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.")); + return Err(Error::new(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.")); + return Err(Error::new(ErrorKind::InvalidData, "Non-string cannot be dictionary key.")); } }, ValueParse::EndMarker => break, @@ -284,7 +288,7 @@ impl Value { 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.")); + return Err(Error::new(ErrorKind::InvalidData, "Premature end marker in dictionary.")); } }; body.insert( k, v ); @@ -292,20 +296,20 @@ impl Value { Ok(ValueParse::Value(Value::Dictionary(body))) } _ => { - Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid data type specified.")) + Err(Error::new(ErrorKind::InvalidData, "Invalid data type specified.")) } } } - pub fn read(r: &mut R) -> Result { + 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.")), + Ok(ValueParse::EndMarker) => Err(Error::new(ErrorKind::InvalidData, "Unexpecetd EndMarker while parsing structure.")), Err(e) => Err(e) } } - pub fn to_packet( &self ) -> Result, std::io::Error> { + pub fn to_packet( &self ) -> Result, Error> { let mut body : Vec = vec![1u8,0u8,0u8,0u8,0u8]; self.write( &mut body )?; let len = body.len() as u32; @@ -313,7 +317,7 @@ impl Value { Ok(body) } - pub fn write_packet( &self, w: &mut W ) -> Result<(), std::io::Error> { + pub fn write_packet( &self, w: &mut W ) -> Result<(), Error> { match self.to_packet() { Ok(body) => { w.write_all( &body ) @@ -324,18 +328,60 @@ impl Value { } } - 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.")); + pub fn bytes_to_read( r: &[u8] ) -> Result { + if r.len() < 5 { + Ok(BytesToRead::Estimate(5)) + } else { + if r[0] != 1 { + return Err(Error::new(ErrorKind::InvalidData, "Invalid gats packet version.")); + } + if let Ok(ar) = r[1..5].try_into() { + Ok(BytesToRead::Final(i32::from_be_bytes( ar ) as usize)) + } else { + Err(Error::new(ErrorKind::UnexpectedEof, "Insufficient data presented to decode packet header.")) + } + } + } + + pub fn from_packet( r: &[u8] ) -> Result { + if r.len() < 5 { + return Err(Error::new(ErrorKind::UnexpectedEof, "Insufficient data presented to decode packet header.")); + } + if r[0] != 1 { + return Err(Error::new(ErrorKind::InvalidData, "Invalid gats packet version.")); + } + let size = if let Ok(ar) = r[1..5].try_into() { + i32::from_be_bytes( ar ) + } else { + return Err(Error::new(ErrorKind::UnexpectedEof, "Insufficient data presented to decode packet header.")); + }; + if r.len() != size as usize { + return Err(Error::new(ErrorKind::InvalidData, "Packet buffer is the wrong length.")); + } + Ok(Value::read( &mut Cursor::new( &r[5..] ) )?) + } + + pub fn read_packet( r: &mut R ) -> Result { + let mut buf = Vec::::new(); + let mut fill = 0usize; + loop { + match Value::bytes_to_read( &buf ) { + Ok(BytesToRead::Estimate(size)) => { + buf.resize(size, 0u8); + r.read_exact( &mut buf[fill..] )?; + fill = buf.len(); + } + Ok(BytesToRead::Final(size)) => { + buf.resize(size, 0u8); + r.read_exact( &mut buf[fill..] )?; + //fill = buf.len(); + return Value::from_packet( &buf ); + } + Err(e) => { + return Err(e); + } + } } - 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 ) )?) } } @@ -346,25 +392,6 @@ mod tests { use std::fs::File; use std::io::Cursor; - #[test] - fn write_file1() -> Result<(),Box> { - let mut f = File::create("test.gats")?; - 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)), - ])); - v.write_packet( &mut f )?; - Ok(()) - } - #[test] fn round_int() -> Result<(),Box> { let v = Value::Integer(555666); @@ -469,4 +496,24 @@ mod tests { assert!( v == v2 ); Ok(()) } + + #[test] + fn packet_1() -> 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 buf = v.to_packet()?; + let v2 = Value::from_packet( &buf )?; + assert!( v == v2 ); + Ok(()) + } } -- cgit v1.2.3