Skip to main content

nix_compat/nix_daemon/
types.rs

1use std::collections::BTreeMap;
2use std::time::Duration;
3
4use crate::derived_path::DerivedPath;
5use crate::nixbase32;
6use crate::realisation::{DrvOutput, Realisation};
7use crate::wire::de::Error;
8use crate::{
9    narinfo::Signature,
10    nixhash::CAHash,
11    store_path::StorePath,
12    wire::{
13        de::{NixDeserialize, NixRead},
14        ser::{NixSerialize, NixWrite},
15    },
16};
17use bytes::Bytes;
18use nix_compat_derive::{NixDeserialize, NixSerialize};
19
20/// Marker type that consumes/sends and ignores a u64.
21#[derive(Clone, Debug, NixDeserialize, NixSerialize)]
22#[nix(from = "u64", into = "u64")]
23pub struct IgnoredZero;
24impl From<u64> for IgnoredZero {
25    fn from(_: u64) -> Self {
26        IgnoredZero
27    }
28}
29
30impl From<IgnoredZero> for u64 {
31    fn from(_: IgnoredZero) -> Self {
32        0
33    }
34}
35
36#[derive(
37    Debug,
38    Clone,
39    Copy,
40    PartialEq,
41    Eq,
42    PartialOrd,
43    Ord,
44    Hash,
45    num_enum::TryFromPrimitive,
46    num_enum::IntoPrimitive,
47    NixDeserialize,
48    NixSerialize,
49)]
50#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
51#[nix(try_from = "u16", into = "u16")]
52#[repr(u16)]
53pub enum BuildMode {
54    Normal = 0,
55    Repair = 1,
56    Check = 2,
57}
58
59#[derive(
60    Debug,
61    Clone,
62    Copy,
63    PartialEq,
64    Eq,
65    PartialOrd,
66    Ord,
67    Hash,
68    num_enum::TryFromPrimitive,
69    num_enum::IntoPrimitive,
70    NixDeserialize,
71    NixSerialize,
72)]
73#[nix(try_from = "u16", into = "u16")]
74#[repr(u16)]
75pub enum BuildStatus {
76    Built = 0,
77    Substituted = 1,
78    AlreadyValid = 2,
79    PermanentFailure = 3,
80    InputRejected = 4,
81    OutputRejected = 5,
82    TransientFailure = 6,
83    CachedFailure = 7,
84    TimedOut = 8,
85    MiscFailure = 9,
86    DependencyFailed = 10,
87    LogLimitExceeded = 11,
88    NotDeterministic = 12,
89    ResolvesToAlreadyValid = 13,
90    NoSubstituters = 14,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, NixDeserialize, NixSerialize)]
94#[repr(transparent)]
95pub struct Microseconds(i64);
96
97impl From<i64> for Microseconds {
98    fn from(value: i64) -> Self {
99        Microseconds(value)
100    }
101}
102
103impl From<Microseconds> for Duration {
104    fn from(value: Microseconds) -> Self {
105        Duration::from_micros(value.0.unsigned_abs())
106    }
107}
108
109impl TryFrom<Duration> for Microseconds {
110    type Error = std::num::TryFromIntError;
111    fn try_from(value: Duration) -> Result<Self, Self::Error> {
112        Ok(Microseconds(value.as_micros().try_into()?))
113    }
114}
115
116impl From<Microseconds> for i64 {
117    fn from(value: Microseconds) -> Self {
118        value.0
119    }
120}
121
122impl NixDeserialize for Option<Microseconds> {
123    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
124    where
125        R: ?Sized + NixRead + Send,
126    {
127        if let Some(tag) = reader.try_read_value::<u8>().await? {
128            match tag {
129                0 => Ok(Some(None)),
130                1 => Ok(Some(Some(reader.read_value::<Microseconds>().await?))),
131                _ => Err(R::Error::invalid_data("invalid optional tag from remote")),
132            }
133        } else {
134            Ok(None)
135        }
136    }
137}
138
139impl NixSerialize for Option<Microseconds> {
140    async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
141    where
142        W: NixWrite,
143    {
144        if let Some(value) = self.as_ref() {
145            writer.write_number(1).await?;
146            writer.write_value(value).await
147        } else {
148            writer.write_number(0).await
149        }
150    }
151}
152
153#[derive(Debug, NixSerialize)]
154pub struct TraceLine {
155    have_pos: IgnoredZero,
156    hint: String,
157}
158
159/// Represents an error returned by the nix-daemon to its client.
160///
161/// Adheres to the format described in serialization.md
162#[derive(NixSerialize)]
163pub struct NixError {
164    #[nix(version = "26..")]
165    type_: &'static str,
166
167    #[nix(version = "26..")]
168    level: u64,
169
170    #[nix(version = "26..")]
171    name: &'static str,
172
173    msg: String,
174    #[nix(version = "26..")]
175    have_pos: IgnoredZero,
176
177    #[nix(version = "26..")]
178    traces: Vec<TraceLine>,
179
180    #[nix(version = "..=25")]
181    exit_status: u64,
182}
183
184impl NixError {
185    pub fn new(msg: String) -> Self {
186        Self {
187            type_: "Error",
188            level: 0, // error
189            name: "Error",
190            msg,
191            have_pos: IgnoredZero {},
192            traces: vec![],
193            exit_status: 1,
194        }
195    }
196}
197
198impl NixSerialize for Option<UnkeyedValidPathInfo> {
199    async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
200    where
201        W: NixWrite,
202    {
203        match self {
204            Some(value) => {
205                writer.write_value(&true).await?;
206                writer.write_value(value).await
207            }
208            None => writer.write_value(&false).await,
209        }
210    }
211}
212
213#[derive(NixSerialize, NixDeserialize, Debug, Clone, PartialEq)]
214pub struct UnkeyedValidPathInfo {
215    pub deriver: Option<StorePath>,
216    pub nar_hash: NarHash,
217    pub references: Vec<StorePath>,
218    pub registration_time: u64,
219    pub nar_size: u64,
220    pub ultimate: bool,
221    pub signatures: Vec<Signature<String>>,
222    pub ca: Option<CAHash>,
223}
224
225/// Request tuple for [super::worker_protocol::Operation::QueryValidPaths]
226#[derive(NixDeserialize)]
227pub struct QueryValidPaths {
228    // Paths to query
229    pub paths: Vec<StorePath>,
230
231    // Whether to try and substitute the paths.
232    #[nix(version = "27..")]
233    pub substitute: bool,
234}
235
236/// Request tuple for [super::worker_protocol::Operation::BuildPaths]
237#[derive(NixDeserialize)]
238pub struct BuildPaths {
239    // Paths to build
240    pub paths: Vec<DerivedPath>,
241
242    // How to build the paths
243    pub mode: BuildMode,
244}
245
246/// newtype wrapper for the byte array that correctly implements NixSerialize, NixDeserialize.
247#[derive(Debug, Clone, Copy, PartialEq, Eq)]
248pub struct NarHash([u8; 32]);
249
250impl NarHash {
251    pub fn from_digest(digest: [u8; 32]) -> Self {
252        NarHash(digest)
253    }
254}
255
256impl std::ops::Deref for NarHash {
257    type Target = [u8; 32];
258
259    fn deref(&self) -> &Self::Target {
260        &self.0
261    }
262}
263
264impl NixDeserialize for NarHash {
265    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
266    where
267        R: ?Sized + NixRead + Send,
268    {
269        if let Some(bytes) = reader.try_read_bytes().await? {
270            let result = data_encoding::HEXLOWER
271                .decode(bytes.as_ref())
272                .map_err(R::Error::invalid_data)?;
273            Ok(Some(NarHash(result.try_into().map_err(|_| {
274                R::Error::invalid_data("incorrect length")
275            })?)))
276        } else {
277            Ok(None)
278        }
279    }
280}
281
282impl NixSerialize for NarHash {
283    async fn serialize<W>(&self, writer: &mut W) -> Result<(), W::Error>
284    where
285        W: NixWrite,
286    {
287        nixbase32::encode(&self.0).serialize(writer).await
288    }
289}
290
291/// Info type used by [super::worker_protocol::Operation::AddToStoreNar] and [super::worker_protocol::Operation::AddMultipleToStore]
292///
293/// See: [ValidPathInfo reference](https://snix.dev/docs/reference/nix-daemon-protocol/types/#validpathinfo)
294#[derive(NixDeserialize, Debug)]
295pub struct ValidPathInfo {
296    // - path :: [StorePath][se-StorePath]
297    pub path: StorePath,
298    pub info: UnkeyedValidPathInfo,
299}
300
301#[derive(Debug, Clone, PartialEq, Eq, NixDeserialize, NixSerialize)]
302pub struct BuildResult {
303    pub status: BuildStatus,
304    pub error_msg: Bytes,
305    #[nix(version = "29..")]
306    pub times_built: u32,
307    #[nix(version = "29..")]
308    pub is_non_deterministic: bool,
309    #[nix(version = "29..")]
310    pub start_time: u64,
311    #[nix(version = "29..")]
312    pub stop_time: u64,
313    #[nix(version = "37..")]
314    pub cpu_user: Option<Microseconds>,
315    #[nix(version = "37..")]
316    pub cpu_system: Option<Microseconds>,
317    #[nix(version = "28..")]
318    pub built_outputs: BTreeMap<DrvOutput, Realisation>,
319}
320
321pub type KeyedBuildResults = Vec<KeyedBuildResult>;
322#[derive(Debug, Clone, PartialEq, Eq, NixDeserialize, NixSerialize)]
323pub struct KeyedBuildResult {
324    pub path: DerivedPath,
325    pub result: BuildResult,
326}
327
328#[derive(Debug, Clone, PartialEq, Eq, Hash, NixDeserialize, NixSerialize)]
329pub struct QueryMissingResult {
330    pub will_build: Vec<StorePath>,
331    pub will_substitute: Vec<StorePath>,
332    pub unknown: Vec<StorePath>,
333    pub download_size: u64,
334    pub nar_size: u64,
335}