1use thiserror::Error;
4
5pub type Result<T, E = Error> = core::result::Result<T, E>;
7
8#[derive(Debug, Error)]
14#[non_exhaustive]
15pub enum Error {
16 #[error("hypervisor backend error: {message}")]
18 Backend {
19 message: String,
21 #[source]
23 source: Option<Box<dyn core::error::Error + Send + Sync + 'static>>,
24 },
25
26 #[error("guest memory operation out of range: {0}")]
28 MemoryOutOfRange(String),
29
30 #[error("invalid memory protection change: {0}")]
32 InvalidProtection(String),
33
34 #[error("backend does not support capability: {0}")]
36 Unsupported(&'static str),
37
38 #[error("invalid vCPU state transition: {0}")]
40 InvalidVcpuState(&'static str),
41
42 #[error("invalid argument: {0}")]
44 InvalidArgument(String),
45}
46
47impl Error {
48 pub fn backend(message: impl Into<String>) -> Self {
50 Self::Backend {
51 message: message.into(),
52 source: None,
53 }
54 }
55
56 pub fn backend_source<E>(message: impl Into<String>, source: E) -> Self
58 where
59 E: core::error::Error + Send + Sync + 'static,
60 {
61 Self::Backend {
62 message: message.into(),
63 source: Some(Box::new(source)),
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn backend_error_carries_message() {
74 let err = Error::backend("failed to map");
75 assert_eq!(err.to_string(), "hypervisor backend error: failed to map");
76 }
77
78 #[test]
79 fn backend_error_chains_source() {
80 let inner = Error::MemoryOutOfRange("0x1000".into());
81 let outer = Error::backend_source("wrap", inner);
82 let chained = core::error::Error::source(&outer)
83 .map(ToString::to_string)
84 .unwrap_or_default();
85 assert!(chained.contains("0x1000"));
86 }
87}