diff --git a/Cargo.lock b/Cargo.lock index c2f7643..12cce84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -855,6 +855,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "wslpluginapi-sys" +version = "0.1.0-alpha.0+2.1.3" +source = "git+https://github.com/mveril/wslpluginapi-sys.git?branch=main#19cb304cb9c76df2fb27a3d601a6872c3bb4f414" +dependencies = [ + "bindgen", + "libc", + "semver", + "struct-field-names-as-array", + "windows", +] + [[package]] name = "wslplugins-macro" version = "0.1.0-alpha.0" @@ -875,7 +887,7 @@ dependencies = [ "struct-field-names-as-array", "strum", "syn", - "wslplugins-sys", + "wslpluginapi-sys", ] [[package]] @@ -884,8 +896,8 @@ version = "0.1.0-alpha.0" dependencies = [ "trybuild", "windows", + "wslpluginapi-sys", "wslplugins-rs", - "wslplugins-sys", ] [[package]] @@ -902,17 +914,6 @@ dependencies = [ "typed-path", "widestring", "windows", + "wslpluginapi-sys", "wslplugins-macro", - "wslplugins-sys", -] - -[[package]] -name = "wslplugins-sys" -version = "0.1.0-alpha.0+2.1.3" -dependencies = [ - "bindgen", - "libc", - "semver", - "struct-field-names-as-array", - "windows", ] diff --git a/Cargo.toml b/Cargo.toml index 9a6f4f1..f59f20c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,17 @@ [workspace] resolver = "2" members = [ - "wslplugins-sys", "plugin", "wslplugins-rs", "wslplugins-macro", "wslplugins-macro-core", "wslplugins-macro-tests", ] + +[workspace.package] +authors = ["Mickaël Véril "] +version = "0.1.0-alpha.0" +edition = "2021" +license = "MIT" +repository = "https://github.com/mveril/wslplugins-rs" +description = "A Rust framework for developing WSL plugins using safe and idiomatic Rust." diff --git a/plugin/Cargo.toml b/plugin/Cargo.toml index bfa9fde..0b5505b 100644 --- a/plugin/Cargo.toml +++ b/plugin/Cargo.toml @@ -1,7 +1,9 @@ [package] name = "plugin" -version = "0.1.0-alpha.0" -authors = ["Mickaël Véril "] +authors.workspace = true +version.workspace = true +license.workspace = true +repository.workspace = true edition = "2021" [lib] diff --git a/wslplugins-macro-core/Cargo.toml b/wslplugins-macro-core/Cargo.toml index 7b52295..604179b 100644 --- a/wslplugins-macro-core/Cargo.toml +++ b/wslplugins-macro-core/Cargo.toml @@ -1,7 +1,9 @@ [package] name = "wslplugins-macro-core" -version = "0.1.0-alpha.0" -authors = ["Mickaël Véril "] +authors.workspace = true +version.workspace = true +license.workspace = true +repository.workspace = true edition = "2021" [dependencies] @@ -12,7 +14,7 @@ heck = "0.5" strum = { version = "0.26.3", features = ["derive"] } [build-dependencies] -wslplugins-sys = { path = "../wslplugins-sys", features = [ +wslpluginapi-sys = { git = "https://github.com/mveril/wslpluginapi-sys.git", branch = "main", features = [ "hooks-field-names", ] } quote = "*" diff --git a/wslplugins-macro-core/build.rs b/wslplugins-macro-core/build.rs index d2e8e3b..9c87531 100644 --- a/wslplugins-macro-core/build.rs +++ b/wslplugins-macro-core/build.rs @@ -1,6 +1,6 @@ use std::{env, fs::File, io::Write, path::PathBuf}; use struct_field_names_as_array::FieldNamesAsSlice; -use wslplugins_sys::WSLPluginHooksV1; +use wslpluginapi_sys::WSLPluginHooksV1; fn main() -> Result<(), Box> { let items: &'static [&'static str] = WSLPluginHooksV1::FIELD_NAMES_AS_SLICE; diff --git a/wslplugins-macro-tests/Cargo.toml b/wslplugins-macro-tests/Cargo.toml index 459b207..2430b84 100644 --- a/wslplugins-macro-tests/Cargo.toml +++ b/wslplugins-macro-tests/Cargo.toml @@ -1,12 +1,15 @@ [package] name = "wslplugins-macro-tests" -version = "0.1.0-alpha.0" -authors = ["Mickaël Véril "] +authors.workspace = true +version.workspace = true +license.workspace = true +repository.workspace = true +description = "A Rust framework for developing WSL plugins using safe and idiomatic Rust." edition = "2021" [dependencies] wslplugins-rs = { path = "../wslplugins-rs", features = ["macro"] } -wslplugins-sys = { path = "../wslplugins-sys" } +wslpluginapi-sys = { git = "https://github.com/mveril/wslpluginapi-sys.git", branch = "main" } [dependencies.windows] version = "0.58" features = ["Win32_Foundation"] diff --git a/wslplugins-macro/Cargo.toml b/wslplugins-macro/Cargo.toml index 1d89c5b..41f472d 100644 --- a/wslplugins-macro/Cargo.toml +++ b/wslplugins-macro/Cargo.toml @@ -1,8 +1,11 @@ [package] name = "wslplugins-macro" -version = "0.1.0-alpha.0" -authors = ["Mickaël Véril "] +authors.workspace = true +version.workspace = true +license.workspace = true +repository.workspace = true edition = "2021" + [lib] proc-macro = true diff --git a/wslplugins-rs/Cargo.toml b/wslplugins-rs/Cargo.toml index f81d165..708bc18 100644 --- a/wslplugins-rs/Cargo.toml +++ b/wslplugins-rs/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "wslplugins-rs" -version = "0.1.0-alpha.0" -authors = ["Mickaël Véril "] +authors.workspace = true +version.workspace = true +license.workspace = true +repository.workspace = true +description.workspace = true edition = "2021" [dependencies.windows] @@ -18,7 +21,7 @@ thiserror = "2.0.7" typed-path = ">0.1" widestring = { version = "1", features = ["alloc"] } wslplugins-macro = { path = "../wslplugins-macro", optional = true } -wslplugins-sys = { path = "../wslplugins-sys" } +wslpluginapi-sys = { git = "https://github.com/mveril/wslpluginapi-sys.git", branch = "main" } [dependencies.semver] version = ">0.1" diff --git a/wslplugins-rs/src/api/api_v1.rs b/wslplugins-rs/src/api/api_v1.rs index 544f038..1888653 100644 --- a/wslplugins-rs/src/api/api_v1.rs +++ b/wslplugins-rs/src/api/api_v1.rs @@ -1,10 +1,11 @@ -extern crate wslplugins_sys; +extern crate wslpluginapi_sys; #[cfg(doc)] use super::Error; use super::Result; use crate::api::errors::require_update_error::Result as UpReqResult; use crate::cstring_ext::CstringExt; use crate::wsl_session_information::WSLSessionInformation; +use crate::WSLVersion; #[cfg(feature = "log-instrument")] use log_instrument::instrument; use std::ffi::{CString, OsStr}; @@ -23,7 +24,7 @@ use windows::{ Win32::Foundation::BOOL, }; -use wslplugins_sys::{WSLPluginAPIV1, WSLVersion}; +use wslpluginapi_sys::WSLPluginAPIV1; use super::utils::check_required_version_result; @@ -72,7 +73,7 @@ impl ApiV1 { /// ); #[cfg_attr(feature = "log-instrument", instrument)] pub fn version(&self) -> &WSLVersion { - &self.0.Version + self.0.Version.as_ref() } /// Create plan9 mount between Windows & Linux diff --git a/wslplugins-rs/src/api/errors.rs b/wslplugins-rs/src/api/errors.rs index a729900..c2a6eee 100644 --- a/wslplugins-rs/src/api/errors.rs +++ b/wslplugins-rs/src/api/errors.rs @@ -8,7 +8,7 @@ use thiserror::Error; pub mod require_update_error; pub use require_update_error::Error as RequireUpdateError; use windows::core::{Error as WinError, HRESULT}; -use wslplugins_sys::WSL_E_PLUGIN_REQUIRES_UPDATE; +use wslpluginapi_sys::WSL_E_PLUGIN_REQUIRES_UPDATE; /// A comprehensive error type for WSL plugins. /// diff --git a/wslplugins-rs/src/api/errors/require_update_error.rs b/wslplugins-rs/src/api/errors/require_update_error.rs index 8cb8fdf..c243d47 100644 --- a/wslplugins-rs/src/api/errors/require_update_error.rs +++ b/wslplugins-rs/src/api/errors/require_update_error.rs @@ -4,9 +4,10 @@ //! does not meet the required version. It integrates with Windows error codes for seamless interop //! with WSL APIs. +use crate::WSLVersion; use thiserror::Error; use windows::core::HRESULT; -use wslplugins_sys::{WSLVersion, WSL_E_PLUGIN_REQUIRES_UPDATE}; +use wslpluginapi_sys::WSL_E_PLUGIN_REQUIRES_UPDATE; /// Represents an error when the current WSL version is unsupported. /// diff --git a/wslplugins-rs/src/api/utils.rs b/wslplugins-rs/src/api/utils.rs index 33ea9d7..fe2acee 100644 --- a/wslplugins-rs/src/api/utils.rs +++ b/wslplugins-rs/src/api/utils.rs @@ -5,7 +5,7 @@ use super::errors::require_update_error::{Error, Result}; use crate::WSLContext; -use wslplugins_sys::WSLVersion; +use crate::WSLVersion; pub(crate) fn check_required_version_result( current_version: &WSLVersion, @@ -15,8 +15,8 @@ pub(crate) fn check_required_version_result( Ok(()) } else { Err(Error { - current_version: *current_version, - required_version: *required_version, + current_version: current_version.clone(), + required_version: required_version.clone(), }) } } @@ -36,7 +36,7 @@ pub(crate) fn check_required_version_result_from_context( #[cfg(test)] mod tests { use super::*; - use wslplugins_sys::WSLVersion; + use crate::WSLVersion; /// Tests that `check_required_version_result` returns `Ok` when the current version meets the requirement. #[test] diff --git a/wslplugins-rs/src/distribution_information.rs b/wslplugins-rs/src/distribution_information.rs index 101b7e2..3923c38 100644 --- a/wslplugins-rs/src/distribution_information.rs +++ b/wslplugins-rs/src/distribution_information.rs @@ -12,7 +12,7 @@ //! - Process ID (PID) of the init process (requires API version 2.0.5 or higher) //! - PID namespace -extern crate wslplugins_sys; +extern crate wslpluginapi_sys; #[cfg(doc)] use crate::api::errors::require_update_error::Error; use crate::api::{ @@ -20,43 +20,43 @@ use crate::api::{ }; use crate::core_distribution_information::CoreDistributionInformation; use crate::WSLContext; +use crate::WSLVersion; use std::ffi::OsString; use std::fmt::{Debug, Display}; use std::hash::Hash; use std::os::windows::ffi::OsStringExt; use windows::core::GUID; -use wslplugins_sys::WSLVersion; /// Represents detailed information about a WSL distribution. /// /// This struct wraps the `WSLDistributionInformation` from the WSL Plugin API and provides /// safe, idiomatic Rust access to its fields. #[repr(transparent)] -pub struct DistributionInformation(wslplugins_sys::WSLDistributionInformation); +pub struct DistributionInformation(wslpluginapi_sys::WSLDistributionInformation); -impl AsRef for wslplugins_sys::WSLDistributionInformation { +impl AsRef for wslpluginapi_sys::WSLDistributionInformation { fn as_ref(&self) -> &DistributionInformation { unsafe { - &*(self as *const wslplugins_sys::WSLDistributionInformation + &*(self as *const wslpluginapi_sys::WSLDistributionInformation as *const DistributionInformation) } } } -impl From for wslplugins_sys::WSLDistributionInformation { +impl From for wslpluginapi_sys::WSLDistributionInformation { fn from(value: DistributionInformation) -> Self { value.0 } } -impl AsRef for DistributionInformation { - fn as_ref(&self) -> &wslplugins_sys::WSLDistributionInformation { +impl AsRef for DistributionInformation { + fn as_ref(&self) -> &wslpluginapi_sys::WSLDistributionInformation { &self.0 } } -impl From for DistributionInformation { - fn from(value: wslplugins_sys::WSLDistributionInformation) -> Self { +impl From for DistributionInformation { + fn from(value: wslpluginapi_sys::WSLDistributionInformation) -> Self { DistributionInformation(value) } } @@ -179,6 +179,7 @@ mod tests { #[test] fn test_layouts() { - test_transparence::(); + test_transparence::( + ); } } diff --git a/wslplugins-rs/src/lib.rs b/wslplugins-rs/src/lib.rs index 5b63b3d..f868287 100644 --- a/wslplugins-rs/src/lib.rs +++ b/wslplugins-rs/src/lib.rs @@ -62,12 +62,14 @@ pub use offline_distribution_information::OfflineDistributionInformation; pub use wsl_context::WSLContext; pub use wsl_session_information::WSLSessionInformation; pub use wsl_vm_creation_settings::WSLVmCreationSettings; +mod wsl_version; +pub use wsl_version::WSLVersion; /// Re-exports procedural macros when the `macro` feature is enabled. /// It allow to mark a plugin struct (that implement [WSLPluginV1] trait) to be easely integrated to the WSL plugin system without writing manually C code for entry point or hooks. #[cfg(feature = "macro")] pub use wslplugins_macro::wsl_plugin_v1; -/// Re-exports the `wslplugins_sys` crate as `sys` when the `sys` feature is enabled. +/// Re-exports the `wslpluginapi_sys` crate as `sys` when the `sys` feature is enabled. #[cfg(feature = "sys")] -pub use wslplugins_sys as sys; +pub use wslpluginapi_sys as sys; diff --git a/wslplugins-rs/src/offline_distribution_information.rs b/wslplugins-rs/src/offline_distribution_information.rs index 58278c8..0dc5b71 100644 --- a/wslplugins-rs/src/offline_distribution_information.rs +++ b/wslplugins-rs/src/offline_distribution_information.rs @@ -3,7 +3,7 @@ //! This module provides an abstraction over `WslOfflineDistributionInformation` from the WSL Plugin API, //! offering a safe and idiomatic Rust interface for accessing offline distribution details. -extern crate wslplugins_sys; +extern crate wslpluginapi_sys; use crate::core_distribution_information::CoreDistributionInformation; use std::{ ffi::OsString, @@ -18,30 +18,30 @@ use windows::core::GUID; /// This struct allows access to the details of an offline WSL distribution, including /// its ID, name, and optional package family name. #[repr(transparent)] -pub struct OfflineDistributionInformation(wslplugins_sys::WslOfflineDistributionInformation); +pub struct OfflineDistributionInformation(wslpluginapi_sys::WslOfflineDistributionInformation); -impl From for wslplugins_sys::WslOfflineDistributionInformation { +impl From for wslpluginapi_sys::WslOfflineDistributionInformation { fn from(value: OfflineDistributionInformation) -> Self { value.0 } } -impl From for OfflineDistributionInformation { - fn from(value: wslplugins_sys::WslOfflineDistributionInformation) -> Self { +impl From for OfflineDistributionInformation { + fn from(value: wslpluginapi_sys::WslOfflineDistributionInformation) -> Self { OfflineDistributionInformation(value) } } -impl AsRef for OfflineDistributionInformation { - fn as_ref(&self) -> &wslplugins_sys::WslOfflineDistributionInformation { +impl AsRef for OfflineDistributionInformation { + fn as_ref(&self) -> &wslpluginapi_sys::WslOfflineDistributionInformation { &self.0 } } -impl AsRef for wslplugins_sys::WslOfflineDistributionInformation { +impl AsRef for wslpluginapi_sys::WslOfflineDistributionInformation { fn as_ref(&self) -> &OfflineDistributionInformation { unsafe { - &*(self as *const wslplugins_sys::WslOfflineDistributionInformation + &*(self as *const wslpluginapi_sys::WslOfflineDistributionInformation as *const OfflineDistributionInformation) } } @@ -122,7 +122,7 @@ mod tests { #[test] fn test_layouts() { test_transparence::< - wslplugins_sys::WslOfflineDistributionInformation, + wslpluginapi_sys::WslOfflineDistributionInformation, OfflineDistributionInformation, >(); } diff --git a/wslplugins-rs/src/plugin/utils.rs b/wslplugins-rs/src/plugin/utils.rs index f34da12..1e17039 100644 --- a/wslplugins-rs/src/plugin/utils.rs +++ b/wslplugins-rs/src/plugin/utils.rs @@ -7,7 +7,7 @@ use windows::{ core::{Error as WinError, Result as WinResult}, Win32::Foundation::ERROR_ALREADY_INITIALIZED, }; -use wslplugins_sys::WSLPluginAPIV1; +use wslpluginapi_sys::WSLPluginAPIV1; use crate::WSLContext; @@ -35,7 +35,7 @@ use super::{Result, WSLPluginV1}; /// /// # Errors /// - Returns [WinError]`::from(`[ERROR_ALREADY_INITIALIZED]`)` if a plugin is already initialized. -/// - Returns [WinError]`::from(`[WSL_E_PLUGIN_REQUIRES_UPDATE](wslplugins_sys::WSL_E_PLUGIN_REQUIRES_UPDATE)`)` error if the API version is insufficient. +/// - Returns [WinError]`::from(`[WSL_E_PLUGIN_REQUIRES_UPDATE](wslpluginapi_sys::WSL_E_PLUGIN_REQUIRES_UPDATE)`)` error if the API version is insufficient. /// /// # Safety /// This function calls an unsafe API to check the reqred version. Ensure the provided API pointer @@ -47,7 +47,7 @@ pub fn create_plugin_with_required_version( required_revision: u32, ) -> WinResult { unsafe { - wslplugins_sys::require_version(required_major, required_minor, required_revision, api) + wslpluginapi_sys::require_version(required_major, required_minor, required_revision, api) .ok()?; } if let Some(context) = WSLContext::init(api.as_ref()) { diff --git a/wslplugins-rs/src/wsl_session_information.rs b/wslplugins-rs/src/wsl_session_information.rs index 4c71432..85e976b 100644 --- a/wslplugins-rs/src/wsl_session_information.rs +++ b/wslplugins-rs/src/wsl_session_information.rs @@ -3,7 +3,7 @@ //! This module provides a safe abstraction over the `WSLSessionInformation` structure //! from the WSL Plugin API, allowing access to session details in an idiomatic Rust interface. -extern crate wslplugins_sys; +extern crate wslpluginapi_sys; use core::hash; use std::fmt; use windows::Win32::Foundation::*; @@ -13,7 +13,7 @@ use windows::Win32::Security::PSID; /// /// This struct wraps the `WSLSessionInformation` provided by the WSL Plugin API and /// provides safe, idiomatic access to its fields. -pub struct WSLSessionInformation(wslplugins_sys::WSLSessionInformation); +pub struct WSLSessionInformation(wslpluginapi_sys::WSLSessionInformation); impl WSLSessionInformation { /// Retrieves the session ID. @@ -41,28 +41,29 @@ impl WSLSessionInformation { } } -impl From for WSLSessionInformation { - fn from(value: wslplugins_sys::WSLSessionInformation) -> Self { +impl From for WSLSessionInformation { + fn from(value: wslpluginapi_sys::WSLSessionInformation) -> Self { WSLSessionInformation(value) } } -impl From for wslplugins_sys::WSLSessionInformation { +impl From for wslpluginapi_sys::WSLSessionInformation { fn from(value: WSLSessionInformation) -> Self { value.0 } } -impl AsRef for wslplugins_sys::WSLSessionInformation { +impl AsRef for wslpluginapi_sys::WSLSessionInformation { fn as_ref(&self) -> &WSLSessionInformation { unsafe { - &*(self as *const wslplugins_sys::WSLSessionInformation as *const WSLSessionInformation) + &*(self as *const wslpluginapi_sys::WSLSessionInformation + as *const WSLSessionInformation) } } } -impl AsRef for WSLSessionInformation { - fn as_ref(&self) -> &wslplugins_sys::WSLSessionInformation { +impl AsRef for WSLSessionInformation { + fn as_ref(&self) -> &wslpluginapi_sys::WSLSessionInformation { &self.0 } } @@ -112,6 +113,6 @@ mod tests { #[test] fn test_layouts() { - test_transparence::(); + test_transparence::(); } } diff --git a/wslplugins-rs/src/wsl_user_configuration/bitflags.rs b/wslplugins-rs/src/wsl_user_configuration/bitflags.rs index c100abe..9aa961c 100644 --- a/wslplugins-rs/src/wsl_user_configuration/bitflags.rs +++ b/wslplugins-rs/src/wsl_user_configuration/bitflags.rs @@ -21,9 +21,9 @@ bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct WSLUserConfigurationFlags: i32 { /// A custom Linux kernel is used for the WSL instance. - const CustomKernel = wslplugins_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernel; + const CustomKernel = wslpluginapi_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernel; /// A custom kernel command-line is used for the WSL instance. - const CustomKernelCommandLine = wslplugins_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernelCommandLine; + const CustomKernelCommandLine = wslpluginapi_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernelCommandLine; } } diff --git a/wslplugins-rs/src/wsl_user_configuration/enumflags2.rs b/wslplugins-rs/src/wsl_user_configuration/enumflags2.rs index 327ed4b..1334c1c 100644 --- a/wslplugins-rs/src/wsl_user_configuration/enumflags2.rs +++ b/wslplugins-rs/src/wsl_user_configuration/enumflags2.rs @@ -23,11 +23,11 @@ use enumflags2::{bitflags, BitFlags}; #[repr(u32)] pub enum WSLUserConfigurationFlags { /// A custom Linux kernel is used for the WSL instance. - CustomKernel = wslplugins_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernel as u32, + CustomKernel = wslpluginapi_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernel as u32, /// A custom kernel command-line is used for the WSL instance. CustomKernelCommandLine = - wslplugins_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernelCommandLine as u32, + wslpluginapi_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernelCommandLine as u32, } impl From for BitFlags { diff --git a/wslplugins-rs/src/wsl_user_configuration/flagset.rs b/wslplugins-rs/src/wsl_user_configuration/flagset.rs index 6759a25..6f1abf0 100644 --- a/wslplugins-rs/src/wsl_user_configuration/flagset.rs +++ b/wslplugins-rs/src/wsl_user_configuration/flagset.rs @@ -21,10 +21,10 @@ flags! { #[derive(Hash)] pub enum WSLUserConfigurationFlags: i32 { /// A custom Linux kernel is used for the WSL instance. - CustomKernel = wslplugins_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernel, + CustomKernel = wslpluginapi_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernel, /// A custom kernel command-line is used for the WSL instance. CustomKernelCommandLine = - wslplugins_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernelCommandLine, + wslpluginapi_sys::WSLUserConfiguration_WSLUserConfigurationCustomKernelCommandLine, } } diff --git a/wslplugins-rs/src/wsl_version.rs b/wslplugins-rs/src/wsl_version.rs new file mode 100644 index 0000000..bbc53d8 --- /dev/null +++ b/wslplugins-rs/src/wsl_version.rs @@ -0,0 +1,140 @@ +use std::{ + fmt::{Debug, Display}, + hash::Hash, +}; + +/// Represents a WSL version number. +/// +/// This struct wraps the `WSLVersion` from the WSL Plugin API and provides +/// safe, idiomatic Rust access to its fields. +/// # Example +/// ``` +/// use wslplugins_rs::WSLVersion; +/// let version = WSLVersion::new(2, 0, 0); +/// assert_eq!(version.major(), 2); +/// assert_eq!(version.minor(), 0); +/// assert_eq!(version.revision(), 0); +/// ``` +#[repr(transparent)] +#[derive(Clone, Eq)] +pub struct WSLVersion(wslpluginapi_sys::WSLVersion); + +impl WSLVersion { + /// Creates a new `WSLVersion` instance. + /// # Parameters + /// - `major`: The major version number. + /// - `minor`: The minor version number. + /// - `revision`: The revision number. + /// # Returns + /// The new `WSLVersion` instance. + pub fn new(major: u32, minor: u32, revision: u32) -> Self { + wslpluginapi_sys::WSLVersion { + Major: major, + Minor: minor, + Revision: revision, + } + .into() + } + + /// Retrieves the major version number. + pub fn major(&self) -> u32 { + self.0.Major + } + + /// Set the major version number. + pub fn set_major(&mut self, major: u32) { + self.0.Major = major + } + + /// Retrieves the minor version number. + pub fn minor(&self) -> u32 { + self.0.Minor + } + + /// Set the minor version number. + pub fn set_minor(&mut self, minor: u32) { + self.0.Minor = minor + } + + /// Retrieves the revision version number. + pub fn revision(&self) -> u32 { + self.0.Revision + } + + /// Set the revision version number. + pub fn set_revision(&mut self, revision: u32) { + self.0.Revision = revision + } +} + +impl From for WSLVersion { + fn from(value: wslpluginapi_sys::WSLVersion) -> Self { + WSLVersion(value) + } +} + +impl From for wslpluginapi_sys::WSLVersion { + fn from(value: WSLVersion) -> Self { + value.0 + } +} + +impl AsRef for wslpluginapi_sys::WSLVersion { + fn as_ref(&self) -> &WSLVersion { + unsafe { &*(self as *const wslpluginapi_sys::WSLVersion as *const WSLVersion) } + } +} + +impl AsRef for WSLVersion { + fn as_ref(&self) -> &wslpluginapi_sys::WSLVersion { + &self.0 + } +} + +impl Hash for WSLVersion { + fn hash(&self, state: &mut H) { + self.major().hash(state); + self.minor().hash(state); + self.revision().hash(state); + } +} + +impl Default for WSLVersion { + fn default() -> Self { + Self::new(1, 0, 0) + } +} + +impl PartialEq for WSLVersion { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl PartialOrd for WSLVersion { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for WSLVersion { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl Display for WSLVersion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}.{}.{}", self.major(), self.minor(), self.revision()) + } +} + +impl Debug for WSLVersion { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct(stringify!(WSLVersion)) + .field("major", &self.major()) + .field("minor", &self.minor()) + .field("revision", &self.revision()) + .finish() + } +} diff --git a/wslplugins-rs/src/wsl_vm_creation_settings.rs b/wslplugins-rs/src/wsl_vm_creation_settings.rs index 8e44ec4..fa22145 100644 --- a/wslplugins-rs/src/wsl_vm_creation_settings.rs +++ b/wslplugins-rs/src/wsl_vm_creation_settings.rs @@ -12,30 +12,31 @@ use crate::WSLUserConfiguration; /// /// This struct wraps the `WSLVmCreationSettings` structure from the WSL Plugin API, providing /// safe and idiomatic Rust access to its fields. -pub struct WSLVmCreationSettings(wslplugins_sys::WSLVmCreationSettings); +pub struct WSLVmCreationSettings(wslpluginapi_sys::WSLVmCreationSettings); -impl From for WSLVmCreationSettings { - fn from(value: wslplugins_sys::WSLVmCreationSettings) -> Self { +impl From for WSLVmCreationSettings { + fn from(value: wslpluginapi_sys::WSLVmCreationSettings) -> Self { WSLVmCreationSettings(value) } } -impl From for wslplugins_sys::WSLVmCreationSettings { +impl From for wslpluginapi_sys::WSLVmCreationSettings { fn from(value: WSLVmCreationSettings) -> Self { value.0 } } -impl AsRef for WSLVmCreationSettings { - fn as_ref(&self) -> &wslplugins_sys::WSLVmCreationSettings { +impl AsRef for WSLVmCreationSettings { + fn as_ref(&self) -> &wslpluginapi_sys::WSLVmCreationSettings { &self.0 } } -impl AsRef for wslplugins_sys::WSLVmCreationSettings { +impl AsRef for wslpluginapi_sys::WSLVmCreationSettings { fn as_ref(&self) -> &WSLVmCreationSettings { unsafe { - &*(self as *const wslplugins_sys::WSLVmCreationSettings as *const WSLVmCreationSettings) + &*(self as *const wslpluginapi_sys::WSLVmCreationSettings + as *const WSLVmCreationSettings) } } } @@ -77,6 +78,6 @@ mod tests { #[test] fn test_layouts() { - test_transparence::(); + test_transparence::(); } } diff --git a/wslplugins-sys/Cargo.toml b/wslplugins-sys/Cargo.toml deleted file mode 100644 index 425ecef..0000000 --- a/wslplugins-sys/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "wslplugins-sys" -version = "0.1.0-alpha.0+2.1.3" -authors = ["Mickaël Véril "] -edition = "2021" -[features] -hooks-field-names = ["struct-field-names-as-array"] - -[build-dependencies] -bindgen = "0.71.1" -semver = "^1.0" - -[dependencies] -libc = "0.2" -struct-field-names-as-array = { version = "*", features = [ - "derive", -], optional = true } -[dependencies.windows] -version = "0.58" -features = [ - "Win32_Foundation", - "Win32_Security", - "Win32_System_Diagnostics_Debug", - "Win32_Networking_WinSock", -] diff --git a/wslplugins-sys/build.rs b/wslplugins-sys/build.rs deleted file mode 100644 index 25222fb..0000000 --- a/wslplugins-sys/build.rs +++ /dev/null @@ -1,151 +0,0 @@ -extern crate bindgen; -extern crate semver; - -use bindgen::callbacks::{ParseCallbacks, TypeKind}; -use semver::Version; -use std::env; -use std::path::{Path, PathBuf}; -use std::process::{Command, ExitStatus}; - -const WSL_PACKAGE_NAME: &str = "Microsoft.WSL.PluginApi"; -const LOCAL_NUGET_PATH: &str = "nuget_packages"; // Local folder to store NuGet packages - -#[derive(Debug, Default)] -struct BindgenCallback { - generate_hooks_fields_name: bool, -} - -impl BindgenCallback { - fn new(generate_hooks_fields_names: bool) -> Self { - BindgenCallback { - generate_hooks_fields_name: generate_hooks_fields_names, - } - } -} - -impl ParseCallbacks for BindgenCallback { - fn add_derives(&self, _info: &bindgen::callbacks::DeriveInfo<'_>) -> Vec { - if _info.kind == TypeKind::Struct && _info.name == "WSLVersion" { - vec![ - "Eq".into(), - "PartialEq".into(), - "Ord".into(), - "PartialOrd".into(), - "Hash".into(), - ] - } else if _info.kind == TypeKind::Struct - && _info.name.contains("PluginHooks") - && self.generate_hooks_fields_name - { - vec!["FieldNamesAsSlice".into()] - } else { - vec![] - } - } -} - -// Function to ensure the NuGet package is installed in the local folder -fn ensure_package_installed( - package_name: &str, - package_version: &str, - output_dir: &str, -) -> Result> { - // Run the NuGet install command with -NonInteractive to avoid prompts - let status = Command::new("nuget") - .args([ - "install", - package_name, - "-Version", - package_version, - "-OutputDirectory", - output_dir, // Local folder to install the NuGet package - "-NonInteractive", // Ensures the command runs without user interaction - ]) - .status() - .expect("Failed to execute nuget install command"); - - if !status.success() { - return Err(format!( - "NuGet install command failed with status: {:?}", - status.code() - ) - .into()); - } - Ok(status) -} - -fn main() -> Result<(), Box> { - // Extract the version of the package from the Cargo metadata - let version_str = env!("CARGO_PKG_VERSION"); - let version = Version::parse(version_str).expect("Unable to parse the Cargo package version"); - let build_metadata = &version.build; - - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:version={}", version); - if !build_metadata.is_empty() { - println!("cargo:build-metadata={}", build_metadata); - } - - let package_version = build_metadata.to_string(); - - // Ensure the NuGet package is installed in the specified local directory - ensure_package_installed(WSL_PACKAGE_NAME, &package_version, LOCAL_NUGET_PATH)?; - - // Construct the full path to the installed package in the local directory - let package_path = - Path::new(LOCAL_NUGET_PATH).join(format!("{:}.{:}", WSL_PACKAGE_NAME, package_version)); - - // Construct the path to the header file - let header_file_path = package_path - .join("build") - .join("native") - .join("include") - .join("WslPluginApi.h"); - - // Check if the header file exists - if !header_file_path.exists() { - return Err(format!("Header file does not exist: {:?}", header_file_path).into()); - } - - println!("Using header file from: {:?}", header_file_path); - - // Use bindgen to generate Rust bindings from the header file - let hooks_fields_name_feature = env::var("CARGO_FEATURE_HOOKS_FIELD_NAMES").is_ok(); - let mut builder = bindgen::Builder::default() - .header(header_file_path.to_str().unwrap()) - .raw_line("use windows::core::*;") - .raw_line("use windows::Win32::Foundation::*;") - .raw_line("use windows::Win32::Security::*;") - .raw_line("use windows::Win32::Networking::WinSock::SOCKET;") - .raw_line("#[allow(clippy::upper_case_acronyms)]") - .raw_line("type LPCWSTR = PCWSTR;") - .raw_line("#[allow(clippy::upper_case_acronyms)]") - .raw_line("type LPCSTR = PCSTR;") - .raw_line("#[allow(clippy::upper_case_acronyms)]") - .raw_line("type DWORD = u32;"); - - if hooks_fields_name_feature { - builder = builder.raw_line("use struct_field_names_as_array::FieldNamesAsSlice;"); - } - - let wslplugins_sys = builder - .derive_debug(true) - .derive_copy(true) - .allowlist_item("WSL.*") - .allowlist_item("Wsl.*") - .clang_arg("-fparse-all-comments") - .allowlist_recursively(false) - .parse_callbacks(Box::new(BindgenCallback::new(hooks_fields_name_feature))) - .generate_comments(true) - .generate() - .expect("Unable to generate wslplugins_sys"); - - // Write the generated bindings to the OUT_DIR - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let wslplugins_sys_out_path = out_dir.join("wslplugins_sys.rs"); - wslplugins_sys - .write_to_file(wslplugins_sys_out_path) - .expect("Couldn't write wslplugins_sys!"); - - Ok(()) -} diff --git a/wslplugins-sys/src/bindgen.rs b/wslplugins-sys/src/bindgen.rs deleted file mode 100644 index f91abb2..0000000 --- a/wslplugins-sys/src/bindgen.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -include!(concat!(env!("OUT_DIR"), "/wslplugins_sys.rs")); diff --git a/wslplugins-sys/src/lib.rs b/wslplugins-sys/src/lib.rs deleted file mode 100644 index aaa5cd9..0000000 --- a/wslplugins-sys/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod bindgen; -mod manual; -pub use crate::bindgen::*; -pub use manual::*; diff --git a/wslplugins-sys/src/manual.rs b/wslplugins-sys/src/manual.rs deleted file mode 100644 index 76ca6ce..0000000 --- a/wslplugins-sys/src/manual.rs +++ /dev/null @@ -1,190 +0,0 @@ -use std::fmt::Display; - -use crate::{WSLPluginAPIV1, WSLVersion}; -use windows::core::HRESULT; -use windows::Win32::Foundation::{SEVERITY_ERROR, S_OK}; -use windows::Win32::System::Diagnostics::Debug::{FACILITY_CODE, FACILITY_ITF}; - -#[inline(always)] -const fn make_hresult(severity: u32, facility: FACILITY_CODE, code: u32) -> HRESULT { - HRESULT(((severity << 31) | (facility.0 << 16) | code) as i32) -} - -pub const WSL_E_PLUGIN_REQUIRES_UPDATE: HRESULT = - make_hresult(SEVERITY_ERROR, FACILITY_ITF, 0x8004032A); - -/// Ensures the WSL Plugin API version meets the minimum required version. -/// -/// This function compares the version of the API passed as a parameter against the required -/// version numbers specified (`required_major`, `required_minor`, `required_revision`). -/// If the API version is lower than required, it returns `WSL_E_PLUGIN_REQUIRES_UPDATE`. -/// Otherwise, it returns `S_OK`. -/// -/// # Parameters -/// -/// - `required_major`: The major version number required by the plugin. -/// - `required_minor`: The minor version number required by the plugin. -/// - `required_revision`: The revision number required by the plugin. -/// - `api`: A pointer to the `WSLPluginAPIV1` structure, containing the current API version. -/// -/// # Returns -/// -/// - `S_OK`: If the API version meets or exceeds the required version. -/// - `WSL_E_PLUGIN_REQUIRES_UPDATE`: If the API version is below the required minimum. -/// -/// # Safety -/// -/// This function is `unsafe` because it dereferences a raw pointer (`api`). The caller must -/// ensure that the pointer is valid and points to a properly initialized `WSLPluginAPIV1` -/// structure. -#[inline(always)] -pub const unsafe fn require_version( - required_major: u32, - required_minor: u32, - required_revision: u32, - api: *const WSLPluginAPIV1, -) -> HRESULT { - let version = &(*api).Version; - - if version.Major < required_major - || (version.Major == required_major && version.Minor < required_minor) - || (version.Major == required_major - && version.Minor == required_minor - && version.Revision < required_revision) - { - WSL_E_PLUGIN_REQUIRES_UPDATE - } else { - S_OK - } -} - -impl Display for WSLVersion { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}.{}.{}", self.Major, self.Minor, self.Revision) - } -} - -impl WSLVersion { - pub fn new(major: u32, minor: u32, revision: u32) -> Self { - Self { - Major: major, - Minor: minor, - Revision: revision, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{WSLPluginAPIV1, WSLVersion}; - use windows::Win32::Foundation::S_OK; - - #[test] - fn test_version_exact_match() { - let api = WSLPluginAPIV1 { - Version: WSLVersion { - Major: 1, - Minor: 0, - Revision: 0, - }, - MountFolder: None, - ExecuteBinary: None, - PluginError: None, - ExecuteBinaryInDistribution: None, - }; - - assert_eq!(unsafe { require_version(1, 0, 0, &api) }, S_OK); - } - - #[test] - fn test_version_major_too_low() { - let api = WSLPluginAPIV1 { - Version: WSLVersion { - Major: 0, - Minor: 9, - Revision: 0, - }, - MountFolder: None, - ExecuteBinary: None, - PluginError: None, - ExecuteBinaryInDistribution: None, - }; - - assert_eq!( - unsafe { require_version(1, 0, 0, &api) }, - WSL_E_PLUGIN_REQUIRES_UPDATE - ); - } - - #[test] - fn test_version_minor_too_low() { - let api = WSLPluginAPIV1 { - Version: WSLVersion { - Major: 1, - Minor: 0, - Revision: 0, - }, - MountFolder: None, - ExecuteBinary: None, - PluginError: None, - ExecuteBinaryInDistribution: None, - }; - - assert_eq!( - unsafe { require_version(1, 1, 0, &api) }, - WSL_E_PLUGIN_REQUIRES_UPDATE - ); - } - - #[test] - fn test_version_revision_too_low() { - let api = WSLPluginAPIV1 { - Version: WSLVersion { - Major: 1, - Minor: 0, - Revision: 0, - }, - MountFolder: None, - ExecuteBinary: None, - PluginError: None, - ExecuteBinaryInDistribution: None, - }; - - assert_eq!( - unsafe { require_version(1, 0, 1, &api) }, - WSL_E_PLUGIN_REQUIRES_UPDATE - ); - } - - #[test] - fn test_version_high_enough() { - let api = WSLPluginAPIV1 { - Version: WSLVersion { - Major: 1, - Minor: 2, - Revision: 3, - }, - MountFolder: None, - ExecuteBinary: None, - PluginError: None, - ExecuteBinaryInDistribution: None, - }; - - assert_eq!(unsafe { require_version(1, 0, 1, &api) }, S_OK); - } - - #[test] - fn test_display_trait() { - let version = WSLVersion::new(1, 2, 3); - assert_eq!(format!("{}", version), "1.2.3"); - } - - #[test] - fn test_new_constructor() { - let version = WSLVersion::new(1, 2, 3); - assert_eq!(version.Major, 1); - assert_eq!(version.Minor, 2); - assert_eq!(version.Revision, 3); - } -}