use thiserror::Error;
pub type Result<T, E = Error> = core::result::Result<T, E>;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Error {
#[error("hypervisor backend error: {message}")]
Backend {
message: String,
#[source]
source: Option<Box<dyn core::error::Error + Send + Sync + 'static>>,
},
#[error("guest memory operation out of range: {0}")]
MemoryOutOfRange(String),
#[error("invalid memory protection change: {0}")]
InvalidProtection(String),
#[error("backend does not support capability: {0}")]
Unsupported(&'static str),
#[error("invalid vCPU state transition: {0}")]
InvalidVcpuState(&'static str),
#[error("invalid argument: {0}")]
InvalidArgument(String),
}
impl Error {
pub fn backend(message: impl Into<String>) -> Self {
Self::Backend {
message: message.into(),
source: None,
}
}
pub fn backend_source<E>(message: impl Into<String>, source: E) -> Self
where
E: core::error::Error + Send + Sync + 'static,
{
Self::Backend {
message: message.into(),
source: Some(Box::new(source)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn backend_error_carries_message() {
let err = Error::backend("failed to map");
assert_eq!(err.to_string(), "hypervisor backend error: failed to map");
}
#[test]
fn backend_error_chains_source() {
let inner = Error::MemoryOutOfRange("0x1000".into());
let outer = Error::backend_source("wrap", inner);
let chained = core::error::Error::source(&outer)
.map(ToString::to_string)
.unwrap_or_default();
assert!(chained.contains("0x1000"));
}
}