lotus_lib/toc/
node.rs

1use std::fmt;
2use std::path::PathBuf;
3
4use arctree::Node as ArcNode;
5
6/// The kind of a node.
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub enum NodeKind {
9    /// A directory node.
10    Directory,
11
12    /// A file node.
13    File,
14}
15
16/// A node in a tree.
17///
18/// Nodes can be either directories or files.
19/// The cost of cloning a node is low, as it uses [`Arc`] internally.
20#[derive(Clone, PartialEq)]
21pub struct Node {
22    node: ArcNode<NodeData>,
23}
24
25impl fmt::Debug for Node {
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        let node = self.node.read();
28        f.debug_struct("Node")
29            .field("name", &node.name)
30            .field("kind", &node.kind)
31            .field("cache_offset", &node.cache_offset)
32            .field("timestamp", &node.timestamp)
33            .field("comp_len", &node.comp_len)
34            .field("len", &node.len)
35            .finish()
36    }
37}
38
39/// Trait for file nodes.
40pub trait FileNode {
41    /// Returns the cache offset of the file.
42    fn cache_offset(&self) -> i64;
43
44    /// Returns the timestamp of the file.
45    fn timestamp(&self) -> i64;
46
47    /// Returns the compressed length of the file.
48    fn comp_len(&self) -> i32;
49
50    /// Returns the decompressed length of the file.
51    fn len(&self) -> i32;
52}
53
54/// Trait for directory nodes.
55pub trait DirectoryNode {
56    /// Returns the children of the directory.
57    fn children(&self) -> Vec<Node>;
58
59    /// Returns the child with the given name.
60    fn get_child(&self, name: &str) -> Option<Node>;
61}
62
63impl Node {
64    fn new(
65        name: &str,
66        kind: NodeKind,
67        cache_offset: Option<i64>,
68        timestamp: Option<i64>,
69        comp_len: Option<i32>,
70        len: Option<i32>,
71    ) -> Self {
72        Self {
73            node: ArcNode::new(NodeData::new(
74                name,
75                kind,
76                cache_offset,
77                timestamp,
78                comp_len,
79                len,
80            )),
81        }
82    }
83
84    pub(super) fn root() -> Self {
85        Self::directory("")
86    }
87
88    pub(super) fn file(
89        name: &str,
90        cache_offset: i64,
91        timestamp: i64,
92        comp_len: i32,
93        len: i32,
94    ) -> Self {
95        Self::new(
96            name,
97            NodeKind::File,
98            Some(cache_offset),
99            Some(timestamp),
100            Some(comp_len),
101            Some(len),
102        )
103    }
104
105    pub(super) fn directory(name: &str) -> Self {
106        Self::new(name, NodeKind::Directory, None, None, None, None)
107    }
108
109    pub(super) fn append(&mut self, child: Node) {
110        self.node.append(child.node.clone());
111    }
112
113    /// Returns the name of the node.
114    pub fn name(&self) -> String {
115        self.node.read().name().to_string()
116    }
117
118    /// Returns the path of the node.
119    pub fn path(&self) -> PathBuf {
120        let mut ancestors = Vec::new();
121        let mut ancestor = self.node.parent();
122        while let Some(current_ancestor) = ancestor {
123            ancestors.push(current_ancestor.clone());
124            ancestor = current_ancestor.parent();
125        }
126
127        let mut path = PathBuf::from("/");
128        for ancestor in ancestors.iter().rev() {
129            path.push(ancestor.read().name());
130        }
131
132        path.push(self.name());
133
134        path
135    }
136
137    /// Returns the kind of the node.
138    pub fn kind(&self) -> NodeKind {
139        self.node.read().kind()
140    }
141
142    /// Returns the parent of the node.
143    pub fn parent(&self) -> Option<Node> {
144        self.node.parent().map(|parent| Node { node: parent })
145    }
146}
147
148impl FileNode for Node {
149    fn cache_offset(&self) -> i64 {
150        self.node.read().cache_offset().unwrap().clone()
151    }
152
153    fn timestamp(&self) -> i64 {
154        self.node.read().timestamp().unwrap().clone()
155    }
156
157    fn comp_len(&self) -> i32 {
158        self.node.read().comp_len().unwrap().clone()
159    }
160
161    fn len(&self) -> i32 {
162        self.node.read().len().unwrap().clone()
163    }
164}
165
166impl DirectoryNode for Node {
167    fn children(&self) -> Vec<Node> {
168        self.node
169            .children()
170            .map(|child| Node {
171                node: child.clone(),
172            })
173            .collect()
174    }
175
176    fn get_child(&self, name: &str) -> Option<Node> {
177        self.node
178            .children()
179            .find(|child| *child.read().name() == *name)
180            .map(|child| Node {
181                node: child.clone(),
182            })
183    }
184}
185
186#[derive(Debug)]
187struct NodeData {
188    name: String,
189    kind: NodeKind,
190    cache_offset: Option<i64>,
191    timestamp: Option<i64>,
192    comp_len: Option<i32>,
193    len: Option<i32>,
194}
195
196impl NodeData {
197    fn new(
198        name: &str,
199        kind: NodeKind,
200        cache_offset: Option<i64>,
201        timestamp: Option<i64>,
202        comp_len: Option<i32>,
203        len: Option<i32>,
204    ) -> Self {
205        Self {
206            name: String::from(name),
207            kind,
208            cache_offset,
209            timestamp,
210            comp_len,
211            len,
212        }
213    }
214
215    fn name(&self) -> &String {
216        &self.name
217    }
218
219    fn kind(&self) -> NodeKind {
220        self.kind
221    }
222
223    fn cache_offset(&self) -> Option<&i64> {
224        self.cache_offset.as_ref()
225    }
226
227    fn timestamp(&self) -> Option<&i64> {
228        self.timestamp.as_ref()
229    }
230
231    fn comp_len(&self) -> Option<&i32> {
232        self.comp_len.as_ref()
233    }
234
235    fn len(&self) -> Option<&i32> {
236        self.len.as_ref()
237    }
238}