use crate::NetError;
use crate::line::{DEFAULT_MAX_LINE_BYTES, LineDecoder};
#[derive(Debug)]
pub struct NdjsonDecoder {
lines: LineDecoder,
max_line_bytes: Option<usize>,
}
impl Default for NdjsonDecoder {
fn default() -> Self {
Self::new()
}
}
impl NdjsonDecoder {
pub fn new() -> Self {
Self::with_max_line_bytes(DEFAULT_MAX_LINE_BYTES)
}
pub fn unbounded() -> Self {
Self {
lines: LineDecoder::unbounded(),
max_line_bytes: None,
}
}
pub fn with_max_line_bytes(max_line_bytes: usize) -> Self {
Self {
lines: LineDecoder::with_max_line_bytes(max_line_bytes),
max_line_bytes: Some(max_line_bytes),
}
}
pub fn push(&mut self, bytes: &[u8]) -> Result<Vec<String>, NetError> {
let mut records = Vec::new();
for line in self.lines.push_checked(bytes)? {
self.check_limit(line.len())?;
if line.is_empty() {
continue;
}
records.push(String::from_utf8_lossy(&line).into_owned());
}
Ok(records)
}
pub fn flush(&mut self) -> Option<String> {
self.flush_checked()
.expect("ndjson line cap exceeded; use push to handle oversized input")
}
pub fn flush_checked(&mut self) -> Result<Option<String>, NetError> {
let Some(line) = self.lines.flush_checked()? else {
return Ok(None);
};
if line.is_empty() {
return Ok(None);
}
self.check_limit(line.len())?;
Ok(Some(String::from_utf8_lossy(&line).into_owned()))
}
fn check_limit(&self, len: usize) -> Result<(), NetError> {
if let Some(limit) = self.max_line_bytes
&& len > limit
{
return Err(NetError::LineTooLong { max: limit });
}
Ok(())
}
}