use std::collections::HashMap; use std::vec::Vec; use std::io::{Write,Read,Cursor,Error,ErrorKind}; use std::num::FpCategory; use std::sync::LazyLock; #[derive(PartialEq)] pub enum Value { Integer(i64), ByteString(Vec), Boolean(bool), List(Vec), Dictionary(HashMap), Float(f64), Nothing, } pub enum BytesToRead { Estimate(usize), Final(usize), } 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 { let mut w = Vec::::with_capacity(10); let mut v = x; let mut bb = if x < 0 { v = -v; 0x40_u8 } else { 0x00_u8 } | (v&0x3F) as u8 | if v > (v & 0x3F) { 0x80_u8 } else { 0x00_u8 }; w.push(bb); v >>= 6; while v > 0 { bb = (v & 0x7F) as u8 | if v > (v & 0x7F) { 0x80_u8 } else { 0x00_u8 }; w.push(bb); v >>= 7; } w } fn read_packed_int( r: &mut R ) -> Result { let mut out : i64; let mut bb = [0u8]; r.read_exact( &mut bb )?; let negative = (bb[0]&0x40_u8) == 0x40_u8; out = (bb[0]&0x3F_u8) as i64; let mut c = 0; while (bb[0]&0x80_u8) != 0 { r.read_exact( &mut bb )?; out |= ((bb[0]&0x7F_u8) as i64) << (6+7*c); c += 1; } if negative { Ok(-out) } else { Ok(out) } } impl Value { pub fn write(&self, w: &mut W) -> Result<(), Error> { match self { Self::Integer(x) => { let bb = [b'i']; w.write_all(&bb)?; w.write_all(&write_packed_int( *x ))?; }, Self::ByteString(s) => { let bb = [b's']; w.write_all(&bb)?; w.write_all(&write_packed_int( s.len() as i64 ))?; w.write_all( s )?; }, Self::Boolean(b) => { let mut bb = [0u8]; bb[0] = if *b { b'1' } else { b'0' }; w.write_all( &bb )?; }, Self::List(l) => { let mut bb = [b'l']; w.write_all(&bb)?; for v in l { v.write( w )?; } bb[0] = b'e'; w.write_all(&bb)?; }, Self::Dictionary(d) => { let mut bb = [b'd']; w.write_all(&bb)?; for (k, v) in d { (Value::ByteString( k.clone().into_bytes() )).write( w )?; v.write( w )?; } bb[0] = b'e'; w.write_all(&bb)?; }, Self::Float(f) => { match f.classify() { FpCategory::Nan => { let mut bb = [b'F', 0u8]; bb[1] = if f.is_sign_negative() { 'N' } else { 'n' } as u8; w.write_all( &bb )?; }, FpCategory::Infinite => { let mut bb = [b'F', 0u8]; bb[1] = if f.is_sign_negative() { 'I' } else { 'i' } as u8; w.write_all( &bb )?; }, FpCategory::Zero => { let mut bb = [b'F', 0u8]; bb[1] = if f.is_sign_negative() { 'Z' } else { 'z' } as u8; w.write_all( &bb )?; }, FpCategory::Subnormal => { let mut bb = [b'F', 0u8]; // The format doesn't account for these...uh...make them zero? bb[1] = if f.is_sign_negative() { 'Z' } else { 'z' } as u8; w.write_all( &bb )?; }, FpCategory::Normal => { let bb = [b'f']; w.write_all( &bb )?; let mut bin = Vec::::with_capacity(10); let (negative, d) = if f.is_sign_negative() { (true, -*f) } else { (false, *f) }; let scale : i64 = (d.ln() / *FLOAT_DIVISOR) as i64; let scale = if scale < 0 { -1 } else { scale }; let mut d = d / 256.0_f64.powf( scale as f64 ); bin.push( d as u8 ); d = d.fract(); for _ in 0..15 { d *= 256.0; bin.push( d as u8 ); d = d.fract(); if d == 0.0 { break; } } if negative { w.write_all( &write_packed_int( -(bin.len() as i64) ) )?; } else { w.write_all( &write_packed_int( bin.len() as i64 ) )?; } w.write_all( &bin )?; w.write_all( &write_packed_int( scale ) )?; }, } }, Self::Nothing => { let bb = [b'n']; w.write_all( &bb )?; }, } Ok(()) } 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(); while let ValueParse::Value(v) = Value::read_parse(r)? { body.push(v); } 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))), _ =>Err(Error::new(ErrorKind::InvalidData, "Unknown exceptional float subtype found.")), } } 'd' => { let mut body = HashMap::new(); while let ValueParse::Value(k) = Value::read_parse(r)? { let k = if let Value::ByteString(s) = k { if let Ok(s) = String::from_utf8(s) { s } else { return Err(Error::new(ErrorKind::InvalidData, "Keys must be utf8 compatbile strings.")); } } else { return Err(Error::new(ErrorKind::InvalidData, "Non-string cannot be dictionary key.")); }; let v = match Value::read_parse(r)? { ValueParse::Value(v) => v, ValueParse::EndMarker => { return Err(Error::new(ErrorKind::InvalidData, "Premature end marker in dictionary.")); } }; body.insert( k, v ); } Ok(ValueParse::Value(Value::Dictionary(body))) } _ => { Err(Error::new(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(Error::new(ErrorKind::InvalidData, "Unexpecetd EndMarker while parsing structure.")), Err(e) => Err(e) } } 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; body[1..5].copy_from_slice( &len.to_be_bytes() ); Ok(body) } pub fn write_packet( &self, w: &mut W ) -> Result<(), Error> { match self.to_packet() { Ok(body) => { w.write_all( &body ) } Err(e) => { Err(e) } } } 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.")); } 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); } } } } } #[cfg(test)] mod tests { use super::*; use core::error::Error; use std::fs::File; use std::io::Cursor; #[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(()) } #[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(()) } }