diff --git a/src/lazy/binary/raw/v1_1/reader.rs b/src/lazy/binary/raw/v1_1/reader.rs index e01a2c2cb..d180bef12 100644 --- a/src/lazy/binary/raw/v1_1/reader.rs +++ b/src/lazy/binary/raw/v1_1/reader.rs @@ -457,4 +457,30 @@ mod tests { Ok(()) } + + #[test] + fn nulls() -> IonResult<()> { + #[rustfmt::skip] + let data: Vec<([u8; 2], IonType)> = vec![ + ([0xEB, 0x00], IonType::Bool), // null.bool + ([0xEB, 0x01], IonType::Int), // null.int + ([0xEB, 0x02], IonType::Float), // null.float + ([0xEB, 0x03], IonType::Decimal), // null.decimal + ([0xEB, 0x04], IonType::Timestamp), // null.timestamp + ([0xEB, 0x05], IonType::String), // null.string + ([0xEB, 0x06], IonType::Symbol), // null.symbol + ([0xEB, 0x07], IonType::Blob), // null.blob + ([0xEB, 0x08], IonType::Clob), // null.clob + ([0xEB, 0x09], IonType::List), // null.list + ([0xEB, 0x0A], IonType::SExp), // null.sexp + ([0xEB, 0x0B], IonType::Struct), // null.struct + ]; + + for (data, expected_type) in data { + let mut reader = LazyRawBinaryReader_1_1::new(&data); + let actual_type = reader.next()?.expect_value()?.read()?.expect_null()?; + assert_eq!(actual_type, expected_type); + } + Ok(()) + } } diff --git a/src/lazy/binary/raw/v1_1/type_descriptor.rs b/src/lazy/binary/raw/v1_1/type_descriptor.rs index 96dda27ee..8556c5b13 100644 --- a/src/lazy/binary/raw/v1_1/type_descriptor.rs +++ b/src/lazy/binary/raw/v1_1/type_descriptor.rs @@ -14,6 +14,20 @@ pub struct Opcode { /// A statically defined array of TypeDescriptor that allows a binary reader to map a given /// byte (`u8`) to a `TypeDescriptor` without having to perform any masking or bitshift operations. pub(crate) static ION_1_1_OPCODES: &[Opcode; 256] = &init_opcode_cache(); +pub(crate) static ION_1_1_TYPED_NULL_TYPES: &[IonType; 12] = &[ + IonType::Bool, + IonType::Int, + IonType::Float, + IonType::Decimal, + IonType::Timestamp, + IonType::String, + IonType::Symbol, + IonType::Blob, + IonType::Clob, + IonType::List, + IonType::SExp, + IonType::Struct, +]; const DEFAULT_HEADER: Opcode = Opcode { opcode_type: OpcodeType::Nop, @@ -48,6 +62,7 @@ impl Opcode { (0xE, 0x0) => (IonVersionMarker, low_nibble, None), (0xE, 0x1..=0x3) => (SymbolAddress, low_nibble, Some(IonType::Symbol)), (0xE, 0xA) => (NullNull, low_nibble, Some(IonType::Null)), + (0xE, 0xB) => (TypedNull, low_nibble, Some(IonType::Null)), (0xE, 0xC..=0xD) => (Nop, low_nibble, None), (0xF, 0x5) => (LargeInteger, low_nibble, Some(IonType::Int)), (0xF, 0x8) => (String, 0xFF, Some(IonType::String)), // 0xFF indicates >15 byte string. @@ -123,6 +138,7 @@ impl Header { (OpcodeType::String, 0..=15) => InOpcode(self.length_code), (OpcodeType::InlineSymbol, n) if n < 16 => InOpcode(n), (OpcodeType::SymbolAddress, n) if n < 4 => InOpcode(n), + (OpcodeType::TypedNull, _) => InOpcode(1), _ => FlexUIntFollows, } } diff --git a/src/lazy/binary/raw/v1_1/value.rs b/src/lazy/binary/raw/v1_1/value.rs index d1b87e63d..8b6e34356 100644 --- a/src/lazy/binary/raw/v1_1/value.rs +++ b/src/lazy/binary/raw/v1_1/value.rs @@ -11,7 +11,8 @@ use crate::{ raw::{ v1_1::{ annotations_iterator::RawBinaryAnnotationsIterator_1_1, - immutable_buffer::ImmutableBuffer, Header, OpcodeType, + immutable_buffer::ImmutableBuffer, type_descriptor::ION_1_1_TYPED_NULL_TYPES, + Header, OpcodeType, }, value::ValueParseResult, }, @@ -150,8 +151,13 @@ impl<'top> LazyRawBinaryValue_1_1<'top> { /// or [`LazyStruct`](crate::lazy::struct::LazyStruct) that can be traversed to access the container's contents. pub fn read(&self) -> ValueParseResult<'top, BinaryEncoding_1_1> { if self.is_null() { - let raw_value_ref = RawValueRef::Null(self.ion_type()); - return Ok(raw_value_ref); + let ion_type = if self.encoded_value.header.ion_type_code == OpcodeType::TypedNull { + let body = self.value_body()?; + ION_1_1_TYPED_NULL_TYPES[body[0] as usize] + } else { + self.ion_type() + }; + return Ok(RawValueRef::Null(ion_type)); } match self.ion_type() {