Skip to content

Commit

Permalink
Add 1.1 binary reader support for floats (#756)
Browse files Browse the repository at this point in the history
* Add 1.1 binary reader support for floats

* Address PR feedback

* Address renamed field..

* Address feedback; replace use of `slice` with `byte_range` since we don't need the ImmutableBuffer
  • Loading branch information
nirosys authored May 10, 2024
1 parent 2c86c00 commit ba7718d
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
41 changes: 41 additions & 0 deletions src/lazy/binary/raw/v1_1/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,47 @@ mod tests {
Ok(())
}

#[test]
#[allow(clippy::approx_constant)]
fn floats() -> IonResult<()> {
#[rustfmt::skip]
let data: Vec<u8> = 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<u8> = vec![
0xe0, 0x01, 0x01, 0xea, // IVM
Expand Down
3 changes: 3 additions & 0 deletions src/lazy/binary/raw/v1_1/type_descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down Expand Up @@ -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),
Expand Down
23 changes: 22 additions & 1 deletion src/lazy/binary/raw/v1_1/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit ba7718d

Please sign in to comment.