nix_compat/nixhash/
serde.rs

1use super::NixHash;
2use crate::nixbase32;
3use serde::{Deserialize, Serialize};
4use std::fmt::Formatter;
5
6impl<'de> Deserialize<'de> for NixHash {
7    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
8    where
9        D: serde::Deserializer<'de>,
10    {
11        use serde::de::{Error, Visitor};
12
13        struct NixHashVisitor;
14
15        impl Visitor<'_> for NixHashVisitor {
16            type Value = NixHash;
17
18            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
19                formatter.write_str("a string representing a Nix hash")
20            }
21
22            fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
23            where
24                E: Error,
25            {
26                NixHash::from_str(s, None).map_err(|err| Error::custom(format!("{err}: {s:?}")))
27            }
28        }
29
30        deserializer.deserialize_str(NixHashVisitor)
31    }
32}
33
34impl Serialize for NixHash {
35    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
36    where
37        S: serde::Serializer,
38    {
39        let sri = self.to_sri_string();
40        sri.serialize(serializer)
41    }
42}
43
44/// The length of a sha256 digest, nixbase32-encoded.
45const NIXBASE32_SHA256_ENCODE_LEN: usize = nixbase32::encode_len(32);
46
47pub fn from_nix_nixbase32_or_sri<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error>
48where
49    D: serde::Deserializer<'de>,
50{
51    let str: &'de str = Deserialize::deserialize(deserializer)?;
52    if let Some(digest_str) = str.strip_prefix("sha256:") {
53        return from_nix_nixbase32::<D>(digest_str);
54    }
55    if let Some(digest_str) = str.strip_prefix("sha256-") {
56        return from_sri::<D>(digest_str);
57    }
58    Err(serde::de::Error::invalid_value(
59        serde::de::Unexpected::Str(str),
60        &"extected a valid nixbase32 or sri narHash",
61    ))
62}
63
64pub fn from_sri<'de, D>(str: &str) -> Result<[u8; 32], D::Error>
65where
66    D: serde::Deserializer<'de>,
67{
68    let digest: [u8; 32] = data_encoding::BASE64
69        .decode(str.as_bytes())
70        .map_err(|_| {
71            serde::de::Error::invalid_value(
72                serde::de::Unexpected::Str(str),
73                &"valid base64 encoded string",
74            )
75        })?
76        .try_into()
77        .map_err(|_| {
78            serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"valid digest len")
79        })?;
80
81    Ok(digest)
82}
83
84pub fn from_nix_nixbase32<'de, D>(str: &str) -> Result<[u8; 32], D::Error>
85where
86    D: serde::Deserializer<'de>,
87{
88    let digest_str: [u8; NIXBASE32_SHA256_ENCODE_LEN] =
89        str.as_bytes().try_into().map_err(|_| {
90            serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"valid digest len")
91        })?;
92
93    let digest: [u8; 32] = nixbase32::decode_fixed(digest_str).map_err(|_| {
94        serde::de::Error::invalid_value(serde::de::Unexpected::Str(str), &"valid nixbase32")
95    })?;
96
97    Ok(digest)
98}
99
100pub fn to_nix_nixbase32<S>(v: &[u8; 32], serializer: S) -> Result<S::Ok, S::Error>
101where
102    S: serde::Serializer,
103{
104    let string = NixHash::Sha256(*v).to_nix_nixbase32();
105    string.serialize(serializer)
106}