//! When serialising Nix goes wrong ...
use std::error;
use std::fmt::Display;
#[derive(Clone, Debug)]
pub enum Error {
/// Attempted to deserialise an unsupported Nix value (such as a
/// function) that can not be represented by the
/// [`serde::Deserialize`] trait.
Unserializable { value_type: &'static str },
/// Expected to deserialize a value that is unsupported by Nix.
Unsupported { wanted: &'static str },
/// Expected a specific type, but got something else on the Nix side.
UnexpectedType {
expected: &'static str,
got: &'static str,
},
/// Deserialisation error returned from `serde::de`.
Deserialization(String),
/// Deserialized integer did not fit.
IntegerConversion { got: i64, need: &'static str },
/// Evaluation of the supplied Nix code failed while computing the
/// value for deserialisation.
NixErrors {
errors: Vec<tvix_eval::Error>,
source: tvix_eval::SourceCode,
},
/// Could not determine an externally tagged enum representation.
AmbiguousEnum,
/// Attempted to provide content to a unit enum.
UnitEnumContent,
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Unserializable { value_type } => write!(
f,
"can not deserialise a Nix '{}' into a Rust type",
value_type
),
Error::Unsupported { wanted } => {
write!(f, "can not deserialize a '{}' from a Nix value", wanted)
}
Error::UnexpectedType { expected, got } => {
write!(f, "expected type {}, but got Nix type {}", expected, got)
}
Error::NixErrors { errors, source } => {
writeln!(
f,
"{} occured during Nix evaluation: ",
if errors.len() == 1 { "error" } else { "errors" }
)?;
for err in errors {
writeln!(f, "{}", err.fancy_format_str(&source))?;
}
Ok(())
}
Error::Deserialization(err) => write!(f, "deserialisation error occured: {}", err),
Error::IntegerConversion { got, need } => {
write!(f, "i64({}) does not fit in a {}", got, need)
}
Error::AmbiguousEnum => write!(f, "could not determine enum variant: ambiguous keys"),
Error::UnitEnumContent => write!(f, "provided content for unit enum variant"),
}
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Self::NixErrors { errors, .. } => errors.first().map(|e| e as &dyn error::Error),
_ => None,
}
}
}
impl serde::de::Error for Error {
fn custom<T>(err: T) -> Self
where
T: Display,
{
Self::Deserialization(err.to_string())
}
}