diff --git a/src/basic.rs b/src/basic.rs index 016cc6f..1019be1 100644 --- a/src/basic.rs +++ b/src/basic.rs @@ -3,6 +3,7 @@ /// use byteorder::{ByteOrder, BigEndian}; use std::io; +use std::fmt; pub type OResult = Result; @@ -14,7 +15,6 @@ pub enum ErrType { Failed(String), } - pub fn fail(input: &[u8], msg: String) -> IResult { Err((input, ErrType::Failed(msg))) } @@ -118,20 +118,21 @@ pub fn bitarray2int(bits: &[bool; 16]) -> u16 { } pub fn pack_bitarray(buf: &mut [u8], bits: &[bool; 16]) { - BigEndian::write_u16(buf, bitarray2int(bits)) + BigEndian::write_u16(buf, bitarray2int(bits)); } pub fn pack_int2(buf: &mut [u8], int: i16) { - BigEndian::write_i16(buf, int) + BigEndian::write_i16(buf, int); } pub fn pack_int4(buf: &mut [u8], int: i32) { - BigEndian::write_i32(buf, int) + BigEndian::write_i32(buf, int); } -pub fn pack_real8(buf: &mut [u8], fnum: f64) { - BigEndian::write_u64(buf, encode_real8(fnum)) +pub fn pack_real8(buf: &mut [u8], fnum: f64) -> Result<(), FloatTooBigError> { + BigEndian::write_u64(buf, encode_real8(fnum)?); + Ok(()) } pub fn pack_ascii(buf: &mut [u8], data: &[u8]) -> usize { @@ -156,8 +157,18 @@ pub fn pack_datetime(buf: &mut [u8], date: &[i16; 6]) { } +#[derive(Debug, Clone)] +pub struct FloatTooBigError { + float_value: f64, +} +impl fmt::Display for FloatTooBigError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Float {0} is too large for Real8", self.float_value) + } +} + /// Convert from float64 to GDS REAL8 representation. -pub fn encode_real8(fnum: f64) -> u64 { +pub fn encode_real8(fnum: f64) -> Result { // Split the ieee float bitfields let ieee = fnum.to_bits(); let sign = ieee & 0x8000_0000_0000_0000; @@ -166,7 +177,7 @@ pub fn encode_real8(fnum: f64) -> u64 { let subnorm = (ieee_exp == 0) & (ieee_mant != 0); if (ieee_exp == 0) & (ieee_mant == 0) { - return 0 + return Ok(0) } // IEEE normal double is (1 + ieee_mant / 2^52) * 2^(ieee_exp - 1023) @@ -207,7 +218,7 @@ pub fn encode_real8(fnum: f64) -> u64 { if gds_exp < -14 { // number is too small - return 0 + return Ok(0) } let neg_biased = gds_exp < 0; @@ -218,13 +229,13 @@ pub fn encode_real8(fnum: f64) -> u64 { let too_big = (gds_exp > 0x7f) & !subnorm; if too_big { - panic!("Number too big for real8 format"); //TODO error handling + return Err(FloatTooBigError{float_value: fnum}); } let gds_exp_bits = (gds_exp as u64) << 56; let real8 = sign | gds_exp_bits | gds_mant; - real8 + Ok(real8) } @@ -281,7 +292,7 @@ mod tests { #[should_panic] fn test_encode_real8_panic() { use crate::basic::encode_real8; - encode_real8(1e80); + encode_real8(1e80).unwrap(); } @@ -348,7 +359,7 @@ mod tests { const REALS: [f64; 5] = [1.0, -2.0, 1e-9, 1e-3, 1e-12]; for vv in REALS { print!("{vv}\n"); - assert!((decode_real8(encode_real8(vv)) - vv).abs() < f64::EPSILON); + assert!((decode_real8(encode_real8(vv).unwrap()) - vv).abs() < f64::EPSILON); } } @@ -359,7 +370,7 @@ mod tests { const REALS: [f64; COUNT] = [0.0, 1.0, -1.0, 0.5, 1e-9, 1e-3, 1e-12]; let mut buf = [10; 8 * COUNT]; for (ii, &vv) in REALS.iter().enumerate() { - pack_real8(&mut buf[ii * 8..], vv); + pack_real8(&mut buf[ii * 8..], vv).unwrap(); } for (ii, &vv) in REALS.iter().enumerate() { print!("{vv}\n"); diff --git a/src/record.rs b/src/record.rs index 7d04085..41921c4 100644 --- a/src/record.rs +++ b/src/record.rs @@ -279,7 +279,7 @@ impl RecordData for Real8 { } fn pack_into(buf: &mut [u8], data: &Self::InData) { - pack_real8(buf, *data) + pack_real8(buf, *data).expect(&format!("Float {0} too big for Real8", data)) } fn pack(data: &Self::InData) -> Self::ByteData { @@ -303,8 +303,8 @@ impl RecordData for Real8Pair { } fn pack_into(buf: &mut [u8], data: &Self::InData) { - pack_real8(&mut buf[8 * 0..], data.0); - pack_real8(&mut buf[8 * 1..], data.1); + pack_real8(&mut buf[8 * 0..], data.0).expect(&format!("Float.0 {0} too big for Real8", data.0)); + pack_real8(&mut buf[8 * 1..], data.1).expect(&format!("Float.1 {0} too big for Real8", data.1)); } fn pack(data: &Self::InData) -> Self::ByteData {