1mod derivation {
2 use crate::{
3 derivation::{OutputHash, OutputName, Outputs, UnverifiedOutputsBuilder},
4 store_path::StorePath,
5 wire::{de::NixDeserialize, ser::NixSerialize},
6 };
7 use data_encoding::HEXLOWER;
8 use nix_compat_derive::nix_serde_remote;
9
10 nix_serde_remote!(
11 #[nix(from_str, display)]
12 OutputName
13 );
14
15 impl NixSerialize for Option<&'_ OutputHash> {
16 async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
17 where
18 W: crate::wire::ser::NixWrite,
19 {
20 if let Some(output_hash) = self.as_ref() {
21 writer
22 .write_slice(output_hash.as_mode_and_algo_str().as_bytes())
23 .await?;
24 writer
25 .write_display(
26 &data_encoding::HEXLOWER.encode_display(output_hash.hash.digest_as_bytes()),
27 )
28 .await?;
29 } else {
30 writer.write_slice(&[]).await?;
31 writer.write_slice(&[]).await?;
32 }
33 Ok(())
34 }
35 }
36
37 impl NixDeserialize for Option<OutputHash> {
38 async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
39 where
40 R: ?Sized + crate::wire::de::NixRead + Send,
41 {
42 use crate::wire::de::Error;
43 if let Some(mode_and_algo) = reader.try_read_value::<String>().await? {
44 let hash = reader.read_value::<String>().await?;
45 if mode_and_algo.is_empty() && hash.is_empty() {
46 return Ok(Some(None));
47 }
48 let digest = HEXLOWER
49 .decode(hash.as_bytes())
50 .map_err(R::Error::invalid_data)?;
51 Ok(Some(Some(
52 OutputHash::from_mode_algo_and_digest(&mode_and_algo, digest)
53 .map_err(R::Error::invalid_data)?,
54 )))
55 } else {
56 Ok(None)
57 }
58 }
59 }
60
61 impl NixSerialize for Outputs {
62 async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
63 where
64 W: crate::wire::ser::NixWrite,
65 {
66 for (output_name, path) in self {
67 writer.write_value(output_name).await?;
68 writer.write_value(path).await?;
69 writer.write_value(&self.as_fixed_output_hash()).await?;
70 }
71 Ok(())
72 }
73 }
74
75 impl NixDeserialize for Outputs {
76 async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
77 where
78 R: ?Sized + crate::wire::de::NixRead + Send,
79 {
80 use crate::wire::de::Error;
81 if let Some(len) = reader.try_read_value::<usize>().await? {
82 let mut builder = UnverifiedOutputsBuilder::new();
83 for _ in 0..len {
84 let output_name = reader.read_value::<OutputName>().await?;
85 let store_path = reader.read_value::<StorePath>().await?;
86 let output_hash = reader.read_value::<Option<OutputHash>>().await?;
87 builder
88 .try_insert(output_name, store_path, output_hash)
89 .map_err(R::Error::custom)?;
90 }
91 Ok(Some(builder.try_build().map_err(R::Error::custom)?))
92 } else {
93 Ok(None)
94 }
95 }
96 }
97}
98
99mod derived_path {
100 use crate::derived_path::{DerivedPath, LegacyDerivedPath};
101 use nix_compat_derive::nix_serde_remote;
102
103 nix_serde_remote!(
104 #[nix(into = "LegacyDerivedPath", from = "LegacyDerivedPath")]
105 DerivedPath
106 );
107 nix_serde_remote!(
108 #[nix(from_str, display)]
109 LegacyDerivedPath
110 );
111}
112
113mod int {
114 use nix_compat_derive::{nix_deserialize_remote, nix_serde_remote};
115
116 nix_deserialize_remote!(
117 #[nix(try_from = "u64")]
118 u8
119 );
120 nix_serde_remote!(
121 #[nix(try_from = "u64", into = "u64")]
122 u16
123 );
124 nix_serde_remote!(
125 #[nix(try_from = "u64", into = "u64")]
126 u32
127 );
128 nix_serde_remote!(
129 #[nix(try_from = "u64", try_into = "u64")]
130 i64
131 );
132}
133
134mod log {
135 nix_compat_derive::nix_serde_remote!(
136 #[nix(try_from = "u64", into = "u64")]
137 crate::log::VerbosityLevel
138 );
139}
140
141mod narinfo {
142 use crate::narinfo::Signature;
143 use crate::wire::de::{NixDeserialize, NixRead};
144
145 nix_compat_derive::nix_serialize_remote!(#[nix(display)] Signature<String>);
146
147 impl NixDeserialize for Signature<String> {
148 async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
149 where
150 R: ?Sized + NixRead + Send,
151 {
152 use crate::wire::de::Error;
153 let value: Option<String> = reader.try_read_value().await?;
154 match value {
155 Some(value) => Ok(Some(
156 Signature::<String>::parse(&value).map_err(R::Error::invalid_data)?,
157 )),
158 None => Ok(None),
159 }
160 }
161 }
162}
163
164mod nixhash {
165 use nix_compat_derive::nix_serde_remote;
166
167 use crate::nixhash::{CAHash, HashAlgo};
168 use crate::wire::de::{NixDeserialize, NixRead};
169 use crate::wire::ser::{NixSerialize, NixWrite};
170
171 nix_serde_remote!(
172 #[nix(display, from_str)]
173 HashAlgo
174 );
175
176 impl NixSerialize for CAHash {
177 async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
178 where
179 W: NixWrite,
180 {
181 writer.write_value(&self.to_string()).await
182 }
183 }
184
185 impl NixDeserialize for CAHash {
186 async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
187 where
188 R: ?Sized + NixRead + Send,
189 {
190 use crate::wire::de::Error;
191 let value: Option<String> = reader.try_read_value().await?;
192 match value {
193 Some(value) => Ok(Some(CAHash::from_nix_hex_str(&value).ok_or_else(|| {
194 R::Error::invalid_data(format!("Invalid cahash {value}"))
195 })?)),
196 None => Ok(None),
197 }
198 }
199 }
200
201 impl NixSerialize for Option<CAHash> {
202 async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
203 where
204 W: NixWrite,
205 {
206 match self {
207 Some(value) => writer.write_value(value).await,
208 None => writer.write_value("").await,
209 }
210 }
211 }
212
213 impl NixDeserialize for Option<CAHash> {
214 async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
215 where
216 R: ?Sized + NixRead + Send,
217 {
218 use crate::wire::de::Error;
219 let value: Option<String> = reader.try_read_value().await?;
220 match value {
221 Some(value) => {
222 if value.is_empty() {
223 Ok(None)
224 } else {
225 Ok(Some(Some(CAHash::from_nix_hex_str(&value).ok_or_else(
226 || R::Error::invalid_data(format!("Invalid cahash {value}")),
227 )?)))
228 }
229 }
230 None => Ok(None),
231 }
232 }
233 }
234}
235
236mod realisation {
237 use nix_compat_derive::nix_serde_remote;
238
239 use crate::realisation::{DrvOutput, Realisation};
240 use crate::wire::de::NixDeserialize;
241 use crate::wire::ser::NixSerialize;
242
243 nix_serde_remote!(
244 #[nix(from_str, display)]
245 DrvOutput
246 );
247
248 impl NixSerialize for Realisation {
249 async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
250 where
251 W: crate::wire::ser::NixWrite,
252 {
253 use crate::wire::ser::Error;
254 let s = serde_json::to_string(&self).map_err(W::Error::custom)?;
255 writer.write_slice(s.as_bytes()).await
256 }
257 }
258
259 impl NixDeserialize for Realisation {
260 async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
261 where
262 R: ?Sized + crate::wire::de::NixRead + Send,
263 {
264 use crate::wire::de::Error;
265 if let Some(buf) = reader.try_read_bytes().await? {
266 Ok(Some(
267 serde_json::from_slice(&buf).map_err(R::Error::custom)?,
268 ))
269 } else {
270 Ok(None)
271 }
272 }
273 }
274
275 #[cfg(test)]
276 mod tests {
277 use rstest::rstest;
278
279 use crate::{btree_map, hash_set, realisation::Realisation};
280
281 #[tokio::test]
282 #[rstest]
283 #[case(
284 Realisation {
285 id: "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!out".parse().unwrap(),
286 out_path: "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3".parse().unwrap(),
287 signatures: hash_set!["cache.nixos.org-1:0CpHca+06TwFp9VkMyz5OaphT3E8mnS+1SWymYlvFaghKSYPCMQ66TS1XPAr1+y9rfQZPLaHrBjjnIRktE/nAA=="],
288 dependent_realisations: btree_map![
289 "sha256:ba7816bf8f01cfea414140de5dae2223b00361a496177a9cf410ff61f20015ad!dev" => "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-dev",
290 "sha256:ba7816bf8f01cfea414140de5dae2223b00361a696177a9cf410ff61f20015ad!bin" => "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-bin",
291
292 ],
293 },
294 "{\"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\"}}",
295 )]
296 async fn nix_write_realisation(#[case] value: Realisation, #[case] expected: &str) {
297 use crate::wire::ser::NixWrite as _;
298
299 let mut mock = crate::test::wire::ser::Builder::new()
300 .write_slice(expected.as_bytes())
301 .build();
302 mock.write_value(&value).await.unwrap();
303 }
304
305 #[tokio::test]
306 #[rstest]
307 #[case(
308 Realisation {
309 id: "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!out".parse().unwrap(),
310 out_path: "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3".parse().unwrap(),
311 signatures: hash_set!["cache.nixos.org-1:0CpHca+06TwFp9VkMyz5OaphT3E8mnS+1SWymYlvFaghKSYPCMQ66TS1XPAr1+y9rfQZPLaHrBjjnIRktE/nAA=="],
312 dependent_realisations: btree_map![
313 "sha256:ba7816bf8f01cfea414140de5dae2223b00361a496177a9cf410ff61f20015ad!dev" => "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-dev",
314 "sha256:ba7816bf8f01cfea414140de5dae2223b00361a696177a9cf410ff61f20015ad!bin" => "7h7qgvs4kgzsn8a6rb273saxyqh4jxlz-konsole-18.12.3-bin",
315
316 ],
317 },
318 "{\"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\"}}",
319 )]
320 async fn nix_read_realisation(#[case] expected: Realisation, #[case] value: &str) {
321 use crate::wire::de::NixRead as _;
322
323 let mut mock = crate::test::wire::de::Builder::new()
324 .read_slice(value.as_bytes())
325 .build();
326 let actual: Realisation = mock.read_value().await.unwrap();
327 pretty_assertions::assert_eq!(actual, expected);
328 }
329 }
330}
331
332mod store_path {
333 use crate::store_path::StorePath;
334 use crate::wire::de::{NixDeserialize, NixRead};
335 use crate::wire::ser::{NixSerialize, NixWrite};
336
337 impl NixDeserialize for StorePath {
339 async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
340 where
341 R: ?Sized + NixRead + Send,
342 {
343 use crate::wire::de::Error;
344 if let Some(buf) = reader.try_read_bytes().await? {
345 let result = StorePath::from_absolute_path(&buf);
346 result.map(Some).map_err(R::Error::invalid_data)
347 } else {
348 Ok(None)
349 }
350 }
351 }
352
353 impl NixSerialize for StorePath {
355 fn serialize<W>(&self, writer: &mut W) -> impl Future<Output = Result<(), W::Error>> + Send
356 where
357 W: NixWrite,
358 {
359 let sp = self.as_absolute_path_fmt();
360 async move { writer.write_display(&sp).await }
361 }
362 }
363
364 impl NixDeserialize for Option<StorePath> {
365 async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
366 where
367 R: ?Sized + NixRead + Send,
368 {
369 use crate::wire::de::Error;
370 if let Some(buf) = reader.try_read_bytes().await? {
371 if buf.is_empty() {
372 Ok(Some(None))
373 } else {
374 let result = StorePath::from_absolute_path(&buf);
375 result
376 .map(|r| Some(Some(r)))
377 .map_err(R::Error::invalid_data)
378 }
379 } else {
380 Ok(Some(None))
381 }
382 }
383 }
384
385 impl NixSerialize for Option<StorePath> {
387 async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
388 where
389 W: NixWrite,
390 {
391 match self {
392 Some(value) => writer.write_value(value).await,
393 None => writer.write_value("").await,
394 }
395 }
396 }
397}