use std::io;
use simd_json::value::tape::Node;
use crate::models::decoders::json::value::JsonValueRef;
use crate::models::decoders::json::simd::TapeOps;
use crate::models::interfaces::json::ValueSource;
pub struct JsonFrame<'f> {
pub(crate) nodes: Vec<Node<'f>>,
pub(crate) sources: &'f [ValueSource],
pub(crate) wall_clock_scale: &'f [i64],
pub(crate) max_string_bytes: usize,
pub(crate) next_record: usize,
pub(crate) records_remaining: usize,
pub(crate) now: i64,
}
impl<'f> JsonFrame<'f> {
pub fn records_remaining(&self) -> usize {
self.records_remaining
}
pub fn next_record(&mut self) -> Option<JsonRecord<'_, 'f>> {
if self.records_remaining == 0 {
return None;
}
let record = self.next_record;
self.records_remaining -= 1;
self.next_record = record + self.nodes.span_at(record);
Some(JsonRecord { frame: self, record })
}
}
pub struct JsonRecord<'a, 'f> {
frame: &'a JsonFrame<'f>,
record: usize,
}
impl<'a, 'f> JsonRecord<'a, 'f> {
pub fn value(&self, col: usize) -> io::Result<JsonValueRef<'f>> {
let frame = self.frame;
let nodes = frame.nodes.as_slice();
let value_idx = match &frame.sources[col] {
ValueSource::WallClock => {
return Ok(JsonValueRef::I64(frame.now / frame.wall_clock_scale[col]));
}
ValueSource::RecordKey(key) => {
nodes.object_value_index(self.record, key).ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, format!("missing key '{key}'"))
})?
}
ValueSource::JsonPath(path) => path.resolve(nodes, self.record).ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, format!("path {path:?} not found"))
})?,
ValueSource::FramePath(path) => path.resolve(nodes, 0).ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("frame path {path:?} not found"),
)
})?,
};
let value = nodes.value_at(value_idx).ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
"expected scalar value, found nested object/array",
)
})?;
if let JsonValueRef::Str(s) = &value
&& s.len() > frame.max_string_bytes
{
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"resource limit exceeded: string value of {} bytes (cap {})",
s.len(),
frame.max_string_bytes,
),
));
}
Ok(value)
}
}