use std::error::Error as StdError; use std::future::Future; use std::ops::RangeInclusive; use std::{fmt, io}; use ::bytes::Bytes; use super::ProtocolVersion; mod bytes; mod collections; mod int; #[cfg(any(test, feature = "test"))] pub mod mock; mod reader; pub use reader::{NixReader, NixReaderBuilder}; /// Like serde the `Error` trait allows `NixRead` implementations to add /// custom error handling for `NixDeserialize`. pub trait Error: Sized + StdError { /// A totally custom non-specific error. fn custom<T: fmt::Display>(msg: T) -> Self; /// Some kind of std::io::Error occured. fn io_error(err: std::io::Error) -> Self { Self::custom(format_args!("There was an I/O error {}", err)) } /// The data read from `NixRead` is invalid. /// This could be that some bytes were supposed to be valid UFT-8 but weren't. fn invalid_data<T: fmt::Display>(msg: T) -> Self { Self::custom(msg) } /// Required data is missing. This is mostly like an EOF fn missing_data<T: fmt::Display>(msg: T) -> Self { Self::custom(msg) } } impl Error for io::Error { fn custom<T: fmt::Display>(msg: T) -> Self { io::Error::new(io::ErrorKind::Other, msg.to_string()) } fn io_error(err: std::io::Error) -> Self { err } fn invalid_data<T: fmt::Display>(msg: T) -> Self { io::Error::new(io::ErrorKind::InvalidData, msg.to_string()) } fn missing_data<T: fmt::Display>(msg: T) -> Self { io::Error::new(io::ErrorKind::UnexpectedEof, msg.to_string()) } } /// A reader of data from the Nix daemon protocol. /// Basically there are two basic types in the Nix daemon protocol /// u64 and a bytes buffer. Everything else is more or less built on /// top of these two types. pub trait NixRead: Send { type Error: Error + Send; /// Some types are serialized differently depending on the version /// of the protocol and so this can be used for implementing that. fn version(&self) -> ProtocolVersion; /// Read a single u64 from the protocol. /// This returns an Option to support graceful shutdown. fn try_read_number( &mut self, ) -> impl Future<Output = Result<Option<u64>, Self::Error>> + Send + '_; /// Read bytes from the protocol. /// A size limit on the returned bytes has to be specified. /// This returns an Option to support graceful shutdown. fn try_read_bytes_limited( &mut self, limit: RangeInclusive<usize>, ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send + '_; /// Read bytes from the protocol without a limit. /// The default implementation just calls `try_read_bytes_limited` with a /// limit of `0..=usize::MAX` but other implementations are free to have a /// reader wide limit. /// This returns an Option to support graceful shutdown. fn try_read_bytes( &mut self, ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send + '_ { self.try_read_bytes_limited(0..=usize::MAX) } /// Read a single u64 from the protocol. /// This will return an error if the number could not be read. fn read_number(&mut self) -> impl Future<Output = Result<u64, Self::Error>> + Send + '_ { async move { match self.try_read_number().await? { Some(v) => Ok(v), None => Err(Self::Error::missing_data("unexpected end-of-file")), } } } /// Read bytes from the protocol. /// A size limit on the returned bytes has to be specified. /// This will return an error if the number could not be read. fn read_bytes_limited( &mut self, limit: RangeInclusive<usize>, ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send + '_ { async move { match self.try_read_bytes_limited(limit).await? { Some(v) => Ok(v), None => Err(Self::Error::missing_data("unexpected end-of-file")), } } } /// Read bytes from the protocol. /// The default implementation just calls `read_bytes_limited` with a /// limit of `0..=usize::MAX` but other implementations are free to have a /// reader wide limit. /// This will return an error if the bytes could not be read. fn read_bytes(&mut self) -> impl Future<Output = Result<Bytes, Self::Error>> + Send + '_ { self.read_bytes_limited(0..=usize::MAX) } /// Read a value from the protocol. /// Uses `NixDeserialize::deserialize` to read a value. fn read_value<V: NixDeserialize>( &mut self, ) -> impl Future<Output = Result<V, Self::Error>> + Send + '_ { V::deserialize(self) } /// Read a value from the protocol. /// Uses `NixDeserialize::try_deserialize` to read a value. /// This returns an Option to support graceful shutdown. fn try_read_value<V: NixDeserialize>( &mut self, ) -> impl Future<Output = Result<Option<V>, Self::Error>> + Send + '_ { V::try_deserialize(self) } } impl<T: ?Sized + NixRead> NixRead for &mut T { type Error = T::Error; fn version(&self) -> ProtocolVersion { (**self).version() } fn try_read_number( &mut self, ) -> impl Future<Output = Result<Option<u64>, Self::Error>> + Send + '_ { (**self).try_read_number() } fn try_read_bytes_limited( &mut self, limit: RangeInclusive<usize>, ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send + '_ { (**self).try_read_bytes_limited(limit) } fn try_read_bytes( &mut self, ) -> impl Future<Output = Result<Option<Bytes>, Self::Error>> + Send + '_ { (**self).try_read_bytes() } fn read_number(&mut self) -> impl Future<Output = Result<u64, Self::Error>> + Send + '_ { (**self).read_number() } fn read_bytes_limited( &mut self, limit: RangeInclusive<usize>, ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send + '_ { (**self).read_bytes_limited(limit) } fn read_bytes(&mut self) -> impl Future<Output = Result<Bytes, Self::Error>> + Send + '_ { (**self).read_bytes() } fn try_read_value<V: NixDeserialize>( &mut self, ) -> impl Future<Output = Result<Option<V>, Self::Error>> + Send + '_ { (**self).try_read_value() } fn read_value<V: NixDeserialize>( &mut self, ) -> impl Future<Output = Result<V, Self::Error>> + Send + '_ { (**self).read_value() } } /// A data structure that can be deserialized from the Nix daemon /// worker protocol. pub trait NixDeserialize: Sized { /// Read a value from the reader. /// This returns an Option to support gracefull shutdown. fn try_deserialize<R>( reader: &mut R, ) -> impl Future<Output = Result<Option<Self>, R::Error>> + Send + '_ where R: ?Sized + NixRead + Send; fn deserialize<R>(reader: &mut R) -> impl Future<Output = Result<Self, R::Error>> + Send + '_ where R: ?Sized + NixRead + Send, { async move { match Self::try_deserialize(reader).await? { Some(v) => Ok(v), None => Err(R::Error::missing_data("unexpected end-of-file")), } } } }