heddle_object_model/object/
tree_source.rs1use std::{
5 fs::File,
6 io::{Read, Seek, SeekFrom},
7};
8
9use bytes::Bytes;
10
11use super::tree_stream::TreeStreamError;
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum TreeBodyIntegrity {
21 VerifiedPlacement,
23 SequentialVerify,
25}
26
27pub trait TreeByteSource {
29 fn read_exact_at(&mut self, offset: u64, buf: &mut [u8]) -> Result<(), TreeStreamError>;
30 fn len(&self) -> u64;
31 fn integrity(&self) -> TreeBodyIntegrity;
32 fn bytes_read(&self) -> u64;
33
34 fn is_empty(&self) -> bool {
35 self.len() == 0
36 }
37}
38
39#[derive(Debug)]
41pub struct BytesTreeSource {
42 bytes: Bytes,
43 integrity: TreeBodyIntegrity,
44 bytes_read: u64,
45}
46
47impl BytesTreeSource {
48 pub fn verified_placement(bytes: impl Into<Bytes>) -> Self {
49 Self {
50 bytes: bytes.into(),
51 integrity: TreeBodyIntegrity::VerifiedPlacement,
52 bytes_read: 0,
53 }
54 }
55
56 pub fn sequential_verify(bytes: impl Into<Bytes>) -> Self {
57 Self {
58 bytes: bytes.into(),
59 integrity: TreeBodyIntegrity::SequentialVerify,
60 bytes_read: 0,
61 }
62 }
63}
64
65impl TreeByteSource for BytesTreeSource {
66 fn read_exact_at(&mut self, offset: u64, buf: &mut [u8]) -> Result<(), TreeStreamError> {
67 let start =
68 usize::try_from(offset).map_err(|_| TreeStreamError::TruncatedFrame { offset })?;
69 let end = start
70 .checked_add(buf.len())
71 .ok_or(TreeStreamError::TruncatedFrame { offset })?;
72 let slice = self
73 .bytes
74 .get(start..end)
75 .ok_or(TreeStreamError::TruncatedFrame { offset })?;
76 buf.copy_from_slice(slice);
77 self.bytes_read += buf.len() as u64;
78 Ok(())
79 }
80
81 fn len(&self) -> u64 {
82 self.bytes.len() as u64
83 }
84
85 fn integrity(&self) -> TreeBodyIntegrity {
86 self.integrity
87 }
88
89 fn bytes_read(&self) -> u64 {
90 self.bytes_read
91 }
92}
93
94#[derive(Debug)]
97pub struct FileTreeSource {
98 file: File,
99 len: u64,
100 integrity: TreeBodyIntegrity,
101 bytes_read: u64,
102}
103
104impl FileTreeSource {
105 pub fn sequential_verify(file: File, len: u64) -> Self {
106 Self {
107 file,
108 len,
109 integrity: TreeBodyIntegrity::SequentialVerify,
110 bytes_read: 0,
111 }
112 }
113}
114
115impl TreeByteSource for FileTreeSource {
116 fn read_exact_at(&mut self, offset: u64, buf: &mut [u8]) -> Result<(), TreeStreamError> {
117 if offset
118 .checked_add(buf.len() as u64)
119 .is_none_or(|end| end > self.len)
120 {
121 return Err(TreeStreamError::TruncatedFrame { offset });
122 }
123 self.file.seek(SeekFrom::Start(offset))?;
124 self.file.read_exact(buf)?;
125 self.bytes_read += buf.len() as u64;
126 Ok(())
127 }
128
129 fn len(&self) -> u64 {
130 self.len
131 }
132
133 fn integrity(&self) -> TreeBodyIntegrity {
134 self.integrity
135 }
136
137 fn bytes_read(&self) -> u64 {
138 self.bytes_read
139 }
140}
141
142#[derive(Debug)]
144pub enum OpenedTreeBody {
145 Bytes(BytesTreeSource),
146 File(FileTreeSource),
147}
148
149impl TreeByteSource for OpenedTreeBody {
150 fn read_exact_at(&mut self, offset: u64, buf: &mut [u8]) -> Result<(), TreeStreamError> {
151 match self {
152 Self::Bytes(source) => source.read_exact_at(offset, buf),
153 Self::File(source) => source.read_exact_at(offset, buf),
154 }
155 }
156
157 fn len(&self) -> u64 {
158 match self {
159 Self::Bytes(source) => source.len(),
160 Self::File(source) => source.len(),
161 }
162 }
163
164 fn integrity(&self) -> TreeBodyIntegrity {
165 match self {
166 Self::Bytes(source) => source.integrity(),
167 Self::File(source) => source.integrity(),
168 }
169 }
170
171 fn bytes_read(&self) -> u64 {
172 match self {
173 Self::Bytes(source) => source.bytes_read(),
174 Self::File(source) => source.bytes_read(),
175 }
176 }
177}