use crate::{com, raw, Error, Result};
#[derive(Clone, Copy, Default, Eq, PartialEq)]
pub struct ComponentFlags(u32);
impl ComponentFlags {
pub const NONE: Self = Self(wslc_sys::WSLC_COMPONENT_FLAG_NONE);
pub const VIRTUAL_MACHINE_PLATFORM: Self =
Self(wslc_sys::WSLC_COMPONENT_FLAG_VIRTUAL_MACHINE_PLATFORM);
pub const WSL_PACKAGE: Self = Self(wslc_sys::WSLC_COMPONENT_FLAG_WSL_PACKAGE);
pub const SDK_NEEDS_UPDATE: Self = Self(wslc_sys::WSLC_COMPONENT_FLAG_SDK_NEEDS_UPDATE);
pub const fn from_bits_retain(bits: u32) -> Self {
Self(bits)
}
pub const fn bits(self) -> u32 {
self.0
}
pub const fn is_empty(self) -> bool {
self.0 == 0
}
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
}
impl std::fmt::Debug for ComponentFlags {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut parts = Vec::new();
if self.contains(Self::VIRTUAL_MACHINE_PLATFORM) {
parts.push("VIRTUAL_MACHINE_PLATFORM");
}
if self.contains(Self::WSL_PACKAGE) {
parts.push("WSL_PACKAGE");
}
if self.contains(Self::SDK_NEEDS_UPDATE) {
parts.push("SDK_NEEDS_UPDATE");
}
if parts.is_empty() {
parts.push("NONE");
}
write!(f, "ComponentFlags({})", parts.join(" | "))
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Version {
pub major: u32,
pub minor: u32,
pub revision: u32,
}
impl From<wslc_sys::WslcVersion> for Version {
fn from(value: wslc_sys::WslcVersion) -> Self {
Self {
major: value.major,
minor: value.minor,
revision: value.revision,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct InstallProgress {
pub component: ComponentFlags,
pub progress_steps: u32,
pub total_steps: u32,
}
pub struct Service;
impl Service {
pub fn missing_components() -> Result<ComponentFlags> {
let _com = com::try_initialize_mta()?;
let sdk = raw::sdk()?;
let mut flags = 0;
let hr = unsafe { (sdk.WslcGetMissingComponents)(&mut flags) };
unsafe { raw::check_hr(hr, std::ptr::null_mut()) }?;
Ok(ComponentFlags::from_bits_retain(flags))
}
pub fn version() -> Result<Version> {
let _com = com::try_initialize_mta()?;
let sdk = raw::sdk()?;
let mut version = wslc_sys::WslcVersion::default();
let hr = unsafe { (sdk.WslcGetVersion)(&mut version) };
unsafe { raw::check_hr(hr, std::ptr::null_mut()) }?;
Ok(version.into())
}
pub fn ensure_available() -> Result<()> {
let missing = Self::missing_components()?;
if !missing.is_empty() {
return Err(Error::MissingComponents(missing));
}
Self::version()?;
Ok(())
}
pub fn install_with_dependencies<F>(progress: F) -> Result<()>
where
F: FnMut(InstallProgress) + Send + 'static,
{
let _com = com::try_initialize_mta()?;
let sdk = raw::sdk()?;
let mut callback = Box::new(progress);
let context = (&mut *callback) as *mut F as wslc_sys::PVOID;
let hr =
unsafe { (sdk.WslcInstallWithDependencies)(Some(install_trampoline::<F>), context) };
unsafe { raw::check_hr(hr, std::ptr::null_mut()) }
}
}
unsafe extern "system" fn install_trampoline<F>(
component: wslc_sys::WslcComponentFlags,
progress_steps: u32,
total_steps: u32,
context: wslc_sys::PVOID,
) where
F: FnMut(InstallProgress),
{
if context.is_null() {
return;
}
let callback = unsafe { &mut *(context as *mut F) };
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
callback(InstallProgress {
component: ComponentFlags::from_bits_retain(component),
progress_steps,
total_steps,
});
}));
}