io_m2dir/entry.rs
1//! Entry-level m2dir coroutines and their shared types.
2//!
3//! An entry is a single message file inside an m2dir, named
4//! `<date>,<checksum>.<nonce>` per the specification. This module holds
5//! the [`M2dirEntry`] handle and its companions, shared by the store,
6//! get, list and delete coroutines below.
7
8pub mod delete;
9pub mod get;
10pub mod list;
11pub mod store;
12
13use alloc::{string::String, vec::Vec};
14
15use thiserror::Error;
16
17use crate::{flag::M2dirFlags, path::M2dirPath};
18
19/// Errors that can occur while parsing or validating an entry
20/// filename.
21#[derive(Clone, Debug, Error)]
22pub enum M2dirEntryParseError {
23 /// The given path is not a regular file.
24 #[error("path {0} is not a regular file")]
25 NotFile(M2dirPath),
26 /// The path has no final filename component.
27 #[error("path {0} is missing a filename")]
28 MissingFilename(M2dirPath),
29 /// The filename does not match the m2dir specification.
30 #[error("entry {path} does not match filename spec: {reason}")]
31 InvalidFilename {
32 path: M2dirPath,
33 reason: &'static str,
34 },
35 /// The checksum embedded in the filename does not match the file
36 /// contents.
37 #[error("invalid checksum for {path}: expected {expected:?}, got {got:?}")]
38 InvalidChecksum {
39 path: M2dirPath,
40 expected: String,
41 got: String,
42 },
43}
44
45/// A single entry inside an [`M2dir`](crate::m2dir::M2dir).
46#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
47pub struct M2dirEntry {
48 id: String,
49 path: M2dirPath,
50}
51
52impl M2dirEntry {
53 /// Builds an [`M2dirEntry`] from a path and its unique id without
54 /// checking the on-disk checksum. Used by coroutines that have
55 /// just delivered the entry and trust their own checksum.
56 pub fn from_parts(id: impl Into<String>, path: impl Into<M2dirPath>) -> Self {
57 Self {
58 id: id.into(),
59 path: path.into(),
60 }
61 }
62
63 /// Returns the path to the entry file.
64 pub fn path(&self) -> &M2dirPath {
65 &self.path
66 }
67
68 /// Returns the unique identifier of the entry (the
69 /// `<checksum>.<nonce>` portion of the filename).
70 pub fn id(&self) -> &str {
71 &self.id
72 }
73
74 /// Returns the checksum portion of the id (the chunk before the
75 /// last `.`).
76 pub fn checksum(&self) -> &str {
77 self.id.rsplit_once('.').map(|(c, _)| c).unwrap_or(&self.id)
78 }
79}
80
81/// An [`M2dirEntry`] paired with its file contents and flags metadata.
82///
83/// Produced by the bulk reads on
84/// [`M2dirClient`](crate::client::M2dirClient), which fetch an entry's
85/// bytes and its `.flags` sidecar in one pass.
86#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
87pub struct M2dirFullEntry {
88 entry: M2dirEntry,
89 contents: Vec<u8>,
90 flags: M2dirFlags,
91}
92
93impl M2dirFullEntry {
94 /// Builds a full entry from its resolved handle, file contents and
95 /// flags set.
96 pub fn from_parts(entry: M2dirEntry, contents: Vec<u8>, flags: M2dirFlags) -> Self {
97 Self {
98 entry,
99 contents,
100 flags,
101 }
102 }
103
104 /// Returns the underlying entry handle (id and on-disk path).
105 pub fn entry(&self) -> &M2dirEntry {
106 &self.entry
107 }
108
109 /// Returns the raw bytes read from the entry file.
110 pub fn contents(&self) -> &[u8] {
111 &self.contents
112 }
113
114 /// Returns the flags read from the entry's `.flags` sidecar.
115 pub fn flags(&self) -> &M2dirFlags {
116 &self.flags
117 }
118}