use std::collections::HashMap; use std::vec::Vec; use std::io::{Write,Read}; use std::num::FpCategory; pub enum Value { Integer(i64), ByteString(Vec), Boolean(bool), List(Vec), Dictionary(HashMap), Float(f64), Nothing, } // const FLOAT_DIVISOR: f64 = (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 } | if v > (v & 0x3F) { 0x80_u8 } else { 0x00_u8 }; w.push(bb); v = v >> 6; while v > 0 { bb = (v & 0x7F) as u8 | if v > (v & 0x7F) { 0x80_u8 } else { 0x00_u8 }; w.push(bb); v = v >> 7; } w } fn read_packed_int( r: &mut R ) -> Result { let mut out : i64; let mut bb = [0u8]; r.read( &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( &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<(), std::io::Error> { match self { Self::Integer(x) => { let mut bb = [0u8]; bb[0] = 'i' as u8; w.write_all(&bb)?; w.write_all(&write_packed_int( *x ))?; }, Self::ByteString(s) => { let mut bb = [0u8]; bb[0] = 's' as u8; 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 { '1' } else { '0' } as u8; w.write_all( &bb )?; }, Self::List(l) => { }, Self::Dictionary(d) => { }, Self::Float(f) => { let mut bb = ['F' as u8, 0u8]; match f.classify() { FpCategory::Nan => { bb[1] = if f.is_sign_negative() { 'N' } else { 'n' } as u8; w.write_all( &bb )?; }, FpCategory::Infinite => { bb[1] = if f.is_sign_negative() { 'I' } else { 'i' } as u8; w.write_all( &bb )?; }, FpCategory::Zero => { bb[1] = if f.is_sign_negative() { 'Z' } else { 'z' } as u8; w.write_all( &bb )?; }, FpCategory::Subnormal => { // 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 div = 256f64.ln(); todo!(); }, } }, Self::Nothing => { }, } Ok(()) } } pub fn add(left: u64, right: u64) -> u64 { left + right } #[cfg(test)] mod tests { use super::*; #[test] fn it_works() { let result = add(2, 2); assert_eq!(result, 4); } }