use std::fmt;
use std::io::{Read, Seek, Write};
use crate::error::RiegeliError;
use crate::record_reader::RecordReader;
use crate::record_writer::RecordWriter;
use super::field_iter::{FieldValue, ProtoFieldIter, copy_fields};
use super::handler::HandleField;
use super::wire::is_proto_message;
use super::writer::SerializedMessageWriter;
#[derive(Debug)]
pub struct StreamError {
pub record_index: usize,
pub source: RiegeliError,
}
impl fmt::Display for StreamError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"error at record index {}: {}",
self.record_index, self.source
)
}
}
impl std::error::Error for StreamError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.source)
}
}
pub fn for_each_proto_record<R, H, F>(
reader: &mut RecordReader<R>,
handlers: &mut H,
mut fallback: Option<&mut F>,
) -> Result<(), StreamError>
where
R: Read + Seek,
H: HandleField,
F: FnMut(usize, &[u8]),
{
let mut record_index: usize = 0;
loop {
let record = reader.read_record().map_err(|e| StreamError {
record_index,
source: e,
})?;
let record = match record {
Some(r) => r,
None => break, };
if is_proto_message(&record) {
super::handler::read_message(&record, handlers).map_err(|e| StreamError {
record_index,
source: e,
})?;
} else if let Some(fb) = fallback.as_deref_mut() {
fb(record_index, &record);
}
record_index += 1;
}
Ok(())
}
pub fn extract_varint_column<R: Read + Seek>(
reader: &mut RecordReader<R>,
field_number: u32,
) -> Result<Vec<u64>, StreamError> {
let mut values = Vec::new();
let mut record_index: usize = 0;
loop {
let record = reader.read_record().map_err(|e| StreamError {
record_index,
source: e,
})?;
let record = match record {
Some(r) => r,
None => break,
};
if is_proto_message(&record) {
let iter = ProtoFieldIter::new(&record);
for result in iter {
let field = result.map_err(|e| StreamError {
record_index,
source: e,
})?;
if field.field_number == field_number
&& let FieldValue::Varint(v) = field.value
{
values.push(v);
}
}
}
record_index += 1;
}
Ok(values)
}
pub fn filter_fields_to_writer<R, W>(
reader: &mut RecordReader<R>,
writer: &mut RecordWriter<W>,
field_numbers: &[u32],
) -> Result<(), StreamError>
where
R: Read + Seek,
W: Write,
{
let mut record_index: usize = 0;
loop {
let record = reader.read_record().map_err(|e| StreamError {
record_index,
source: e,
})?;
let record = match record {
Some(r) => r,
None => break,
};
if is_proto_message(&record) {
let mut msg_writer = SerializedMessageWriter::new();
copy_fields(&record, field_numbers, &mut msg_writer).map_err(|e| StreamError {
record_index,
source: e,
})?;
let filtered = msg_writer.finish().map_err(|e| StreamError {
record_index,
source: e,
})?;
writer.write_record(&filtered).map_err(|e| StreamError {
record_index,
source: e,
})?;
} else {
writer.write_record(&record).map_err(|e| StreamError {
record_index,
source: e,
})?;
}
record_index += 1;
}
Ok(())
}