use std::io;
use std::path::PathBuf;
use crate::source::SourceKind;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("no identity source produced a value (tried: {tried})")]
NoSource {
tried: String,
},
#[error("{source_kind}: {path} contains the `uninitialized` sentinel")]
Uninitialized {
source_kind: SourceKind,
path: PathBuf,
},
#[error("{source_kind}: I/O error reading {}: {source}", path.display())]
Io {
source_kind: SourceKind,
path: PathBuf,
#[source]
source: io::Error,
},
#[error("{source_kind}: malformed value: {reason}")]
Malformed {
source_kind: SourceKind,
reason: String,
},
#[error("{source_kind}: {reason}")]
Platform {
source_kind: SourceKind,
reason: String,
},
}
impl Error {
#[must_use]
pub fn source_kind(&self) -> Option<SourceKind> {
match self {
Self::NoSource { .. } => None,
Self::Uninitialized { source_kind, .. }
| Self::Io { source_kind, .. }
| Self::Malformed { source_kind, .. }
| Self::Platform { source_kind, .. } => Some(*source_kind),
}
}
#[must_use]
pub fn is_recoverable(&self) -> bool {
matches!(self, Self::NoSource { .. })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_recoverable_only_true_for_no_source() {
assert!(Error::NoSource { tried: "x".into() }.is_recoverable());
assert!(
!Error::Uninitialized {
source_kind: SourceKind::MachineId,
path: "/etc/machine-id".into(),
}
.is_recoverable()
);
assert!(
!Error::Platform {
source_kind: SourceKind::IoPlatformUuid,
reason: "ioreg failed".into(),
}
.is_recoverable()
);
assert!(
!Error::Malformed {
source_kind: SourceKind::Dmi,
reason: "not a uuid".into(),
}
.is_recoverable()
);
}
#[test]
fn source_kind_round_trips_through_error() {
let err = Error::Platform {
source_kind: SourceKind::AwsImds,
reason: "x".into(),
};
assert_eq!(err.source_kind(), Some(SourceKind::AwsImds));
assert_eq!(
Error::NoSource {
tried: "env-override".into()
}
.source_kind(),
None
);
}
}