diff options
| author | Mike Buland <mike@xagasoft.com> | 2025-11-19 11:50:43 -0800 |
|---|---|---|
| committer | Mike Buland <mike@xagasoft.com> | 2025-11-19 11:50:43 -0800 |
| commit | a9c4c9c2cbf70686d5f21f6bd1dd5c477f4a5085 (patch) | |
| tree | ee46a942628fb005ecda8a241246d24dc763a9c5 /rust | |
| parent | 18c320a5d659090604696cd9466618e82a0d2358 (diff) | |
| download | libgats-a9c4c9c2cbf70686d5f21f6bd1dd5c477f4a5085.tar.gz libgats-a9c4c9c2cbf70686d5f21f6bd1dd5c477f4a5085.tar.bz2 libgats-a9c4c9c2cbf70686d5f21f6bd1dd5c477f4a5085.tar.xz libgats-a9c4c9c2cbf70686d5f21f6bd1dd5c477f4a5085.zip | |
Read side is almost done, just packet work to go.
Diffstat (limited to '')
| -rw-r--r-- | rust/src/lib.rs | 287 |
1 files changed, 283 insertions, 4 deletions
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; | |||
| 3 | use std::io::{Write,Read}; | 3 | use std::io::{Write,Read}; |
| 4 | use std::num::FpCategory; | 4 | use std::num::FpCategory; |
| 5 | use std::sync::LazyLock; | 5 | use std::sync::LazyLock; |
| 6 | use std::io::Cursor; | ||
| 6 | 7 | ||
| 8 | #[derive(PartialEq)] | ||
| 7 | pub enum Value { | 9 | pub enum Value { |
| 8 | Integer(i64), | 10 | Integer(i64), |
| 9 | ByteString(Vec<u8>), | 11 | ByteString(Vec<u8>), |
| @@ -14,6 +16,44 @@ pub enum Value { | |||
| 14 | Nothing, | 16 | Nothing, |
| 15 | } | 17 | } |
| 16 | 18 | ||
| 19 | pub enum ValueParse { | ||
| 20 | Value(Value), | ||
| 21 | EndMarker, | ||
| 22 | } | ||
| 23 | |||
| 24 | impl PartialEq<i64> for Value { | ||
| 25 | fn eq(&self, other: &i64) -> bool { | ||
| 26 | if let Value::Integer(x) = self { | ||
| 27 | x == other | ||
| 28 | } else { | ||
| 29 | false | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | impl PartialEq<Vec<u8>> for Value { | ||
| 35 | fn eq(&self, other: &Vec<u8>) -> bool { | ||
| 36 | if let Value::ByteString(x) = self { | ||
| 37 | x == other | ||
| 38 | } else { | ||
| 39 | false | ||
| 40 | } | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | impl PartialEq<bool> for Value { | ||
| 45 | fn eq(&self, other: &bool) -> bool { | ||
| 46 | if let Value::Boolean(x) = self { | ||
| 47 | x == other | ||
| 48 | } else { | ||
| 49 | false | ||
| 50 | } | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | impl std::cmp::Eq for Value { | ||
| 55 | } | ||
| 56 | |||
| 17 | static FLOAT_DIVISOR: LazyLock<f64> = LazyLock::new(|| (256_f64).ln()); | 57 | static FLOAT_DIVISOR: LazyLock<f64> = LazyLock::new(|| (256_f64).ln()); |
| 18 | 58 | ||
| 19 | fn write_packed_int( x: i64 ) -> Vec<u8> | 59 | fn write_packed_int( x: i64 ) -> Vec<u8> |
| @@ -154,15 +194,149 @@ impl Value { | |||
| 154 | Ok(()) | 194 | Ok(()) |
| 155 | } | 195 | } |
| 156 | 196 | ||
| 157 | pub fn write_packet<W: Write>( &self, w: &mut W ) -> Result<(), std::io::Error> { | 197 | fn read_parse<R: Read>(r: &mut R) -> Result<ValueParse, std::io::Error> { |
| 198 | let it = { | ||
| 199 | let mut it = [0u8]; | ||
| 200 | r.read_exact( &mut it )?; | ||
| 201 | it[0] | ||
| 202 | }; | ||
| 203 | match it as char { | ||
| 204 | '0' => Ok(ValueParse::Value(Value::Boolean(false))), | ||
| 205 | '1' => Ok(ValueParse::Value(Value::Boolean(true))), | ||
| 206 | 'n' => Ok(ValueParse::Value(Value::Nothing)), | ||
| 207 | 'e' => Ok(ValueParse::EndMarker), | ||
| 208 | 'i' => Ok(ValueParse::Value(Value::Integer(read_packed_int(r)?))), | ||
| 209 | 's' => { | ||
| 210 | let len = read_packed_int(r)?; | ||
| 211 | let mut body = vec![0; len as usize]; | ||
| 212 | r.read_exact( &mut body )?; | ||
| 213 | Ok(ValueParse::Value(Value::ByteString(body))) | ||
| 214 | } | ||
| 215 | 'l' => { | ||
| 216 | let mut body = Vec::<Value>::new(); | ||
| 217 | loop { | ||
| 218 | match Value::read_parse(r)? { | ||
| 219 | ValueParse::Value(v) => body.push(v), | ||
| 220 | ValueParse::EndMarker => break, | ||
| 221 | } | ||
| 222 | } | ||
| 223 | Ok(ValueParse::Value(Value::List(body))) | ||
| 224 | } | ||
| 225 | 'f' => { | ||
| 226 | let (lng, neg) = { | ||
| 227 | let lng = read_packed_int( r )?; | ||
| 228 | if lng < 0 { | ||
| 229 | (-lng, true) | ||
| 230 | } else { | ||
| 231 | (lng, false) | ||
| 232 | } | ||
| 233 | }; | ||
| 234 | let mut value = 0.0f64; | ||
| 235 | let mut buf = vec![0u8; lng as usize]; | ||
| 236 | r.read_exact( &mut buf )?; | ||
| 237 | for b in buf[1..].iter().rev() { | ||
| 238 | value = (value+(*b as f64))*(1.0/256.0); | ||
| 239 | } | ||
| 240 | value += buf[0] as f64; | ||
| 241 | let scale = read_packed_int( r )?; | ||
| 242 | value *= 256.0f64.powi( scale as i32 ); | ||
| 243 | if neg { | ||
| 244 | Ok(ValueParse::Value(Value::Float(-value))) | ||
| 245 | } else { | ||
| 246 | Ok(ValueParse::Value(Value::Float(value))) | ||
| 247 | } | ||
| 248 | } | ||
| 249 | 'F' => { | ||
| 250 | let st = { | ||
| 251 | let mut st = [0u8]; | ||
| 252 | r.read_exact( &mut st )?; | ||
| 253 | st[0] | ||
| 254 | }; | ||
| 255 | match st as char { | ||
| 256 | 'N' => Ok(ValueParse::Value(Value::Float(f64::NAN))), | ||
| 257 | 'n' => Ok(ValueParse::Value(Value::Float(f64::NAN))), | ||
| 258 | 'I' => Ok(ValueParse::Value(Value::Float(f64::NEG_INFINITY))), | ||
| 259 | 'i' => Ok(ValueParse::Value(Value::Float(f64::INFINITY))), | ||
| 260 | 'Z' => Ok(ValueParse::Value(Value::Float(-0.0f64))), | ||
| 261 | 'z' => Ok(ValueParse::Value(Value::Float(0.0f64))), | ||
| 262 | _ => { | ||
| 263 | return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Unknown exceptional float subtype found.")); | ||
| 264 | } | ||
| 265 | } | ||
| 266 | } | ||
| 267 | 'd' => { | ||
| 268 | let mut body = HashMap::new(); | ||
| 269 | loop { | ||
| 270 | let k = match Value::read_parse(r)? { | ||
| 271 | ValueParse::Value(v) => { | ||
| 272 | if let Value::ByteString(s) = v { | ||
| 273 | if let Ok(s) = String::from_utf8(s) { | ||
| 274 | s | ||
| 275 | } else { | ||
| 276 | return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Keys must be utf8 compatbile strings.")); | ||
| 277 | } | ||
| 278 | } else { | ||
| 279 | return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Non-string cannot be dictionary key.")); | ||
| 280 | } | ||
| 281 | }, | ||
| 282 | ValueParse::EndMarker => break, | ||
| 283 | }; | ||
| 284 | let v = match Value::read_parse(r)? { | ||
| 285 | ValueParse::Value(v) => v, | ||
| 286 | ValueParse::EndMarker => { | ||
| 287 | return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Premature end marker in dictionary.")); | ||
| 288 | } | ||
| 289 | }; | ||
| 290 | body.insert( k, v ); | ||
| 291 | } | ||
| 292 | Ok(ValueParse::Value(Value::Dictionary(body))) | ||
| 293 | } | ||
| 294 | _ => { | ||
| 295 | Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid data type specified.")) | ||
| 296 | } | ||
| 297 | } | ||
| 298 | } | ||
| 299 | |||
| 300 | pub fn read<R: Read>(r: &mut R) -> Result<Value, std::io::Error> { | ||
| 301 | match Value::read_parse(r) { | ||
| 302 | Ok(ValueParse::Value(v)) => Ok(v), | ||
| 303 | Ok(ValueParse::EndMarker) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Unexpecetd EndMarker while parsing structure.")), | ||
| 304 | Err(e) => Err(e) | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | pub fn to_packet( &self ) -> Result<Vec<u8>, std::io::Error> { | ||
| 158 | let mut body : Vec<u8> = vec![1u8,0u8,0u8,0u8,0u8]; | 309 | let mut body : Vec<u8> = vec![1u8,0u8,0u8,0u8,0u8]; |
| 159 | self.write( &mut body )?; | 310 | self.write( &mut body )?; |
| 160 | let len = body.len() as u32; | 311 | let len = body.len() as u32; |
| 161 | body[1..5].copy_from_slice( &len.to_be_bytes() ); | 312 | body[1..5].copy_from_slice( &len.to_be_bytes() ); |
| 162 | w.write_all( &body ) | 313 | Ok(body) |
| 163 | } | 314 | } |
| 164 | 315 | ||
| 316 | pub fn write_packet<W: Write>( &self, w: &mut W ) -> Result<(), std::io::Error> { | ||
| 317 | match self.to_packet() { | ||
| 318 | Ok(body) => { | ||
| 319 | w.write_all( &body ) | ||
| 320 | } | ||
| 321 | Err(e) => { | ||
| 322 | Err(e) | ||
| 323 | } | ||
| 324 | } | ||
| 325 | } | ||
| 165 | 326 | ||
| 327 | pub fn from_packet<R: Read>( r: &mut R ) -> Result<Value, std::io::Error> { | ||
| 328 | let mut ver = [0u8]; | ||
| 329 | let mut size = [0u8; 4]; | ||
| 330 | r.read_exact( &mut ver )?; | ||
| 331 | if ver[0] != 1 { | ||
| 332 | return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid gats packet version.")); | ||
| 333 | } | ||
| 334 | r.read_exact( &mut size )?; | ||
| 335 | let size = i32::from_be_bytes( size ); | ||
| 336 | let mut buf = vec![0u8; size as usize -5]; | ||
| 337 | r.read_exact( &mut buf )?; | ||
| 338 | Ok(Value::read( &mut Cursor::new( buf ) )?) | ||
| 339 | } | ||
| 166 | } | 340 | } |
| 167 | 341 | ||
| 168 | #[cfg(test)] | 342 | #[cfg(test)] |
| @@ -170,7 +344,7 @@ mod tests { | |||
| 170 | use super::*; | 344 | use super::*; |
| 171 | use core::error::Error; | 345 | use core::error::Error; |
| 172 | use std::fs::File; | 346 | use std::fs::File; |
| 173 | use std::io::prelude::*; | 347 | use std::io::Cursor; |
| 174 | 348 | ||
| 175 | #[test] | 349 | #[test] |
| 176 | fn write_file1() -> Result<(),Box<dyn Error>> { | 350 | fn write_file1() -> Result<(),Box<dyn Error>> { |
| @@ -187,7 +361,112 @@ mod tests { | |||
| 187 | ("null".to_string(), Value::Nothing), | 361 | ("null".to_string(), Value::Nothing), |
| 188 | ("float".to_string(), Value::Float(123.456)), | 362 | ("float".to_string(), Value::Float(123.456)), |
| 189 | ])); | 363 | ])); |
| 190 | v.write_packet( &mut f ); | 364 | v.write_packet( &mut f )?; |
| 365 | Ok(()) | ||
| 366 | } | ||
| 367 | |||
| 368 | #[test] | ||
| 369 | fn round_int() -> Result<(),Box<dyn Error>> { | ||
| 370 | let v = Value::Integer(555666); | ||
| 371 | let mut buf = Vec::<u8>::new(); | ||
| 372 | v.write( &mut buf )?; | ||
| 373 | let v2 = Value::read( &mut Cursor::new(buf) )?; | ||
| 374 | assert!( v == v2 ); | ||
| 375 | assert!( v == 555666 ); | ||
| 376 | Ok(()) | ||
| 377 | } | ||
| 378 | |||
| 379 | #[test] | ||
| 380 | fn round_str() -> Result<(),Box<dyn Error>> { | ||
| 381 | let v = Value::ByteString(vec![1,1,2,3,5,8,13,21,34]); | ||
| 382 | let mut buf = Vec::<u8>::new(); | ||
| 383 | v.write( &mut buf )?; | ||
| 384 | let v2 = Value::read( &mut Cursor::new(buf) )?; | ||
| 385 | let v3 = Value::ByteString(vec![1,1,2,3,5,8,13,21,35]); | ||
| 386 | assert!( v == v2 ); | ||
| 387 | assert!( v != v3 ); | ||
| 388 | assert!( v == vec![1,1,2,3,5,8,13,21,34] ); | ||
| 389 | Ok(()) | ||
| 390 | } | ||
| 391 | |||
| 392 | #[test] | ||
| 393 | fn round_bool_true() -> Result<(),Box<dyn Error>> { | ||
| 394 | let v = Value::Boolean(true); | ||
| 395 | let mut buf = Vec::<u8>::new(); | ||
| 396 | v.write( &mut buf )?; | ||
| 397 | let v2 = Value::read( &mut Cursor::new(buf) )?; | ||
| 398 | let v3 = Value::Boolean(false); | ||
| 399 | assert!( v == v2 ); | ||
| 400 | assert!( v != v3 ); | ||
| 401 | assert!( v == true ); | ||
| 402 | Ok(()) | ||
| 403 | } | ||
| 404 | |||
| 405 | #[test] | ||
| 406 | fn round_bool_false() -> Result<(),Box<dyn Error>> { | ||
| 407 | let v = Value::Boolean(false); | ||
| 408 | let mut buf = Vec::<u8>::new(); | ||
| 409 | v.write( &mut buf )?; | ||
| 410 | let v2 = Value::read( &mut Cursor::new(buf) )?; | ||
| 411 | let v3 = Value::Boolean(true); | ||
| 412 | assert!( v == v2 ); | ||
| 413 | assert!( v != v3 ); | ||
| 414 | assert!( v == false ); | ||
| 415 | Ok(()) | ||
| 416 | } | ||
| 417 | |||
| 418 | #[test] | ||
| 419 | fn round_list() -> Result<(),Box<dyn Error>> { | ||
| 420 | let v = Value::List(vec![ | ||
| 421 | Value::Integer(1), Value::Integer(1), Value::Integer(2), | ||
| 422 | Value::Integer(3), Value::Integer(5), Value::Integer(8), | ||
| 423 | Value::Integer(13), Value::Integer(21), Value::Integer(34), | ||
| 424 | ]); | ||
| 425 | let mut buf = Vec::<u8>::new(); | ||
| 426 | v.write( &mut buf )?; | ||
| 427 | let v2 = Value::read( &mut Cursor::new(buf) )?; | ||
| 428 | assert!( v == v2 ); | ||
| 429 | Ok(()) | ||
| 430 | } | ||
| 431 | |||
| 432 | #[test] | ||
| 433 | fn round_dictionary() -> Result<(), Box<dyn Error>> { | ||
| 434 | let v = Value::Dictionary(HashMap::from([ | ||
| 435 | ("biggerint".to_string(), Value::Integer(98765)), | ||
| 436 | ("negint".to_string(), Value::Integer(-98765)), | ||
| 437 | ("integer".to_string(), Value::Integer(44)), | ||
| 438 | ("boolean".to_string(), Value::Boolean(true)), | ||
| 439 | ("list".to_string(), Value::List(vec![ | ||
| 440 | Value::Integer(1), Value::Integer(1), Value::Integer(2), | ||
| 441 | Value::Integer(3), Value::Integer(5), Value::Integer(8), | ||
| 442 | ])), | ||
| 443 | ("null".to_string(), Value::Nothing), | ||
| 444 | ("float".to_string(), Value::Float(123.456)), | ||
| 445 | ])); | ||
| 446 | let mut buf = Vec::<u8>::new(); | ||
| 447 | v.write( &mut buf )?; | ||
| 448 | let v2 = Value::read( &mut Cursor::new(buf) )?; | ||
| 449 | assert!( v == v2 ); | ||
| 450 | Ok(()) | ||
| 451 | } | ||
| 452 | |||
| 453 | #[test] | ||
| 454 | fn round_null() -> Result<(), Box<dyn Error>> { | ||
| 455 | let v = Value::Nothing; | ||
| 456 | let mut buf = Vec::<u8>::new(); | ||
| 457 | v.write( &mut buf )?; | ||
| 458 | let v2 = Value::read( &mut Cursor::new(buf) )?; | ||
| 459 | assert!( v == v2 ); | ||
| 460 | Ok(()) | ||
| 461 | } | ||
| 462 | |||
| 463 | #[test] | ||
| 464 | fn round_float() -> Result<(), Box<dyn Error>> { | ||
| 465 | let v = Value::Float(123.456); | ||
| 466 | let mut buf = Vec::<u8>::new(); | ||
| 467 | v.write( &mut buf )?; | ||
| 468 | let v2 = Value::read( &mut Cursor::new(buf) )?; | ||
| 469 | assert!( v == v2 ); | ||
| 191 | Ok(()) | 470 | Ok(()) |
| 192 | } | 471 | } |
| 193 | } | 472 | } |
