use std::fmt;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
UnsupportedPlatform(&'static str),
SdkNotFound(String),
MissingComponents(crate::ComponentFlags),
ComInitialization { code: i32, message: String },
HResult { code: i32, message: String },
InvalidInput(String),
Nul(String),
Io(std::io::Error),
Utf8(std::string::FromUtf8Error),
}
impl Error {
pub fn from_hresult(code: i32, message: impl Into<String>) -> Self {
Self::HResult {
code,
message: message.into(),
}
}
pub fn hresult(&self) -> Option<i32> {
match self {
Self::ComInitialization { code, .. } | Self::HResult { code, .. } => Some(*code),
_ => None,
}
}
pub fn wslc_kind(&self) -> Option<WslcErrorKind> {
let code = self.hresult()?;
Some(match code as u32 {
wslc_sys::WSLC_E_IMAGE_NOT_FOUND => WslcErrorKind::ImageNotFound,
wslc_sys::WSLC_E_CONTAINER_PREFIX_AMBIGUOUS => WslcErrorKind::ContainerPrefixAmbiguous,
wslc_sys::WSLC_E_CONTAINER_NOT_FOUND => WslcErrorKind::ContainerNotFound,
wslc_sys::WSLC_E_VOLUME_NOT_FOUND => WslcErrorKind::VolumeNotFound,
wslc_sys::WSLC_E_CONTAINER_NOT_RUNNING => WslcErrorKind::ContainerNotRunning,
wslc_sys::WSLC_E_CONTAINER_IS_RUNNING => WslcErrorKind::ContainerIsRunning,
wslc_sys::WSLC_E_SESSION_RESERVED => WslcErrorKind::SessionReserved,
wslc_sys::WSLC_E_INVALID_SESSION_NAME => WslcErrorKind::InvalidSessionName,
wslc_sys::WSLC_E_NETWORK_NOT_FOUND => WslcErrorKind::NetworkNotFound,
wslc_sys::WSLC_E_WU_SEARCH_FAILED => WslcErrorKind::WindowsUpdateSearchFailed,
wslc_sys::WSLC_E_SDK_UPDATE_NEEDED => WslcErrorKind::SdkUpdateNeeded,
wslc_sys::WSLC_E_CONTAINER_DISABLED => WslcErrorKind::ContainerDisabled,
wslc_sys::WSLC_E_REGISTRY_BLOCKED_BY_POLICY => WslcErrorKind::RegistryBlockedByPolicy,
wslc_sys::WSLC_E_VOLUME_NOT_AVAILABLE => WslcErrorKind::VolumeNotAvailable,
wslc_sys::WSLC_E_SESSION_NOT_FOUND => WslcErrorKind::SessionNotFound,
other if (other & 0xffff_0000) == 0x8004_0000 => WslcErrorKind::Unknown(code),
_ => return None,
})
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnsupportedPlatform(platform) => write!(f, "unsupported platform: {platform}"),
Self::SdkNotFound(message) => write!(f, "WSLC SDK not found: {message}"),
Self::MissingComponents(flags) => write!(f, "missing WSL components: {flags:?}"),
Self::ComInitialization { code, message } => {
write!(
f,
"COM initialization failed: HRESULT=0x{:08x}, {message}",
*code as u32
)
}
Self::HResult { code, message } => {
write!(
f,
"WSLC call failed: HRESULT=0x{:08x}, {message}",
*code as u32
)
}
Self::InvalidInput(message) => write!(f, "invalid input: {message}"),
Self::Nul(field) => write!(f, "string contains interior NUL: {field}"),
Self::Io(error) => write!(f, "I/O error: {error}"),
Self::Utf8(error) => write!(f, "UTF-8 conversion error: {error}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(error) => Some(error),
Self::Utf8(error) => Some(error),
_ => None,
}
}
}
impl From<std::io::Error> for Error {
fn from(value: std::io::Error) -> Self {
Self::Io(value)
}
}
impl From<std::string::FromUtf8Error> for Error {
fn from(value: std::string::FromUtf8Error) -> Self {
Self::Utf8(value)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum WslcErrorKind {
ImageNotFound,
ContainerPrefixAmbiguous,
ContainerNotFound,
VolumeNotFound,
ContainerNotRunning,
ContainerIsRunning,
SessionReserved,
InvalidSessionName,
NetworkNotFound,
WindowsUpdateSearchFailed,
SdkUpdateNeeded,
ContainerDisabled,
RegistryBlockedByPolicy,
VolumeNotAvailable,
SessionNotFound,
Unknown(i32),
}