pith_digest/names.rs
1//! The closed sets of names that appear in on-disk records.
2
3use core::fmt;
4
5/// The hash functions this workspace can produce, so an index record
6/// can say what it was computed with.
7///
8/// The [`as_str`](Algorithm::as_str) / [`from_str`](Algorithm::from_str)
9/// pair is the stable wire form: these strings appear in on-disk
10/// records and must not change without a format version bump.
11#[derive(Copy, Clone, Debug, PartialEq, Eq)]
12pub enum Algorithm {
13 /// SHA-1. 20-byte digests.
14 Sha1,
15 /// SHA-2 with a 256-bit state. 32-byte digests.
16 Sha256,
17 /// SHA-2 with a 512-bit state. 64-byte digests.
18 Sha512,
19 /// BLAKE3 with the default 32-byte output.
20 Blake3,
21 /// MD5. 16-byte digests.
22 Md5,
23 /// xxHash64. 8-byte digests.
24 XxHash64,
25 /// FastCDC content-defined chunking. 4-byte digests: the 32-bit
26 /// Gear fingerprint at the cut point, the width the FastCDC
27 /// reference implementation produces.
28 FastCdc,
29 /// A perceptual hash. The width is a property of the modality
30 /// (image, audio, video, text), so
31 /// [`output_len`](Algorithm::output_len) is `None`.
32 Perceptual,
33 /// A name written by a future version of this kit. A record
34 /// carrying it can still be read; it just cannot be recomputed here.
35 Unknown,
36}
37
38impl Algorithm {
39 /// The stable wire form, e.g. `"sha256"`.
40 pub fn as_str(&self) -> &'static str {
41 match self {
42 Algorithm::Sha1 => "sha1",
43 Algorithm::Sha256 => "sha256",
44 Algorithm::Sha512 => "sha512",
45 Algorithm::Blake3 => "blake3",
46 Algorithm::Md5 => "md5",
47 Algorithm::XxHash64 => "xxhash64",
48 Algorithm::FastCdc => "fastcdc",
49 Algorithm::Perceptual => "perceptual",
50 Algorithm::Unknown => "unknown",
51 }
52 }
53
54 /// Parses the wire form. An unrecognised string yields
55 /// [`Algorithm::Unknown`], never an error, so records written by a
56 /// future version stay readable. Matching is exact and
57 /// case-sensitive: `"SHA256"` is `Unknown`.
58 // The spec pins this name and this shape: an inherent function
59 // returning `Self`, not `FromStr`, because parsing never fails.
60 #[expect(clippy::should_implement_trait)]
61 pub fn from_str(s: &str) -> Self {
62 match s {
63 "sha1" => Algorithm::Sha1,
64 "sha256" => Algorithm::Sha256,
65 "sha512" => Algorithm::Sha512,
66 "blake3" => Algorithm::Blake3,
67 "md5" => Algorithm::Md5,
68 "xxhash64" => Algorithm::XxHash64,
69 "fastcdc" => Algorithm::FastCdc,
70 "perceptual" => Algorithm::Perceptual,
71 _ => Algorithm::Unknown,
72 }
73 }
74
75 /// Digest width in bytes for the fixed-width members; `None` for
76 /// [`Perceptual`](Algorithm::Perceptual), whose width is a property
77 /// of the modality, and for [`Unknown`](Algorithm::Unknown).
78 pub fn output_len(&self) -> Option<usize> {
79 match self {
80 Algorithm::Sha1 => Some(20),
81 Algorithm::Sha256 => Some(32),
82 Algorithm::Sha512 => Some(64),
83 Algorithm::Blake3 => Some(32),
84 Algorithm::Md5 => Some(16),
85 Algorithm::XxHash64 => Some(8),
86 Algorithm::FastCdc => Some(4),
87 Algorithm::Perceptual | Algorithm::Unknown => None,
88 }
89 }
90}
91
92impl fmt::Display for Algorithm {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 f.write_str(self.as_str())
95 }
96}
97
98/// The container formats the codecs decode.
99///
100/// The enum is the set of formats the workspace *claims* to handle. A
101/// member is added in the phase that implements that decoder, not
102/// before — an enum listing a format that does not decode is a lie a
103/// caller can act on. The [`as_str`](Format::as_str) /
104/// [`from_str`](Format::from_str) pair is the stable wire form, with
105/// the same rules as [`Algorithm`].
106#[derive(Copy, Clone, Debug, PartialEq, Eq)]
107pub enum Format {
108 /// PNG.
109 Png,
110 /// JPEG.
111 Jpeg,
112 /// BMP.
113 Bmp,
114 /// ZIP.
115 Zip,
116 /// MP4.
117 Mp4,
118 /// MP3.
119 Mp3,
120 /// WAV.
121 Wav,
122 /// FLAC.
123 Flac,
124 /// PDF.
125 Pdf,
126 /// GIF.
127 Gif,
128 /// A format written by a future version of this kit.
129 Unknown,
130}
131
132impl Format {
133 /// The stable wire form, e.g. `"png"`.
134 pub fn as_str(&self) -> &'static str {
135 match self {
136 Format::Png => "png",
137 Format::Jpeg => "jpeg",
138 Format::Bmp => "bmp",
139 Format::Zip => "zip",
140 Format::Mp4 => "mp4",
141 Format::Mp3 => "mp3",
142 Format::Wav => "wav",
143 Format::Flac => "flac",
144 Format::Pdf => "pdf",
145 Format::Gif => "gif",
146 Format::Unknown => "unknown",
147 }
148 }
149
150 /// Parses the wire form. An unrecognised string yields
151 /// [`Format::Unknown`], never an error, so records written by a
152 /// future version stay readable. Matching is exact and
153 /// case-sensitive.
154 // Same spec-pinned shape as `Algorithm::from_str`.
155 #[expect(clippy::should_implement_trait)]
156 pub fn from_str(s: &str) -> Self {
157 match s {
158 "png" => Format::Png,
159 "jpeg" => Format::Jpeg,
160 "bmp" => Format::Bmp,
161 "zip" => Format::Zip,
162 "mp4" => Format::Mp4,
163 "mp3" => Format::Mp3,
164 "wav" => Format::Wav,
165 "flac" => Format::Flac,
166 "pdf" => Format::Pdf,
167 "gif" => Format::Gif,
168 _ => Format::Unknown,
169 }
170 }
171}
172
173impl fmt::Display for Format {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 f.write_str(self.as_str())
176 }
177}