aster_forge_cloud_files_linux/
inode.rs1use std::collections::HashMap;
4
5use aster_forge_cloud_files_core::{CloudItemKey, CloudScope};
6
7use crate::{LinuxCloudFilesError, Result};
8
9pub const LINUX_ROOT_INODE: LinuxInode = LinuxInode(1);
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct LinuxInode(u64);
15
16impl LinuxInode {
17 pub const fn new(value: u64) -> Result<Self> {
23 if value == 0 {
24 return Err(LinuxCloudFilesError::ZeroInode);
25 }
26 Ok(Self(value))
27 }
28
29 #[must_use]
31 pub const fn get(self) -> u64 {
32 self.0
33 }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
38pub struct LinuxInodeGeneration(u64);
39
40impl LinuxInodeGeneration {
41 pub const fn new(value: u64) -> Result<Self> {
47 if value == 0 {
48 return Err(LinuxCloudFilesError::ZeroGeneration);
49 }
50 Ok(Self(value))
51 }
52
53 #[must_use]
55 pub const fn get(self) -> u64 {
56 self.0
57 }
58}
59
60#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct LinuxInodeRecord {
63 key: CloudItemKey,
64 inode: LinuxInode,
65 generation: LinuxInodeGeneration,
66}
67
68impl LinuxInodeRecord {
69 #[must_use]
71 pub const fn new(
72 key: CloudItemKey,
73 inode: LinuxInode,
74 generation: LinuxInodeGeneration,
75 ) -> Self {
76 Self {
77 key,
78 inode,
79 generation,
80 }
81 }
82
83 #[must_use]
85 pub const fn key(&self) -> &CloudItemKey {
86 &self.key
87 }
88
89 #[must_use]
91 pub const fn inode(&self) -> LinuxInode {
92 self.inode
93 }
94
95 #[must_use]
97 pub const fn generation(&self) -> LinuxInodeGeneration {
98 self.generation
99 }
100
101 #[must_use]
103 pub fn into_parts(self) -> (CloudItemKey, LinuxInode, LinuxInodeGeneration) {
104 (self.key, self.inode, self.generation)
105 }
106}
107
108#[derive(Debug, Clone)]
113pub struct LinuxInodeTable {
114 scope: CloudScope,
115 root: LinuxInodeRecord,
116 by_key: HashMap<CloudItemKey, LinuxInodeRecord>,
117 by_inode: HashMap<LinuxInode, LinuxInodeRecord>,
118}
119
120impl LinuxInodeTable {
121 pub fn new(
127 root: LinuxInodeRecord,
128 records: impl IntoIterator<Item = LinuxInodeRecord>,
129 ) -> Result<Self> {
130 if root.inode() != LINUX_ROOT_INODE {
131 return Err(LinuxCloudFilesError::RootInodeMismatch);
132 }
133 let scope = root.key().scope().clone();
134 let mut by_key = HashMap::new();
135 let mut by_inode = HashMap::new();
136 for record in records {
137 if record.key().scope() != &scope {
138 return Err(LinuxCloudFilesError::ScopeMismatch);
139 }
140 if record.inode() == LINUX_ROOT_INODE {
141 return Err(LinuxCloudFilesError::RootInodeMismatch);
142 }
143 if by_key
144 .insert(record.key().clone(), record.clone())
145 .is_some()
146 {
147 return Err(LinuxCloudFilesError::DuplicateItem);
148 }
149 if by_inode.insert(record.inode(), record.clone()).is_some() {
150 return Err(LinuxCloudFilesError::DuplicateInode {
151 inode: record.inode().get(),
152 });
153 }
154 }
155 Ok(Self {
156 scope,
157 root,
158 by_key,
159 by_inode,
160 })
161 }
162
163 #[must_use]
165 pub const fn scope(&self) -> &CloudScope {
166 &self.scope
167 }
168
169 #[must_use]
171 pub const fn root(&self) -> &LinuxInodeRecord {
172 &self.root
173 }
174
175 #[must_use]
177 pub fn by_key(&self, key: &CloudItemKey) -> Option<&LinuxInodeRecord> {
178 if key == self.root.key() {
179 Some(&self.root)
180 } else {
181 self.by_key.get(key)
182 }
183 }
184
185 #[must_use]
187 pub fn by_inode(&self, inode: LinuxInode) -> Option<&LinuxInodeRecord> {
188 if inode == LINUX_ROOT_INODE {
189 Some(&self.root)
190 } else {
191 self.by_inode.get(&inode)
192 }
193 }
194
195 pub fn records(&self) -> impl Iterator<Item = &LinuxInodeRecord> {
197 self.by_inode.values()
198 }
199}