use std::io::Read;
use brodo::cache::CacheFile;
use brodo::field::AnyField;
use brodo::kind::FileKind;
use brodo::meta::GridMeta;
use brodo::topology::Topology;
use brodo::vdb::VdbFile;
use crate::args::Input;
use crate::error::MestoloError;
pub const VDB_UNIT: &str = "unstated";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Kind {
Cache,
Archive,
Vdb,
}
impl Kind {
pub fn name(self) -> &'static str {
match self {
Kind::Cache => "cache file",
Kind::Archive => "archive",
Kind::Vdb => "OpenVDB file",
}
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Grid {
pub meta: GridMeta,
pub topology: Topology,
pub field: AnyField,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Loaded {
pub kind: Kind,
pub grids: Vec<Grid>,
pub skipped: Vec<String>,
pub bytes: Vec<(String, usize)>,
}
impl Loaded {
pub fn grid(&self, name: Option<&str>) -> Result<&Grid, MestoloError> {
match name {
Some(n) => self
.grids
.iter()
.find(|g| g.meta.name == n)
.ok_or_else(|| MestoloError::NoGrid(n.to_owned())),
None => match self.grids.as_slice() {
[g] => Ok(g),
all => Err(MestoloError::WhichGrid(all.len())),
},
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Opened {
Cache {
kind: Kind,
file: CacheFile,
},
Vdb(VdbFile),
}
pub fn open(input: &Input) -> Result<Opened, MestoloError> {
let path = input.path.as_path();
let mut head = Vec::new();
std::fs::File::open(path)?.take(FileKind::HEAD as u64).read_to_end(&mut head)?;
match FileKind::of(&head) {
Some(FileKind::Cache) => {
Ok(Opened::Cache { kind: Kind::Cache, file: brodo::cache::read(path, input.limit)? })
}
Some(FileKind::Archive) => Ok(Opened::Cache {
kind: Kind::Archive,
file: brodo::archive::read(path, input.limit)?,
}),
Some(FileKind::Vdb) => Ok(Opened::Vdb(brodo::vdb::read(path, VDB_UNIT, input.limit)?)),
Some(FileKind::Grid) => Err(MestoloError::BareGrid(path.to_path_buf())),
_ => Err(MestoloError::UnknownKind(path.to_path_buf())),
}
}
pub fn load(input: &Input) -> Result<Loaded, MestoloError> {
match open(input)? {
Opened::Cache { kind, file } => from_cache(file, kind, input.limit),
Opened::Vdb(file) => Ok(from_vdb(file)),
}
}
fn from_cache(file: CacheFile, kind: Kind, limit: u64) -> Result<Loaded, MestoloError> {
let mut grids = Vec::new();
let mut left = limit;
for g in file.grids() {
let need = g.thaw_size()?;
left = left.checked_sub(need).ok_or(MestoloError::TooMuchToThaw {
counted: (limit - left).saturating_add(need),
limit,
})?;
let (topology, field) = g.thaw(need)?;
grids.push(Grid { meta: g.meta().clone(), topology, field });
}
let bytes = file.bytes_entries().iter().map(|b| (b.name.to_owned(), b.bytes.len())).collect();
Ok(Loaded { kind, grids, skipped: Vec::new(), bytes })
}
fn from_vdb(file: VdbFile) -> Loaded {
let grids = file
.grids
.into_iter()
.map(|g| Grid { meta: g.meta, topology: g.topology, field: g.field })
.collect();
Loaded { kind: Kind::Vdb, grids, skipped: file.skipped, bytes: Vec::new() }
}