hdf5_pure_rust/hl/
mutable_file.rs1use std::collections::HashMap;
2use std::fs;
3use std::io::BufReader;
4use std::path::{Path, PathBuf};
5use std::sync::Arc;
6
7use parking_lot::Mutex;
8
9use crate::error::Result;
10use crate::format::superblock::Superblock;
11use crate::hl::dataset::Dataset;
12use crate::hl::file::{FileInner, FileIntent};
13use crate::hl::group::Group;
14use crate::io::reader::HdfReader;
15
16#[path = "mutable_file/attr_mutation.rs"]
17mod attr_mutation;
18#[path = "mutable_file/chunk_btree_v1.rs"]
19mod chunk_btree_v1;
20#[path = "mutable_file/chunk_btree_v2.rs"]
21mod chunk_btree_v2;
22#[path = "mutable_file/chunk_extensible_array.rs"]
23mod chunk_extensible_array;
24#[path = "mutable_file/chunk_fixed_array.rs"]
25mod chunk_fixed_array;
26#[path = "mutable_file/group_mutation.rs"]
27mod group_mutation;
28#[path = "mutable_file/resize.rs"]
29mod resize;
30#[path = "mutable_file/support.rs"]
31mod support;
32#[path = "mutable_file/write_chunk.rs"]
33mod write_chunk;
34
35pub struct MutableFile {
39 inner: Arc<Mutex<FileInner<BufReader<fs::File>>>>,
41 write_handle: fs::File,
43 superblock: Superblock,
44 path: PathBuf,
45}
46
47impl MutableFile {
48 pub fn open_rw<P: AsRef<Path>>(path: P) -> Result<Self> {
50 let path = path.as_ref().to_path_buf();
51
52 let read_file = fs::File::open(&path)?;
54 let mut reader = HdfReader::new(BufReader::new(read_file));
55 let superblock = Superblock::read(&mut reader)?;
56
57 let inner = Arc::new(Mutex::new(FileInner {
58 reader,
59 superblock: superblock.clone(),
60 path: Some(path.clone()),
61 intent: FileIntent::ReadWrite,
62 access_plist: crate::hl::plist::file_access::FileAccess::default(),
63 dset_no_attrs_hint: false,
64 open_objects: HashMap::new(),
65 next_object_id: 1,
66 }));
67
68 let write_handle = fs::OpenOptions::new().write(true).open(&path)?;
70
71 Ok(Self {
72 inner,
73 write_handle,
74 superblock,
75 path,
76 })
77 }
78
79 pub fn root_group(&self) -> Result<Group> {
81 Group::open(self.inner.clone(), "/", self.superblock.root_addr)
82 }
83
84 pub fn visit_member_names<F>(&self, visitor: F) -> Result<()>
86 where
87 F: FnMut(&str) -> Result<()>,
88 {
89 self.root_group()?.visit_member_names(visitor)
90 }
91
92 pub fn dataset(&self, path: &str) -> Result<Dataset> {
94 let path_str = path.trim_start_matches('/');
95 if let Some(last_slash) = path_str.rfind('/') {
96 let group_path = &path_str[..last_slash];
97 let ds_name = &path_str[last_slash + 1..];
98 let root = self.root_group()?;
99 let mut current = root;
100 for part in group_path.split('/').filter(|s| !s.is_empty()) {
101 current = current.open_group(part)?;
102 }
103 current.open_dataset(ds_name)
104 } else {
105 self.root_group()?.open_dataset(path_str)
106 }
107 }
108
109 pub fn group(&self, path: &str) -> Result<Group> {
111 let path_str = path.trim_matches('/');
112 if path_str.is_empty() {
113 return self.root_group();
114 }
115 let mut current = self.root_group()?;
116 for part in path_str.split('/').filter(|s| !s.is_empty()) {
117 current = current.open_group(part)?;
118 }
119 Ok(current)
120 }
121}