diff --git a/src/lazy/binary/raw/v1_1/reader.rs b/src/lazy/binary/raw/v1_1/reader.rs index 7b9efa7c..e01a2c2c 100644 --- a/src/lazy/binary/raw/v1_1/reader.rs +++ b/src/lazy/binary/raw/v1_1/reader.rs @@ -377,6 +377,47 @@ mod tests { Ok(()) } + #[test] + #[allow(clippy::approx_constant)] + fn floats() -> IonResult<()> { + #[rustfmt::skip] + let data: Vec = vec![ + // IVM + 0xe0, 0x01, 0x01, 0xea, + // 0e0 + 0x5A, + + // 3.14 (half-precision) + // 0x5B, 0x42, 0x47, + + // 3.1415927 (single-precision) + 0x5C, 0xdb, 0x0F, 0x49, 0x40, + + // 3.141592653589793 (double-precision) + 0x5D, 0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40, + ]; + + let mut reader = LazyRawBinaryReader_1_1::new(&data); + let _ivm = reader.next()?.expect_ivm()?; + + assert_eq!(reader.next()?.expect_value()?.read()?.expect_float()?, 0.0); + + // TODO: Implement Half-precision. + // assert_eq!(reader.next()?.expect_value()?.read()?.expect_float()?, 3.14); + + assert_eq!( + reader.next()?.expect_value()?.read()?.expect_float()? as f32, + 3.1415927f32, + ); + + assert_eq!( + reader.next()?.expect_value()?.read()?.expect_float()?, + std::f64::consts::PI, + ); + + Ok(()) + } + fn blobs() -> IonResult<()> { let data: Vec = vec![ 0xe0, 0x01, 0x01, 0xea, // IVM diff --git a/src/lazy/binary/raw/v1_1/type_descriptor.rs b/src/lazy/binary/raw/v1_1/type_descriptor.rs index 2d76a09c..96dda27e 100644 --- a/src/lazy/binary/raw/v1_1/type_descriptor.rs +++ b/src/lazy/binary/raw/v1_1/type_descriptor.rs @@ -41,6 +41,7 @@ impl Opcode { let (opcode_type, length_code, ion_type) = match (high_nibble, low_nibble) { (0x5, 0x0..=0x8) => (Integer, low_nibble, Some(IonType::Int)), + (0x5, 0xA..=0xD) => (Float, low_nibble, Some(IonType::Float)), (0x5, 0xE..=0xF) => (Boolean, low_nibble, Some(IonType::Bool)), (0x8, _) => (String, low_nibble, Some(IonType::String)), (0x9, _) => (InlineSymbol, low_nibble, Some(IonType::Symbol)), @@ -114,6 +115,8 @@ impl Header { use LengthType::*; match (self.ion_type_code, self.length_code) { (OpcodeType::Boolean, 0xE..=0xF) => InOpcode(0), + (OpcodeType::Float, 0xA) => InOpcode(0), + (OpcodeType::Float, 0xB..=0xD) => InOpcode(1 << (self.length_code - 0xA)), (OpcodeType::Integer, n) => InOpcode(n), (OpcodeType::Nop, 0xC) => InOpcode(0), (OpcodeType::NullNull, 0xA) => InOpcode(0), diff --git a/src/lazy/binary/raw/v1_1/value.rs b/src/lazy/binary/raw/v1_1/value.rs index ef5b697a..d1b87e63 100644 --- a/src/lazy/binary/raw/v1_1/value.rs +++ b/src/lazy/binary/raw/v1_1/value.rs @@ -236,7 +236,28 @@ impl<'top> LazyRawBinaryValue_1_1<'top> { /// Helper method called by [`Self::read`]. Reads the current value as a float. fn read_float(&self) -> ValueParseResult<'top, BinaryEncoding_1_1> { - todo!(); + debug_assert!(self.encoded_value.ion_type() == IonType::Float); + + let value = match self.encoded_value.value_body_length { + 8 => { + let mut buffer = [0; 8]; + let val_bytes = self.input.bytes_range(1, 8); + buffer[..8].copy_from_slice(val_bytes); + + f64::from_le_bytes(buffer) + } + 4 => { + let mut buffer = [0; 4]; + let val_bytes = self.input.bytes_range(1, 4); + buffer[..4].copy_from_slice(val_bytes); + + f32::from_le_bytes(buffer).into() + } + 2 => todo!("implement half-precision floats"), + 0 => 0.0f64, + _ => unreachable!("found a float value with illegal byte size"), + }; + Ok(RawValueRef::Float(value)) } /// Helper method called by [`Self::read`]. Reads the current value as a decimal.