Skip to main content

nix_compat/wire/
serde.rs

1mod derivation {
2    use crate::derivation::OutputName;
3    use nix_compat_derive::nix_serde_remote;
4
5    nix_serde_remote!(
6        #[nix(from_str, display)]
7        OutputName
8    );
9}
10
11mod derived_path {
12    use crate::derived_path::{DerivedPath, LegacyDerivedPath};
13    use nix_compat_derive::nix_serde_remote;
14
15    nix_serde_remote!(
16        #[nix(into = "LegacyDerivedPath", from = "LegacyDerivedPath")]
17        DerivedPath
18    );
19    nix_serde_remote!(
20        #[nix(from_str, display)]
21        LegacyDerivedPath
22    );
23}
24
25mod int {
26    use nix_compat_derive::{nix_deserialize_remote, nix_serde_remote};
27
28    nix_deserialize_remote!(
29        #[nix(try_from = "u64")]
30        u8
31    );
32    nix_serde_remote!(
33        #[nix(try_from = "u64", into = "u64")]
34        u16
35    );
36    nix_serde_remote!(
37        #[nix(try_from = "u64", into = "u64")]
38        u32
39    );
40    nix_serde_remote!(
41        #[nix(try_from = "u64", try_into = "u64")]
42        i64
43    );
44}
45
46mod log {
47    nix_compat_derive::nix_serde_remote!(
48        #[nix(try_from = "u64", into = "u64")]
49        crate::log::VerbosityLevel
50    );
51}
52
53mod narinfo {
54    use crate::narinfo::Signature;
55    use crate::wire::de::{NixDeserialize, NixRead};
56
57    nix_compat_derive::nix_serialize_remote!(#[nix(display)] Signature<String>);
58
59    impl NixDeserialize for Signature<String> {
60        async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
61        where
62            R: ?Sized + NixRead + Send,
63        {
64            use crate::wire::de::Error;
65            let value: Option<String> = reader.try_read_value().await?;
66            match value {
67                Some(value) => Ok(Some(
68                    Signature::<String>::parse(&value).map_err(R::Error::invalid_data)?,
69                )),
70                None => Ok(None),
71            }
72        }
73    }
74}
75
76mod nixhash {
77    use nix_compat_derive::nix_serde_remote;
78
79    use crate::nixhash::{CAHash, HashAlgo};
80    use crate::wire::de::{NixDeserialize, NixRead};
81    use crate::wire::ser::{NixSerialize, NixWrite};
82
83    nix_serde_remote!(
84        #[nix(display, from_str)]
85        HashAlgo
86    );
87
88    impl NixSerialize for CAHash {
89        async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
90        where
91            W: NixWrite,
92        {
93            writer.write_value(&self.to_string()).await
94        }
95    }
96
97    impl NixDeserialize for CAHash {
98        async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
99        where
100            R: ?Sized + NixRead + Send,
101        {
102            use crate::wire::de::Error;
103            let value: Option<String> = reader.try_read_value().await?;
104            match value {
105                Some(value) => Ok(Some(CAHash::from_nix_hex_str(&value).ok_or_else(|| {
106                    R::Error::invalid_data(format!("Invalid cahash {value}"))
107                })?)),
108                None => Ok(None),
109            }
110        }
111    }
112
113    impl NixSerialize for Option<CAHash> {
114        async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
115        where
116            W: NixWrite,
117        {
118            match self {
119                Some(value) => writer.write_value(value).await,
120                None => writer.write_value("").await,
121            }
122        }
123    }
124
125    impl NixDeserialize for Option<CAHash> {
126        async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
127        where
128            R: ?Sized + NixRead + Send,
129        {
130            use crate::wire::de::Error;
131            let value: Option<String> = reader.try_read_value().await?;
132            match value {
133                Some(value) => {
134                    if value.is_empty() {
135                        Ok(None)
136                    } else {
137                        Ok(Some(Some(CAHash::from_nix_hex_str(&value).ok_or_else(
138                            || R::Error::invalid_data(format!("Invalid cahash {value}")),
139                        )?)))
140                    }
141                }
142                None => Ok(None),
143            }
144        }
145    }
146}
147
148mod realisation {
149    use nix_compat_derive::nix_serde_remote;
150
151    use crate::realisation::{DrvOutput, Realisation};
152    use crate::wire::de::NixDeserialize;
153    use crate::wire::ser::NixSerialize;
154
155    nix_serde_remote!(
156        #[nix(from_str, display)]
157        DrvOutput
158    );
159
160    impl NixSerialize for Realisation {
161        async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
162        where
163            W: crate::wire::ser::NixWrite,
164        {
165            use crate::wire::ser::Error;
166            let s = serde_json::to_string(&self).map_err(W::Error::custom)?;
167            writer.write_slice(s.as_bytes()).await
168        }
169    }
170
171    impl NixDeserialize for Realisation {
172        async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
173        where
174            R: ?Sized + crate::wire::de::NixRead + Send,
175        {
176            use crate::wire::de::Error;
177            if let Some(buf) = reader.try_read_bytes().await? {
178                Ok(Some(
179                    serde_json::from_slice(&buf).map_err(R::Error::custom)?,
180                ))
181            } else {
182                Ok(None)
183            }
184        }
185    }
186
187    #[cfg(test)]
188    mod tests {
189        use rstest::rstest;
190
191        use crate::{btree_map, hash_set, realisation::Realisation};
192
193        #[tokio::test]
194        #[rstest]
195        #[case(
196            Realisation {
197                id: "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!out".parse().unwrap(),
198                out_path: "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3".parse().unwrap(),
199                signatures: hash_set!["cache.nixos.org-1:0CpHca+06TwFp9VkMyz5OaphT3E8mnS+1SWymYlvFaghKSYPCMQ66TS1XPAr1+y9rfQZPLaHrBjjnIRktE/nAA=="],
200                dependent_realisations: btree_map![
201                    "sha256:ba7816bf8f01cfea414140de5dae2223b00361a496177a9cf410ff61f20015ad!dev" => "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-dev",
202                    "sha256:ba7816bf8f01cfea414140de5dae2223b00361a696177a9cf410ff61f20015ad!bin" => "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-bin",
203
204                ],
205            },
206            "{\"id\":\"sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!out\",\"outPath\":\"7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3\",\"signatures\":[\"cache.nixos.org-1:0CpHca+06TwFp9VkMyz5OaphT3E8mnS+1SWymYlvFaghKSYPCMQ66TS1XPAr1+y9rfQZPLaHrBjjnIRktE/nAA==\"],\"dependentRealisations\":{\"sha256:ba7816bf8f01cfea414140de5dae2223b00361a496177a9cf410ff61f20015ad!dev\":\"7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-dev\",\"sha256:ba7816bf8f01cfea414140de5dae2223b00361a696177a9cf410ff61f20015ad!bin\":\"7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-bin\"}}",
207        )]
208        async fn nix_write_realisation(#[case] value: Realisation, #[case] expected: &str) {
209            use crate::wire::ser::NixWrite as _;
210
211            let mut mock = crate::test::wire::ser::Builder::new()
212                .write_slice(expected.as_bytes())
213                .build();
214            mock.write_value(&value).await.unwrap();
215        }
216
217        #[tokio::test]
218        #[rstest]
219        #[case(
220            Realisation {
221                id: "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!out".parse().unwrap(),
222                out_path: "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3".parse().unwrap(),
223                signatures: hash_set!["cache.nixos.org-1:0CpHca+06TwFp9VkMyz5OaphT3E8mnS+1SWymYlvFaghKSYPCMQ66TS1XPAr1+y9rfQZPLaHrBjjnIRktE/nAA=="],
224                dependent_realisations: btree_map![
225                    "sha256:ba7816bf8f01cfea414140de5dae2223b00361a496177a9cf410ff61f20015ad!dev" => "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-dev",
226                    "sha256:ba7816bf8f01cfea414140de5dae2223b00361a696177a9cf410ff61f20015ad!bin" => "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-bin",
227
228                ],
229            },
230            "{\"id\":\"sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!out\",\"outPath\":\"7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3\",\"signatures\":[\"cache.nixos.org-1:0CpHca+06TwFp9VkMyz5OaphT3E8mnS+1SWymYlvFaghKSYPCMQ66TS1XPAr1+y9rfQZPLaHrBjjnIRktE/nAA==\"],\"dependentRealisations\":{\"sha256:ba7816bf8f01cfea414140de5dae2223b00361a496177a9cf410ff61f20015ad!dev\":\"7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-dev\",\"sha256:ba7816bf8f01cfea414140de5dae2223b00361a696177a9cf410ff61f20015ad!bin\":\"7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-bin\"}}",
231        )]
232        async fn nix_read_realisation(#[case] expected: Realisation, #[case] value: &str) {
233            use crate::wire::de::NixRead as _;
234
235            let mut mock = crate::test::wire::de::Builder::new()
236                .read_slice(value.as_bytes())
237                .build();
238            let actual: Realisation = mock.read_value().await.unwrap();
239            pretty_assertions::assert_eq!(actual, expected);
240        }
241    }
242}
243
244mod store_path {
245    use crate::store_path::StorePath;
246    use crate::wire::de::{NixDeserialize, NixRead};
247    use crate::wire::ser::{NixSerialize, NixWrite};
248
249    // Custom implementation since FromStr does not use from_absolute_path
250    impl NixDeserialize for StorePath {
251        async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
252        where
253            R: ?Sized + NixRead + Send,
254        {
255            use crate::wire::de::Error;
256            if let Some(buf) = reader.try_read_bytes().await? {
257                let result = StorePath::from_absolute_path(&buf);
258                result.map(Some).map_err(R::Error::invalid_data)
259            } else {
260                Ok(None)
261            }
262        }
263    }
264
265    // Custom implementation since Display does not use absolute paths.
266    impl NixSerialize for StorePath {
267        fn serialize<W>(&self, writer: &mut W) -> impl Future<Output = Result<(), W::Error>> + Send
268        where
269            W: NixWrite,
270        {
271            let sp = self.as_absolute_path_fmt();
272            async move { writer.write_display(&sp).await }
273        }
274    }
275
276    impl NixDeserialize for Option<StorePath> {
277        async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
278        where
279            R: ?Sized + NixRead + Send,
280        {
281            use crate::wire::de::Error;
282            if let Some(buf) = reader.try_read_bytes().await? {
283                if buf.is_empty() {
284                    Ok(Some(None))
285                } else {
286                    let result = StorePath::from_absolute_path(&buf);
287                    result
288                        .map(|r| Some(Some(r)))
289                        .map_err(R::Error::invalid_data)
290                }
291            } else {
292                Ok(Some(None))
293            }
294        }
295    }
296
297    // Writes StorePath or an empty string.
298    impl NixSerialize for Option<StorePath> {
299        async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
300        where
301            W: NixWrite,
302        {
303            match self {
304                Some(value) => writer.write_value(value).await,
305                None => writer.write_value("").await,
306            }
307        }
308    }
309}