use std::path::Path;
use crate::encoding::Encoding;
use crate::error::MarcError;
use crate::format::MarcFormat;
use crate::raw::{BinaryReader, RawRecordView};
use crate::record::Record;
use crate::xml::XmlReader;
use crate::{detect_file_format, FileFormat};
pub struct MarcReader {
data: Vec<u8>,
source_format: FileFormat,
encoding_override: Option<Encoding>,
}
impl MarcReader {
pub fn from_bytes(data: Vec<u8>) -> Result<Self, MarcError> {
let fmt = detect_file_format(&data);
match fmt {
FileFormat::Binary => Ok(Self {
data,
source_format: FileFormat::Binary,
encoding_override: None,
}),
FileFormat::Xml => Ok(Self {
data: XmlReader::parse(&data)?,
source_format: FileFormat::Xml,
encoding_override: None,
}),
}
}
pub fn from_file(path: &Path) -> Result<Self, MarcError> {
let data = std::fs::read(path)?;
Self::from_bytes(data)
}
pub fn from_binary(data: Vec<u8>) -> Self {
Self {
data,
source_format: FileFormat::Binary,
encoding_override: None,
}
}
pub fn from_xml(data: &[u8]) -> Result<Self, MarcError> {
Ok(Self {
data: XmlReader::parse(data)?,
source_format: FileFormat::Xml,
encoding_override: None,
})
}
pub fn with_encoding(mut self, encoding: Encoding) -> Self {
self.encoding_override = Some(encoding);
self
}
pub fn clear_encoding_override(&mut self) {
self.encoding_override = None;
}
pub fn source_format(&self) -> FileFormat {
self.source_format
}
pub fn encoding_override(&self) -> Option<Encoding> {
self.encoding_override
}
pub fn iter(&self) -> BinaryReader<'_> {
BinaryReader::with_encoding(&self.data, self.encoding_override)
}
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
pub fn into_records(self) -> Result<Vec<Record>, MarcError> {
let mut records = Vec::new();
for view in BinaryReader::with_encoding(&self.data, self.encoding_override) {
let view = view?;
let raw = view.as_raw();
let format = MarcFormat::detect(raw, self.encoding_override)?;
records.push(format.to_record(raw)?);
}
Ok(records)
}
}
impl<'a> IntoIterator for &'a MarcReader {
type Item = Result<RawRecordView<'a>, MarcError>;
type IntoIter = BinaryReader<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}