Skip to main content

nix_compat/wire/de/
mod.rs

1use std::error::Error as StdError;
2use std::future::Future;
3use std::ops::RangeInclusive;
4use std::{fmt, io};
5
6use ::bytes::Bytes;
7
8use super::ProtocolVersion;
9
10mod bytes;
11mod collections;
12mod int;
13mod reader;
14
15pub use reader::{NixReader, NixReaderBuilder};
16
17/// Like serde the `Error` trait allows `NixRead` implementations to add
18/// custom error handling for `NixDeserialize`.
19pub trait Error: Sized + StdError {
20    /// A totally custom non-specific error.
21    fn custom<T: fmt::Display>(msg: T) -> Self;
22
23    /// Some kind of std::io::Error occurred.
24    fn io_error(err: std::io::Error) -> Self {
25        Self::custom(format_args!("There was an I/O error {err}"))
26    }
27
28    /// The data read from `NixRead` is invalid.
29    /// This could be that some bytes were supposed to be valid UFT-8 but weren't.
30    fn invalid_data<T: fmt::Display>(msg: T) -> Self {
31        Self::custom(msg)
32    }
33
34    /// Required data is missing. This is mostly like an EOF
35    fn missing_data<T: fmt::Display>(msg: T) -> Self {
36        Self::custom(msg)
37    }
38}
39
40impl Error for io::Error {
41    fn custom<T: fmt::Display>(msg: T) -> Self {
42        io::Error::other(msg.to_string())
43    }
44
45    fn io_error(err: std::io::Error) -> Self {
46        err
47    }
48
49    fn invalid_data<T: fmt::Display>(msg: T) -> Self {
50        io::Error::new(io::ErrorKind::InvalidData, msg.to_string())
51    }
52
53    fn missing_data<T: fmt::Display>(msg: T) -> Self {
54        io::Error::new(io::ErrorKind::UnexpectedEof, msg.to_string())
55    }
56}
57
58/// A reader of data from the Nix daemon protocol.
59/// Basically there are two basic types in the Nix daemon protocol
60/// u64 and a bytes buffer. Everything else is more or less built on
61/// top of these two types.
62pub trait NixRead: Send {
63    type Error: Error + Send;
64
65    /// Some types are serialized differently depending on the version
66    /// of the protocol and so this can be used for implementing that.
67    fn version(&self) -> ProtocolVersion;
68
69    /// Read a single u64 from the protocol.
70    /// This returns an Option to support graceful shutdown.
71    fn try_read_number(
72        &mut self,
73    ) -> impl Future<Output = Result<Option<u64>, Self::Error>> + Send + '_;
74
75    /// Read bytes from the protocol.
76    /// A size limit on the returned bytes has to be specified.
77    /// This returns an Option to support graceful shutdown.
78    fn try_read_bytes_limited(
79        &mut self,
80        limit: RangeInclusive<usize>,
81    ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send + '_;
82
83    /// Read bytes from the protocol without a limit.
84    /// The default implementation just calls `try_read_bytes_limited` with a
85    /// limit of `0..=usize::MAX` but other implementations are free to have a
86    /// reader wide limit.
87    /// This returns an Option to support graceful shutdown.
88    fn try_read_bytes(
89        &mut self,
90    ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send + '_ {
91        self.try_read_bytes_limited(0..=usize::MAX)
92    }
93
94    /// Read a single u64 from the protocol.
95    /// This will return an error if the number could not be read.
96    fn read_number(&mut self) -> impl Future<Output = Result<u64, Self::Error>> + Send + '_ {
97        async move {
98            match self.try_read_number().await? {
99                Some(v) => Ok(v),
100                None => Err(Self::Error::missing_data("unexpected end-of-file")),
101            }
102        }
103    }
104
105    /// Read bytes from the protocol.
106    /// A size limit on the returned bytes has to be specified.
107    /// This will return an error if the number could not be read.
108    fn read_bytes_limited(
109        &mut self,
110        limit: RangeInclusive<usize>,
111    ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send + '_ {
112        async move {
113            match self.try_read_bytes_limited(limit).await? {
114                Some(v) => Ok(v),
115                None => Err(Self::Error::missing_data("unexpected end-of-file")),
116            }
117        }
118    }
119
120    /// Read bytes from the protocol.
121    /// The default implementation just calls `read_bytes_limited` with a
122    /// limit of `0..=usize::MAX` but other implementations are free to have a
123    /// reader wide limit.
124    /// This will return an error if the bytes could not be read.
125    fn read_bytes(&mut self) -> impl Future<Output = Result<Bytes, Self::Error>> + Send + '_ {
126        self.read_bytes_limited(0..=usize::MAX)
127    }
128
129    /// Read a value from the protocol.
130    /// Uses `NixDeserialize::deserialize` to read a value.
131    fn read_value<V: NixDeserialize>(
132        &mut self,
133    ) -> impl Future<Output = Result<V, Self::Error>> + Send + '_ {
134        V::deserialize(self)
135    }
136
137    /// Read a value from the protocol.
138    /// Uses `NixDeserialize::try_deserialize` to read a value.
139    /// This returns an Option to support graceful shutdown.
140    fn try_read_value<V: NixDeserialize>(
141        &mut self,
142    ) -> impl Future<Output = Result<Option<V>, Self::Error>> + Send + '_ {
143        V::try_deserialize(self)
144    }
145}
146
147impl<T: ?Sized + NixRead> NixRead for &mut T {
148    type Error = T::Error;
149
150    fn version(&self) -> ProtocolVersion {
151        (**self).version()
152    }
153
154    fn try_read_number(
155        &mut self,
156    ) -> impl Future<Output = Result<Option<u64>, Self::Error>> + Send + '_ {
157        (**self).try_read_number()
158    }
159
160    fn try_read_bytes_limited(
161        &mut self,
162        limit: RangeInclusive<usize>,
163    ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send + '_ {
164        (**self).try_read_bytes_limited(limit)
165    }
166
167    fn try_read_bytes(
168        &mut self,
169    ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send + '_ {
170        (**self).try_read_bytes()
171    }
172
173    fn read_number(&mut self) -> impl Future<Output = Result<u64, Self::Error>> + Send + '_ {
174        (**self).read_number()
175    }
176
177    fn read_bytes_limited(
178        &mut self,
179        limit: RangeInclusive<usize>,
180    ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send + '_ {
181        (**self).read_bytes_limited(limit)
182    }
183
184    fn read_bytes(&mut self) -> impl Future<Output = Result<Bytes, Self::Error>> + Send + '_ {
185        (**self).read_bytes()
186    }
187
188    fn try_read_value<V: NixDeserialize>(
189        &mut self,
190    ) -> impl Future<Output = Result<Option<V>, Self::Error>> + Send + '_ {
191        (**self).try_read_value()
192    }
193
194    fn read_value<V: NixDeserialize>(
195        &mut self,
196    ) -> impl Future<Output = Result<V, Self::Error>> + Send + '_ {
197        (**self).read_value()
198    }
199}
200
201/// A data structure that can be deserialized from the Nix daemon
202/// worker protocol.
203pub trait NixDeserialize: Sized {
204    /// Read a value from the reader.
205    /// This returns an Option to support gracefull shutdown.
206    fn try_deserialize<R>(
207        reader: &mut R,
208    ) -> impl Future<Output = Result<Option<Self>, R::Error>> + Send + '_
209    where
210        R: ?Sized + NixRead + Send;
211
212    fn deserialize<R>(reader: &mut R) -> impl Future<Output = Result<Self, R::Error>> + Send + '_
213    where
214        R: ?Sized + NixRead + Send,
215    {
216        async move {
217            match Self::try_deserialize(reader).await? {
218                Some(v) => Ok(v),
219                None => Err(R::Error::missing_data("unexpected end-of-file")),
220            }
221        }
222    }
223}