Skip to main content

harmos_domain/model/storage/files/
read.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10// Finished File Read Contract
11
12/* === Modules === */
13
14/* === Re-Exports === */
15
16/* === Imports === */
17
18// Standard Library Imports
19use std::path::PathBuf;
20// Third Party Imports
21// Local Imports
22use super::FileReference;
23use crate::model::storage::codec::{Nested, Unsigned, coded, variants};
24use crate::{Error, MemorySize, Result};
25
26/* === Constants === */
27
28/* === Macros === */
29
30crate::model::storage::codec::product!(ByteRange {
31    offset: crate::model::storage::codec::Unsigned => 1,
32    limit: crate::model::storage::codec::Optional<crate::model::storage::codec::Unsigned> => 2,
33});
34crate::model::storage::codec::product!(FileBatch {
35    offset: crate::model::storage::codec::Unsigned => 1,
36    bytes: crate::model::storage::codec::Bytes => 2,
37});
38crate::model::storage::codec::product!(FileCompletion {
39    bytes: crate::model::storage::codec::Unsigned => 1,
40});
41variants!(FileSource {
42    0, 1, "stored": Self::Stored(file) => { file: Nested<FileReference> => 1 } => Self::Stored(file);
43    1, 2, "local": Self::Local(path) => { path: super::codec::LocalPath => 1 } => Self::Local(path);
44});
45variants!(FollowStart {
46    0, 1, "beginning": Self::Beginning => {} => Self::Beginning;
47    1, 2, "end": Self::End => {} => Self::End;
48    2, 3, "at": Self::At(offset) => { offset: Unsigned => 1 } => Self::At(offset);
49});
50variants!(FileEvent {
51    0, 1, "data": Self::Data(batch) => { batch: Nested<FileBatch> => 1 } => Self::Data(batch);
52    1, 2, "truncated": Self::Truncated { length } => { length: Unsigned => 1 } => Self::Truncated { length };
53    2, 3, "replaced": Self::Replaced => {} => Self::Replaced;
54});
55coded!(CaptureConsistency { Bounded, Stable });
56crate::model::storage::codec::product!(FileHash {
57    bytes_read: Unsigned => 1,
58    sha256: super::codec::Digest => 2,
59});
60
61/* === Type Aliases === */
62
63/* === Structs === */
64
65#[derive(Clone, Copy, Debug, PartialEq, Eq)]
66pub struct ByteRange {
67    pub offset: u64,
68    pub limit: Option<u64>,
69}
70#[derive(Clone, Debug, PartialEq, Eq)]
71pub struct FileBatch {
72    pub offset: u64,
73    pub bytes: Vec<u8>,
74}
75#[derive(Clone, Copy, Debug, PartialEq, Eq)]
76pub struct FileCompletion {
77    pub bytes: u64,
78}
79
80#[derive(Clone, Copy, Debug, PartialEq, Eq)]
81pub struct FileHash {
82    pub bytes_read: u64,
83    pub sha256: [u8; 32],
84}
85
86/* === Enums === */
87
88#[derive(Clone, Debug, PartialEq, Eq)]
89pub enum FileSource {
90    Stored(FileReference),
91    Local(PathBuf),
92}
93
94#[derive(Clone, Copy, Debug, PartialEq, Eq)]
95pub enum FollowStart {
96    Beginning,
97    End,
98    At(u64),
99}
100
101#[derive(Clone, Debug, PartialEq, Eq)]
102pub enum FileEvent {
103    Data(FileBatch),
104    Truncated { length: u64 },
105    Replaced,
106}
107
108#[derive(Clone, Copy, Debug, PartialEq, Eq)]
109pub enum CaptureConsistency {
110    Bounded,
111    Stable,
112}
113
114/* === Traits === */
115
116/* === Implementations === */
117
118impl FileSource {
119    pub fn grant_scope(&self) -> Option<String> {
120        match self {
121            Self::Stored(file) => Some(file.metadata.id.as_str().to_owned()),
122            Self::Local(_) => None,
123        }
124    }
125}
126
127impl MemorySize for FileSource {
128    fn memory_size(&self) -> usize {
129        std::mem::size_of::<Self>()
130            + match self {
131                Self::Stored(file) => file.memory_size().saturating_sub(std::mem::size_of_val(file)),
132                Self::Local(path) => path.capacity(),
133            }
134    }
135}
136
137impl MemorySize for FollowStart {
138    fn memory_size(&self) -> usize {
139        std::mem::size_of::<Self>()
140    }
141}
142
143impl MemorySize for FileEvent {
144    fn memory_size(&self) -> usize {
145        std::mem::size_of::<Self>()
146            + match self {
147                Self::Data(batch) => batch.memory_size().saturating_sub(std::mem::size_of_val(batch)),
148                Self::Truncated { .. } | Self::Replaced => 0,
149            }
150    }
151}
152
153impl MemorySize for CaptureConsistency {
154    fn memory_size(&self) -> usize {
155        std::mem::size_of::<Self>()
156    }
157}
158
159impl MemorySize for FileHash {
160    fn memory_size(&self) -> usize {
161        std::mem::size_of::<Self>()
162    }
163}
164
165impl ByteRange {
166    pub fn end(self, length: u64) -> Result<u64> {
167        let remaining = length
168            .checked_sub(self.offset)
169            .ok_or(Error::InvalidInput { field: "file byte range", reason: "offset exceeds the immutable file length" })?;
170        self.offset
171            .checked_add(self.limit.unwrap_or(remaining).min(remaining))
172            .ok_or(Error::InvalidInput { field: "file byte range", reason: "byte range overflow" })
173    }
174}
175impl MemorySize for ByteRange {
176    fn memory_size(&self) -> usize {
177        std::mem::size_of::<Self>()
178    }
179}
180impl MemorySize for FileBatch {
181    fn memory_size(&self) -> usize {
182        std::mem::size_of::<Self>().saturating_add(self.bytes.capacity())
183    }
184}
185impl MemorySize for FileCompletion {
186    fn memory_size(&self) -> usize {
187        std::mem::size_of::<Self>()
188    }
189}
190
191/* === Public Functions === */
192
193/* === Private Functions === */
194
195/* === Tests === */