use std::fmt::{Debug, Formatter};
use std::mem;
use std::ops::Range;
use crate::binary::constants::v1_0::{length_codes, IVM};
use crate::binary::int::DecodedInt;
use crate::binary::var_int::VarInt;
use crate::binary::var_uint::VarUInt;
use crate::lazy::binary::encoded_value::EncodedBinaryValue;
use crate::lazy::binary::raw::r#struct::LazyRawBinaryFieldName_1_0;
use crate::lazy::binary::raw::type_descriptor::{Header, TypeDescriptor, ION_1_0_TYPE_DESCRIPTORS};
use crate::lazy::binary::raw::v1_1::binary_buffer::AnnotationsEncoding;
use crate::lazy::binary::raw::v1_1::value::BinaryValueEncoding;
use crate::lazy::binary::raw::value::{LazyRawBinaryValue_1_0, LazyRawBinaryVersionMarker_1_0};
use crate::lazy::decoder::LazyRawFieldExpr;
use crate::lazy::encoder::binary::v1_1::flex_int::FlexInt;
use crate::lazy::encoder::binary::v1_1::flex_uint::FlexUInt;
use crate::lazy::encoding::BinaryEncoding_1_0;
use crate::lazy::expanded::EncodingContextRef;
use crate::result::IonFailure;
use crate::{Int, IonError, IonResult};
#[derive(Clone, Copy)]
pub struct BinaryBuffer<'a> {
data: &'a [u8],
offset: usize,
context: EncodingContextRef<'a>,
}
impl Debug for BinaryBuffer<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "BinaryBuffer {{")?;
for byte in self.bytes().iter().take(16) {
write!(f, "{:x?} ", *byte)?;
}
write!(f, "}}")
}
}
impl PartialEq for BinaryBuffer<'_> {
fn eq(&self, other: &Self) -> bool {
self.offset == other.offset && self.data == other.data
}
}
pub(crate) type ParseResult<'a, T> = IonResult<(T, BinaryBuffer<'a>)>;
impl<'a> BinaryBuffer<'a> {
#[inline]
pub fn new(context: EncodingContextRef<'a>, data: &'a [u8]) -> BinaryBuffer<'a> {
Self::new_with_offset(context, data, 0)
}
pub fn new_with_offset(
context: EncodingContextRef<'a>,
data: &'a [u8],
offset: usize,
) -> BinaryBuffer<'a> {
BinaryBuffer {
context,
data,
offset,
}
}
pub fn bytes(&self) -> &'a [u8] {
self.data
}
pub fn bytes_range(&self, offset: usize, length: usize) -> &'a [u8] {
&self.data[offset..offset + length]
}
pub fn slice(&self, offset: usize, length: usize) -> BinaryBuffer<'a> {
BinaryBuffer {
data: self.bytes_range(offset, length),
offset: self.offset + offset,
context: self.context,
}
}
pub fn offset(&self) -> usize {
self.offset
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn range(&self) -> Range<usize> {
self.offset..self.offset + self.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn peek_next_byte(&self) -> Option<u8> {
self.data.first().copied()
}
pub fn peek_n_bytes(&self, n: usize) -> Option<&'a [u8]> {
self.data.get(..n)
}
#[inline]
pub fn consume(&self, num_bytes_to_consume: usize) -> Self {
debug_assert!(num_bytes_to_consume <= self.len());
Self {
data: &self.data[num_bytes_to_consume..],
offset: self.offset + num_bytes_to_consume,
context: self.context,
}
}
#[inline]
pub(crate) fn peek_type_descriptor(&self) -> IonResult<TypeDescriptor> {
if self.is_empty() {
return IonResult::incomplete("a type descriptor", self.offset());
}
let next_byte = self.data[0];
Ok(ION_1_0_TYPE_DESCRIPTORS[next_byte as usize])
}
pub fn read_ivm(self) -> ParseResult<'a, LazyRawBinaryVersionMarker_1_0<'a>> {
let bytes = self
.peek_n_bytes(IVM.len())
.ok_or_else(|| IonError::incomplete("an IVM", self.offset()))?;
match bytes {
[0xE0, major, minor, 0xEA] => {
let matched = BinaryBuffer::new_with_offset(self.context, bytes, self.offset);
let marker = LazyRawBinaryVersionMarker_1_0::new(matched, *major, *minor);
Ok((marker, self.consume(IVM.len())))
}
invalid_ivm => IonResult::decoding_error(format!("invalid IVM: {invalid_ivm:?}")),
}
}
pub fn read_flex_int(self) -> ParseResult<'a, FlexInt> {
let flex_int = FlexInt::read(self.bytes(), self.offset())?;
let remaining = self.consume(flex_int.size_in_bytes());
Ok((flex_int, remaining))
}
#[inline(always)]
pub fn read_flex_uint(self) -> ParseResult<'a, FlexUInt> {
let flex_uint = FlexUInt::read(self.bytes(), self.offset())?;
let remaining = self.consume(flex_uint.size_in_bytes());
Ok((flex_uint, remaining))
}
#[inline]
pub fn read_var_uint(self) -> ParseResult<'a, VarUInt> {
const LOWER_7_BITMASK: u8 = 0b0111_1111;
const HIGHEST_BIT_VALUE: u8 = 0b1000_0000;
let data = self.bytes();
if data.len() >= 2 {
let first_byte = data[0];
let mut magnitude = (LOWER_7_BITMASK & first_byte) as usize;
let num_bytes = if first_byte >= HIGHEST_BIT_VALUE {
1
} else {
let second_byte = data[1];
if second_byte < HIGHEST_BIT_VALUE {
return self.read_var_uint_slow();
}
let lower_seven = (LOWER_7_BITMASK & second_byte) as usize;
magnitude <<= 7;
magnitude |= lower_seven;
2
};
return Ok((VarUInt::new(magnitude, num_bytes), self.consume(num_bytes)));
}
self.read_var_uint_slow()
}
#[cold]
pub fn read_var_uint_slow(self) -> ParseResult<'a, VarUInt> {
const BITS_PER_ENCODED_BYTE: usize = 7;
const STORAGE_SIZE_IN_BITS: usize = mem::size_of::<usize>() * 8;
const MAX_ENCODED_SIZE_IN_BYTES: usize = STORAGE_SIZE_IN_BITS / BITS_PER_ENCODED_BYTE;
const LOWER_7_BITMASK: u8 = 0b0111_1111;
const HIGHEST_BIT_VALUE: u8 = 0b1000_0000;
let mut magnitude: usize = 0;
let mut encoded_size_in_bytes = 0;
for byte in self.bytes().iter().copied() {
encoded_size_in_bytes += 1;
magnitude <<= 7; let lower_seven = (LOWER_7_BITMASK & byte) as usize;
magnitude |= lower_seven;
if byte >= HIGHEST_BIT_VALUE {
if encoded_size_in_bytes > MAX_ENCODED_SIZE_IN_BYTES {
return Self::value_too_large(
"a VarUInt",
encoded_size_in_bytes,
MAX_ENCODED_SIZE_IN_BYTES,
);
}
return Ok((
VarUInt::new(magnitude, encoded_size_in_bytes),
self.consume(encoded_size_in_bytes),
));
}
}
IonResult::incomplete("a VarUInt", self.offset() + encoded_size_in_bytes)
}
pub fn read_var_int(self) -> ParseResult<'a, VarInt> {
const BITS_PER_ENCODED_BYTE: usize = 7;
const STORAGE_SIZE_IN_BITS: usize = mem::size_of::<i64>() * BITS_PER_BYTE;
const MAX_ENCODED_SIZE_IN_BYTES: usize = STORAGE_SIZE_IN_BITS / BITS_PER_ENCODED_BYTE;
const BITS_PER_BYTE: usize = 8;
if self.is_empty() {
return IonResult::incomplete("a VarInt", self.offset());
}
let first_byte: u8 = self.peek_next_byte().unwrap();
let no_more_bytes: bool = first_byte >= 0b1000_0000; let is_negative: bool = (first_byte & 0b0100_0000) == 0b0100_0000;
let sign: i64 = if is_negative { -1 } else { 1 };
let mut magnitude = (first_byte & 0b0011_1111) as i64;
if no_more_bytes {
return Ok((
VarInt::new(magnitude * sign, is_negative, 1),
self.consume(1),
));
}
let mut encoded_size_in_bytes = 1;
let mut terminated = false;
for byte in self.bytes()[1..].iter().copied() {
let lower_seven = (0b0111_1111 & byte) as i64;
magnitude <<= 7;
magnitude |= lower_seven;
encoded_size_in_bytes += 1;
if byte >= 0b1000_0000 {
terminated = true;
break;
}
}
if !terminated {
return IonResult::incomplete("a VarInt", self.offset() + encoded_size_in_bytes);
}
if encoded_size_in_bytes > MAX_ENCODED_SIZE_IN_BYTES {
return IonResult::decoding_error(format!(
"Found a {encoded_size_in_bytes}-byte VarInt. Max supported size is {MAX_ENCODED_SIZE_IN_BYTES} bytes."
));
}
Ok((
VarInt::new(magnitude * sign, is_negative, encoded_size_in_bytes),
self.consume(encoded_size_in_bytes),
))
}
#[inline(never)]
fn value_too_large<T>(label: &str, length: usize, max_length: usize) -> IonResult<T> {
IonResult::decoding_error(format!(
"found {label} that was too large; size = {length}, max size = {max_length}"
))
}
pub fn read_int(self, length: usize) -> ParseResult<'a, DecodedInt> {
if length == 0 {
return Ok((DecodedInt::new(0, false, 0), self.consume(0)));
}
let int_bytes = self
.peek_n_bytes(length)
.ok_or_else(|| IonError::incomplete("an Int encoding primitive", self.offset()))?;
let is_negative: bool = int_bytes[0] & 0b1000_0000 != 0;
let mut magnitude_le = int_bytes.to_vec();
magnitude_le[0] &= 0b0111_1111;
magnitude_le.reverse();
magnitude_le.push(0);
let value = Int::from_le_signed_bytes(&magnitude_le);
let value = if is_negative { value.neg() } else { value };
Ok((
DecodedInt::new(value, is_negative, length),
self.consume(length),
))
}
pub fn read_annotations_wrapper(
&self,
type_descriptor: TypeDescriptor,
) -> ParseResult<'a, AnnotationsWrapper> {
let input_after_type_descriptor = self.consume(1);
let (annotations_and_value_length, input_after_combined_length) =
match type_descriptor.length_code {
length_codes::NULL => (0, input_after_type_descriptor),
length_codes::VAR_UINT => {
let (var_uint, input) = input_after_type_descriptor.read_var_uint()?;
(var_uint.value(), input)
}
length => (length as usize, input_after_type_descriptor),
};
let (annotations_length, input_after_annotations_length) =
input_after_combined_length.read_var_uint()?;
if annotations_length.value() == 0 {
return IonResult::decoding_error("found an annotations wrapper with no annotations");
}
let expected_value_length = annotations_and_value_length
- annotations_length.size_in_bytes()
- annotations_length.value();
if expected_value_length == 0 {
return IonResult::decoding_error("found an annotation wrapper with no value");
}
if input_after_annotations_length.len() < annotations_length.value() {
return IonResult::incomplete(
"an annotations sequence",
input_after_annotations_length.offset(),
);
}
let annotations_header_length = input_after_annotations_length.offset() - self.offset();
let annotations_header_length = u8::try_from(annotations_header_length).map_err(|_e| {
IonError::decoding_error("found an annotations header greater than 255 bytes long")
})?;
let final_input = input_after_annotations_length.consume(annotations_length.value());
let annotations_sequence_length =
u8::try_from(annotations_length.value()).map_err(|_e| {
IonError::decoding_error(
"found an annotations sequence greater than 255 bytes long",
)
})?;
let wrapper = AnnotationsWrapper {
header_length: annotations_header_length,
sequence_length: annotations_sequence_length,
expected_value_length,
};
Ok((wrapper, final_input))
}
#[inline(never)]
pub fn read_nop_pad(self) -> ParseResult<'a, usize> {
let type_descriptor = self.peek_type_descriptor()?;
let remaining = self.consume(1);
let (length, remaining) = remaining.read_length(type_descriptor.length_code)?;
if remaining.len() < length.value() {
return IonResult::incomplete("a NOP", remaining.offset());
}
let remaining = remaining.consume(length.value());
let total_nop_pad_size = 1 + length.size_in_bytes() + length.value();
Ok((total_nop_pad_size, remaining))
}
#[inline(never)]
pub fn consume_nop_padding(self, mut type_descriptor: TypeDescriptor) -> ParseResult<'a, ()> {
let mut buffer = self;
while type_descriptor.is_nop() {
let (_, buffer_after_nop) = buffer.read_nop_pad()?;
buffer = buffer_after_nop;
if buffer.is_empty() {
break;
}
type_descriptor = buffer.peek_type_descriptor()?
}
Ok(((), buffer))
}
#[inline]
pub fn read_value_length(self, header: Header) -> ParseResult<'a, VarUInt> {
use crate::IonType::*;
let length_code = match header.ion_type {
Null | Bool => 0,
Struct if header.length_code == 1 => length_codes::VAR_UINT,
_ => header.length_code,
};
let (length, remaining) = self.read_length(length_code)?;
match header.ion_type {
Float => match header.length_code {
0 | 4 | 8 | 15 => {}
_ => return IonResult::decoding_error("found a float with an illegal length code"),
},
Timestamp if !header.is_null() && length.value() <= 1 => {
return IonResult::decoding_error("found a timestamp with length <= 1")
}
Struct if header.length_code == 1 && length.value() == 0 => {
return IonResult::decoding_error("found an empty ordered struct")
}
_ => {}
};
Ok((length, remaining))
}
pub fn read_length(self, length_code: u8) -> ParseResult<'a, VarUInt> {
let length = match length_code {
length_codes::NULL => VarUInt::new(0, 0),
length_codes::VAR_UINT => return self.read_var_uint(),
magnitude => VarUInt::new(magnitude as usize, 0),
};
Ok((length, self))
}
pub(crate) fn peek_field(self) -> IonResult<Option<LazyRawFieldExpr<'a, BinaryEncoding_1_0>>> {
let mut input = self;
if self.is_empty() {
return Ok(None);
}
let (mut field_id_var_uint, mut input_after_field_id) = input.read_var_uint()?;
if input_after_field_id.is_empty() {
return IonResult::incomplete(
"found field name but no value",
input_after_field_id.offset(),
);
}
let mut type_descriptor = input_after_field_id.peek_type_descriptor()?;
if type_descriptor.is_nop() {
(field_id_var_uint, input_after_field_id) = match input.read_struct_field_nop_pad()? {
None => {
return Ok(None);
}
Some((nop_length, field_id_var_uint, input_after_field_id)) => {
input = input.consume(nop_length);
type_descriptor = input_after_field_id.peek_type_descriptor()?;
(field_id_var_uint, input_after_field_id)
}
};
}
let field_id = field_id_var_uint.value();
let matched_field_id = input.slice(0, field_id_var_uint.size_in_bytes());
let field_name = LazyRawBinaryFieldName_1_0::new(field_id, matched_field_id);
let field_value = input_after_field_id.read_value(type_descriptor)?;
let allocator = self.context.allocator();
let value_ref = allocator.alloc_with(|| field_value);
Ok(Some(LazyRawFieldExpr::NameValue(field_name, &*value_ref)))
}
#[cold]
fn read_struct_field_nop_pad(self) -> IonResult<Option<(usize, VarUInt, BinaryBuffer<'a>)>> {
let mut input_before_field_id = self;
loop {
if input_before_field_id.is_empty() {
return Ok(None);
}
let (field_id_var_uint, input_after_field_id) =
input_before_field_id.read_var_uint()?;
if input_after_field_id.is_empty() {
return IonResult::incomplete(
"found a field name but no value",
input_after_field_id.offset(),
);
}
if input_after_field_id.peek_type_descriptor()?.is_nop() {
(_, input_before_field_id) = input_after_field_id.read_nop_pad()?;
} else {
let nop_length = input_before_field_id.offset() - self.offset();
return Ok(Some((nop_length, field_id_var_uint, input_after_field_id)));
}
}
}
pub(crate) fn peek_sequence_value(self) -> IonResult<Option<&'a LazyRawBinaryValue_1_0<'a>>> {
if self.is_empty() {
return Ok(None);
}
let mut input = self;
let mut type_descriptor = input.peek_type_descriptor()?;
if type_descriptor.is_nop() {
(_, input) = self.consume_nop_padding(type_descriptor)?;
if input.is_empty() {
return Ok(None);
}
type_descriptor = input.peek_type_descriptor()?;
}
let value = input.read_value(type_descriptor)?;
let allocator = self.context.allocator();
let value_ref = allocator.alloc_with(|| value);
Ok(Some(value_ref))
}
fn read_value(self, type_descriptor: TypeDescriptor) -> IonResult<LazyRawBinaryValue_1_0<'a>> {
if type_descriptor.is_annotation_wrapper() {
self.read_annotated_value(type_descriptor)
} else {
self.read_value_without_annotations(type_descriptor)
}
}
fn read_value_without_annotations(
self,
type_descriptor: TypeDescriptor,
) -> IonResult<LazyRawBinaryValue_1_0<'a>> {
let input = self;
let header = type_descriptor
.to_header()
.ok_or_else(|| IonError::decoding_error("found a non-value in value position"))?;
let header_offset = input.offset();
let (length, _) = input.consume(1).read_value_length(header)?;
let length_length = length.size_in_bytes() as u8;
let value_length = length.value(); let total_length = 1 + length_length as usize
+ value_length;
if total_length > input.len() {
return IonResult::incomplete(
"the stream ended unexpectedly in the middle of a value",
header_offset,
);
}
let encoded_value = EncodedBinaryValue {
encoding: BinaryValueEncoding::Tagged,
header,
annotations_header_length: 0,
annotations_sequence_length: 0,
annotations_encoding: AnnotationsEncoding::SymbolAddress,
header_offset,
length_length,
value_body_length: value_length,
total_length,
};
let lazy_value = LazyRawBinaryValue_1_0 {
encoded_value,
input: self,
};
Ok(lazy_value)
}
fn read_annotated_value(
self,
mut type_descriptor: TypeDescriptor,
) -> IonResult<LazyRawBinaryValue_1_0<'a>> {
let input = self;
let (wrapper, input_after_annotations) = input.read_annotations_wrapper(type_descriptor)?;
type_descriptor = input_after_annotations.peek_type_descriptor()?;
if type_descriptor.is_annotation_wrapper() {
return IonResult::decoding_error(
"found an annotations wrapper inside an annotations wrapper",
);
} else if type_descriptor.is_nop() {
return IonResult::decoding_error("found a NOP inside an annotations wrapper");
}
let mut lazy_value =
input_after_annotations.read_value_without_annotations(type_descriptor)?;
if wrapper.expected_value_length != lazy_value.encoded_value.total_length() {
return IonResult::decoding_error(
"value length did not match length declared by annotations wrapper",
);
}
lazy_value.encoded_value.annotations_header_length = wrapper.header_length;
lazy_value.encoded_value.annotations_sequence_length = wrapper.sequence_length as u16;
lazy_value.encoded_value.total_length +=
lazy_value.encoded_value.annotations_total_length();
lazy_value.input = input;
Ok(lazy_value)
}
pub fn context(&self) -> EncodingContextRef<'a> {
self.context
}
}
pub struct AnnotationsWrapper {
pub header_length: u8,
pub sequence_length: u8,
pub expected_value_length: usize,
}
#[cfg(test)]
mod tests {
use crate::{EncodingContext, Int, IonError, IonVersion};
use super::*;
fn input_test<A: AsRef<[u8]>>(input: A) {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let input = BinaryBuffer::new(context.get_ref(), input.as_ref());
assert_eq!(input.peek_next_byte(), Some(b'f'));
assert_eq!(input.peek_n_bytes(3), Some("foo".as_bytes()));
let input = input.consume(1);
assert_eq!(input.peek_next_byte(), Some(b'o'));
let input = input.consume(1);
assert_eq!(input.peek_next_byte(), Some(b'o'));
let input = input.consume(1);
assert_eq!(input.peek_n_bytes(2), Some(" b".as_bytes()));
assert_eq!(input.peek_n_bytes(6), Some(" bar b".as_bytes()));
}
#[test]
fn string_test() {
input_test(String::from("foo bar baz"));
}
#[test]
fn slice_test() {
input_test("foo bar baz".as_bytes());
}
#[test]
fn vec_test() {
input_test(Vec::from("foo bar baz".as_bytes()));
}
#[test]
fn read_var_uint() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b0111_1001, 0b0000_1111, 0b1000_0001]);
let var_uint = buffer.read_var_uint()?.0;
assert_eq!(3, var_uint.size_in_bytes());
assert_eq!(1_984_385, var_uint.value());
Ok(())
}
#[test]
fn read_var_uint_zero() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b1000_0000]);
let var_uint = buffer.read_var_uint()?.0;
assert_eq!(var_uint.size_in_bytes(), 1);
assert_eq!(var_uint.value(), 0);
Ok(())
}
#[test]
fn read_var_uint_two_bytes_max_value() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b0111_1111, 0b1111_1111]);
let var_uint = buffer.read_var_uint()?.0;
assert_eq!(var_uint.size_in_bytes(), 2);
assert_eq!(var_uint.value(), 16_383);
Ok(())
}
#[test]
fn read_incomplete_var_uint() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b0111_1001, 0b0000_1111]);
match buffer.read_var_uint() {
Err(IonError::Incomplete { .. }) => Ok(()),
other => panic!("expected IonError::Incomplete, but found: {other:?}"),
}
}
#[test]
fn read_var_uint_overflow_detection() {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(
context.get_ref(),
&[
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b1111_1111,
],
);
buffer
.read_var_uint()
.expect_err("This should have failed due to overflow.");
}
#[test]
fn read_var_int_zero() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b1000_0000]);
let var_int = buffer.read_var_int()?.0;
assert_eq!(var_int.size_in_bytes(), 1);
assert_eq!(var_int.value(), 0);
Ok(())
}
#[test]
fn read_negative_var_int() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b0111_1001, 0b0000_1111, 0b1000_0001]);
let var_int = buffer.read_var_int()?.0;
assert_eq!(var_int.size_in_bytes(), 3);
assert_eq!(var_int.value(), -935_809);
Ok(())
}
#[test]
fn read_positive_var_int() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b0011_1001, 0b0000_1111, 0b1000_0001]);
let var_int = buffer.read_var_int()?.0;
assert_eq!(var_int.size_in_bytes(), 3);
assert_eq!(var_int.value(), 935_809);
Ok(())
}
#[test]
fn read_var_int_two_byte_min() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b0111_1111, 0b1111_1111]);
let var_int = buffer.read_var_int()?.0;
assert_eq!(var_int.size_in_bytes(), 2);
assert_eq!(var_int.value(), -8_191);
Ok(())
}
#[test]
fn read_var_int_two_byte_max() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b0011_1111, 0b1111_1111]);
let var_int = buffer.read_var_int()?.0;
assert_eq!(var_int.size_in_bytes(), 2);
assert_eq!(var_int.value(), 8_191);
Ok(())
}
#[test]
fn read_var_int_overflow_detection() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(
context.get_ref(),
&[
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b0111_1111,
0b1111_1111,
],
);
buffer
.read_var_int()
.expect_err("This should have failed due to overflow.");
Ok(())
}
#[test]
fn read_int_negative_zero() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b1000_0000]); let int = buffer.read_int(buffer.len())?.0;
assert_eq!(int.size_in_bytes(), 1);
assert_eq!(int.value(), &Int::from(0));
assert!(int.is_negative_zero());
Ok(())
}
#[test]
fn read_int_positive_zero() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b0000_0000]); let int = buffer.read_int(buffer.len())?.0;
assert_eq!(int.size_in_bytes(), 1);
assert_eq!(int.value(), &Int::from(0));
assert!(!int.is_negative_zero());
Ok(())
}
#[test]
fn read_int_length_zero() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[]); let int = buffer.read_int(buffer.len())?.0;
assert_eq!(int.size_in_bytes(), 0);
assert_eq!(int.value(), &Int::from(0));
assert!(!int.is_negative_zero());
Ok(())
}
#[test]
fn read_two_byte_negative_int() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b1111_1111, 0b1111_1111]);
let int = buffer.read_int(buffer.len())?.0;
assert_eq!(int.size_in_bytes(), 2);
assert_eq!(int.value(), &Int::from(-32_767i64));
Ok(())
}
#[test]
fn read_two_byte_positive_int() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b0111_1111, 0b1111_1111]);
let int = buffer.read_int(buffer.len())?.0;
assert_eq!(int.size_in_bytes(), 2);
assert_eq!(int.value(), &Int::from(32_767i64));
Ok(())
}
#[test]
fn read_three_byte_negative_int() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b1011_1100, 0b1000_0111, 0b1000_0001]);
let int = buffer.read_int(buffer.len())?.0;
assert_eq!(int.size_in_bytes(), 3);
assert_eq!(int.value(), &Int::from(-3_966_849i64));
Ok(())
}
#[test]
fn read_three_byte_positive_int() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let buffer = BinaryBuffer::new(context.get_ref(), &[0b0011_1100, 0b1000_0111, 0b1000_0001]);
let int = buffer.read_int(buffer.len())?.0;
assert_eq!(int.size_in_bytes(), 3);
assert_eq!(int.value(), &Int::from(3_966_849i64));
Ok(())
}
#[test]
fn read_int_overflow() -> IonResult<()> {
let context = EncodingContext::for_ion_version(IonVersion::v1_0);
let data = vec![1; std::mem::size_of::<i128>() + 1];
let buffer = BinaryBuffer::new(context.get_ref(), &data);
let (decoded, _) = buffer.read_int(buffer.len())?;
assert!(
decoded.value().as_i128().is_none(),
"Value should exceed i128 range"
);
Ok(())
}
}