nix_compat/nix_daemon/
types.rs

1use crate::wire::de::Error;
2use crate::{
3    narinfo::Signature,
4    nixhash::CAHash,
5    store_path::StorePath,
6    wire::{
7        de::{NixDeserialize, NixRead},
8        ser::{NixSerialize, NixWrite},
9    },
10};
11use nix_compat_derive::{NixDeserialize, NixSerialize};
12use std::future::Future;
13
14/// Marker type that consumes/sends and ignores a u64.
15#[derive(Clone, Debug, NixDeserialize, NixSerialize)]
16#[nix(from = "u64", into = "u64")]
17pub struct IgnoredZero;
18impl From<u64> for IgnoredZero {
19    fn from(_: u64) -> Self {
20        IgnoredZero
21    }
22}
23
24impl From<IgnoredZero> for u64 {
25    fn from(_: IgnoredZero) -> Self {
26        0
27    }
28}
29
30#[derive(Debug, NixSerialize)]
31pub struct TraceLine {
32    have_pos: IgnoredZero,
33    hint: String,
34}
35
36/// Represents an error returned by the nix-daemon to its client.
37///
38/// Adheres to the format described in serialization.md
39#[derive(NixSerialize)]
40pub struct NixError {
41    #[nix(version = "26..")]
42    type_: &'static str,
43
44    #[nix(version = "26..")]
45    level: u64,
46
47    #[nix(version = "26..")]
48    name: &'static str,
49
50    msg: String,
51    #[nix(version = "26..")]
52    have_pos: IgnoredZero,
53
54    #[nix(version = "26..")]
55    traces: Vec<TraceLine>,
56
57    #[nix(version = "..=25")]
58    exit_status: u64,
59}
60
61impl NixError {
62    pub fn new(msg: String) -> Self {
63        Self {
64            type_: "Error",
65            level: 0, // error
66            name: "Error",
67            msg,
68            have_pos: IgnoredZero {},
69            traces: vec![],
70            exit_status: 1,
71        }
72    }
73}
74
75nix_compat_derive::nix_serialize_remote!(#[nix(display)] Signature<String>);
76
77impl NixDeserialize for Signature<String> {
78    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
79    where
80        R: ?Sized + NixRead + Send,
81    {
82        let value: Option<String> = reader.try_read_value().await?;
83        match value {
84            Some(value) => Ok(Some(
85                Signature::<String>::parse(&value).map_err(R::Error::invalid_data)?,
86            )),
87            None => Ok(None),
88        }
89    }
90}
91
92impl NixSerialize for CAHash {
93    async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
94    where
95        W: NixWrite,
96    {
97        writer.write_value(&self.to_nix_nixbase32_string()).await
98    }
99}
100
101impl NixSerialize for Option<CAHash> {
102    async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
103    where
104        W: NixWrite,
105    {
106        match self {
107            Some(value) => writer.write_value(value).await,
108            None => writer.write_value("").await,
109        }
110    }
111}
112
113impl NixDeserialize for CAHash {
114    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
115    where
116        R: ?Sized + NixRead + Send,
117    {
118        let value: Option<String> = reader.try_read_value().await?;
119        match value {
120            Some(value) => Ok(Some(CAHash::from_nix_hex_str(&value).ok_or_else(|| {
121                R::Error::invalid_data(format!("Invalid cahash {}", value))
122            })?)),
123            None => Ok(None),
124        }
125    }
126}
127
128impl NixDeserialize for Option<CAHash> {
129    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
130    where
131        R: ?Sized + NixRead + Send,
132    {
133        let value: Option<String> = reader.try_read_value().await?;
134        match value {
135            Some(value) => {
136                if value.is_empty() {
137                    Ok(None)
138                } else {
139                    Ok(Some(Some(CAHash::from_nix_hex_str(&value).ok_or_else(
140                        || R::Error::invalid_data(format!("Invalid cahash {}", value)),
141                    )?)))
142                }
143            }
144            None => Ok(None),
145        }
146    }
147}
148
149impl NixSerialize for Option<UnkeyedValidPathInfo> {
150    async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
151    where
152        W: NixWrite,
153    {
154        match self {
155            Some(value) => {
156                writer.write_value(&true).await?;
157                writer.write_value(value).await
158            }
159            None => writer.write_value(&false).await,
160        }
161    }
162}
163
164// Custom implementation since FromStr does not use from_absolute_path
165impl NixDeserialize for StorePath<String> {
166    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
167    where
168        R: ?Sized + NixRead + Send,
169    {
170        use crate::wire::de::Error;
171        if let Some(buf) = reader.try_read_bytes().await? {
172            let result = StorePath::<String>::from_absolute_path(&buf);
173            result.map(Some).map_err(R::Error::invalid_data)
174        } else {
175            Ok(None)
176        }
177    }
178}
179
180impl NixDeserialize for Option<StorePath<String>> {
181    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
182    where
183        R: ?Sized + NixRead + Send,
184    {
185        use crate::wire::de::Error;
186        if let Some(buf) = reader.try_read_bytes().await? {
187            if buf.is_empty() {
188                Ok(Some(None))
189            } else {
190                let result = StorePath::<String>::from_absolute_path(&buf);
191                result
192                    .map(|r| Some(Some(r)))
193                    .map_err(R::Error::invalid_data)
194            }
195        } else {
196            Ok(Some(None))
197        }
198    }
199}
200
201// Custom implementation since Display does not use absolute paths.
202impl<S> NixSerialize for StorePath<S>
203where
204    S: AsRef<str>,
205{
206    fn serialize<W>(&self, writer: &mut W) -> impl Future<Output = Result<(), W::Error>> + Send
207    where
208        W: NixWrite,
209    {
210        let sp = self.to_absolute_path();
211        async move { writer.write_value(&sp).await }
212    }
213}
214
215// Writes StorePath or an empty string.
216impl NixSerialize for Option<StorePath<String>> {
217    async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
218    where
219        W: NixWrite,
220    {
221        match self {
222            Some(value) => writer.write_value(value).await,
223            None => writer.write_value("").await,
224        }
225    }
226}
227
228#[derive(NixSerialize, Debug, Clone, Default, PartialEq)]
229pub struct UnkeyedValidPathInfo {
230    pub deriver: Option<StorePath<String>>,
231    pub nar_hash: String,
232    pub references: Vec<StorePath<String>>,
233    pub registration_time: u64,
234    pub nar_size: u64,
235    pub ultimate: bool,
236    pub signatures: Vec<Signature<String>>,
237    pub ca: Option<CAHash>,
238}
239
240/// Request tuple for [super::worker_protocol::Operation::QueryValidPaths]
241#[derive(NixDeserialize)]
242pub struct QueryValidPaths {
243    // Paths to query
244    pub paths: Vec<StorePath<String>>,
245
246    // Whether to try and substitute the paths.
247    #[nix(version = "27..")]
248    pub substitute: bool,
249}
250
251/// newtype wrapper for the byte array that correctly implements NixSerialize, NixDeserialize.
252#[derive(Debug)]
253pub struct NarHash([u8; 32]);
254
255impl std::ops::Deref for NarHash {
256    type Target = [u8; 32];
257
258    fn deref(&self) -> &Self::Target {
259        &self.0
260    }
261}
262
263impl NixDeserialize for NarHash {
264    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
265    where
266        R: ?Sized + NixRead + Send,
267    {
268        if let Some(bytes) = reader.try_read_bytes().await? {
269            let result = data_encoding::HEXLOWER
270                .decode(bytes.as_ref())
271                .map_err(R::Error::invalid_data)?;
272            Ok(Some(NarHash(result.try_into().map_err(|_| {
273                R::Error::invalid_data("incorrect length")
274            })?)))
275        } else {
276            Ok(None)
277        }
278    }
279}
280
281/// Request type for [super::worker_protocol::Operation::AddToStoreNar]
282#[derive(NixDeserialize, Debug)]
283pub struct AddToStoreNarRequest {
284    // - path :: [StorePath][se-StorePath]
285    pub path: StorePath<String>,
286    // - deriver :: [OptStorePath][se-OptStorePath]
287    pub deriver: Option<StorePath<String>>,
288    // - narHash :: [NARHash][se-NARHash] - always sha256
289    pub nar_hash: NarHash,
290    // - references :: [Set][se-Set] of [StorePath][se-StorePath]
291    pub references: Vec<StorePath<String>>,
292    // - registrationTime :: [Time][se-Time]
293    pub registration_time: u64,
294    // - narSize :: [UInt64][se-UInt64]
295    pub nar_size: u64,
296    // - ultimate :: [Bool64][se-Bool64]
297    pub ultimate: bool,
298    // - signatures :: [Set][se-Set] of [Signature][se-Signature]
299    pub signatures: Vec<Signature<String>>,
300    // - ca :: [OptContentAddress][se-OptContentAddress]
301    pub ca: Option<CAHash>,
302    // - repair :: [Bool64][se-Bool64]
303    pub repair: bool,
304    // - dontCheckSigs :: [Bool64][se-Bool64]
305    pub dont_check_sigs: bool,
306}