arrow_json/reader/
list_array.rsuse crate::reader::tape::{Tape, TapeElement};
use crate::reader::{make_decoder, ArrayDecoder};
use arrow_array::builder::{BooleanBufferBuilder, BufferBuilder};
use arrow_array::OffsetSizeTrait;
use arrow_buffer::buffer::NullBuffer;
use arrow_data::{ArrayData, ArrayDataBuilder};
use arrow_schema::{ArrowError, DataType};
use std::marker::PhantomData;
pub struct ListArrayDecoder<O> {
data_type: DataType,
decoder: Box<dyn ArrayDecoder>,
phantom: PhantomData<O>,
is_nullable: bool,
}
impl<O: OffsetSizeTrait> ListArrayDecoder<O> {
pub fn new(
data_type: DataType,
coerce_primitive: bool,
strict_mode: bool,
is_nullable: bool,
) -> Result<Self, ArrowError> {
let field = match &data_type {
DataType::List(f) if !O::IS_LARGE => f,
DataType::LargeList(f) if O::IS_LARGE => f,
_ => unreachable!(),
};
let decoder = make_decoder(
field.data_type().clone(),
coerce_primitive,
strict_mode,
field.is_nullable(),
)?;
Ok(Self {
data_type,
decoder,
phantom: Default::default(),
is_nullable,
})
}
}
impl<O: OffsetSizeTrait> ArrayDecoder for ListArrayDecoder<O> {
fn decode(&mut self, tape: &Tape<'_>, pos: &[u32]) -> Result<ArrayData, ArrowError> {
let mut child_pos = Vec::with_capacity(pos.len());
let mut offsets = BufferBuilder::<O>::new(pos.len() + 1);
offsets.append(O::from_usize(0).unwrap());
let mut nulls = self
.is_nullable
.then(|| BooleanBufferBuilder::new(pos.len()));
for p in pos {
let end_idx = match (tape.get(*p), nulls.as_mut()) {
(TapeElement::StartList(end_idx), None) => end_idx,
(TapeElement::StartList(end_idx), Some(nulls)) => {
nulls.append(true);
end_idx
}
(TapeElement::Null, Some(nulls)) => {
nulls.append(false);
*p + 1
}
_ => return Err(tape.error(*p, "[")),
};
let mut cur_idx = *p + 1;
while cur_idx < end_idx {
child_pos.push(cur_idx);
cur_idx = tape.next(cur_idx, "list value")?;
}
let offset = O::from_usize(child_pos.len()).ok_or_else(|| {
ArrowError::JsonError(format!("offset overflow decoding {}", self.data_type))
})?;
offsets.append(offset)
}
let child_data = self.decoder.decode(tape, &child_pos)?;
let nulls = nulls.as_mut().map(|x| NullBuffer::new(x.finish()));
let data = ArrayDataBuilder::new(self.data_type.clone())
.len(pos.len())
.nulls(nulls)
.add_buffer(offsets.finish())
.child_data(vec![child_data]);
Ok(unsafe { data.build_unchecked() })
}
}