Skip to main content

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}