use std::collections::HashMap;
use std::fs;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use parking_lot::Mutex;
use crate::error::Result;
use crate::format::superblock::Superblock;
use crate::hl::dataset::Dataset;
use crate::hl::file::FileInner;
use crate::hl::group::Group;
use crate::io::reader::HdfReader;
#[path = "mutable_file/attr_mutation.rs"]
mod attr_mutation;
#[path = "mutable_file/chunk_btree_v1.rs"]
mod chunk_btree_v1;
#[path = "mutable_file/chunk_btree_v2.rs"]
mod chunk_btree_v2;
#[path = "mutable_file/chunk_extensible_array.rs"]
mod chunk_extensible_array;
#[path = "mutable_file/chunk_fixed_array.rs"]
mod chunk_fixed_array;
#[path = "mutable_file/resize.rs"]
mod resize;
#[path = "mutable_file/support.rs"]
mod support;
#[path = "mutable_file/write_chunk.rs"]
mod write_chunk;
pub struct MutableFile {
inner: Arc<Mutex<FileInner<BufReader<fs::File>>>>,
write_handle: fs::File,
superblock: Superblock,
path: PathBuf,
}
impl MutableFile {
pub fn open_rw<P: AsRef<Path>>(path: P) -> Result<Self> {
let path = path.as_ref().to_path_buf();
let read_file = fs::File::open(&path)?;
let mut reader = HdfReader::new(BufReader::new(read_file));
let superblock = Superblock::read(&mut reader)?;
let inner = Arc::new(Mutex::new(FileInner {
reader,
superblock: superblock.clone(),
path: Some(path.clone()),
access_plist: crate::hl::plist::file_access::FileAccess::default(),
dset_no_attrs_hint: false,
open_objects: HashMap::new(),
next_object_id: 1,
}));
let write_handle = fs::OpenOptions::new().write(true).open(&path)?;
Ok(Self {
inner,
write_handle,
superblock,
path,
})
}
pub fn root_group(&self) -> Result<Group> {
Group::open(self.inner.clone(), "/", self.superblock.root_addr)
}
pub fn member_names(&self) -> Result<Vec<String>> {
self.root_group()?.member_names()
}
pub fn dataset(&self, path: &str) -> Result<Dataset> {
let path_str = path.trim_start_matches('/');
if let Some(last_slash) = path_str.rfind('/') {
let group_path = &path_str[..last_slash];
let ds_name = &path_str[last_slash + 1..];
let root = self.root_group()?;
let mut current = root;
for part in group_path.split('/').filter(|s| !s.is_empty()) {
current = current.open_group(part)?;
}
current.open_dataset(ds_name)
} else {
self.root_group()?.open_dataset(path_str)
}
}
pub fn group(&self, path: &str) -> Result<Group> {
let path_str = path.trim_matches('/');
if path_str.is_empty() {
return self.root_group();
}
let mut current = self.root_group()?;
for part in path_str.split('/').filter(|s| !s.is_empty()) {
current = current.open_group(part)?;
}
Ok(current)
}
}