Skip to main content

wslplugins_rs/plugin/
utils.rs

1//! # Plugin Creation and Result Handling Utilities
2//!
3//! This module provides utility functions for creating WSL plugins and handling results,
4//! enabling smooth integration with the WSL Plugin API.
5
6use std::iter::once;
7
8use windows_core::{Error as WinError, Result as WinResult, HRESULT};
9use wslpluginapi_sys::{windows_sys::Win32::Foundation::ERROR_ALREADY_INITIALIZED, WSLPluginAPIV1};
10
11use crate::{WSLContext, WSLVersion, WSLVersionCapability};
12
13#[cfg(doc)]
14use super::Error;
15use super::{Result, WSLPluginV1};
16
17/// Creates a WSL plugin instance with a specified required API version.
18///
19/// This function ensures that the provided WSL Plugin API meets the required version before
20/// creating a new plugin instance. If the API version does not meet the requirements, an error is returned.
21///
22/// # Type Parameters
23/// - `T`: A type implementing the [`WSLPluginV1`] trait, representing the plugin to create.
24///
25/// # Arguments
26/// - `api`: A reference to the WSL Plugin API version 1 structure.
27/// - `required_major`: The required major version of the API.
28/// - `required_minor`: The required minor version of the API.
29/// - `required_revision`: The required revision of the API.
30///
31/// # Returns
32/// - `Ok(plugin)`: The created plugin instance.
33/// - `Err(WinError)`: If the API version is insufficient or the plugin is already initialized.
34///
35/// # Errors
36/// - Returns <code>[WinError]::from([ERROR_ALREADY_INITIALIZED])</code> if a plugin is already initialized.
37/// - Returns <code>[WinError]::from([WSL_E_PLUGIN_REQUIRES_UPDATE](wslpluginapi_sys::WSL_E_PLUGIN_REQUIRES_UPDATE))</code> error if the API version is insufficient.
38#[inline]
39pub fn create_plugin_with_required_version<T: WSLPluginV1>(
40    api: &'static WSLPluginAPIV1,
41    required_major: u32,
42    required_minor: u32,
43    required_revision: u32,
44) -> WinResult<T> {
45    // SAFETY: As api reference exist it's safe to call it
46    unsafe {
47        HRESULT(wslpluginapi_sys::require_version(
48            required_major,
49            required_minor,
50            required_revision,
51            api,
52        ))
53        .ok()?;
54    };
55    WSLContext::init(api.as_ref())
56        .ok_or_else(|| WinError::from_hresult(HRESULT::from_win32(ERROR_ALREADY_INITIALIZED)))
57        .and_then(T::try_new)
58}
59
60/// Creates a WSL plugin instance with a specified required API capability.
61///
62/// # Errors
63/// Returns a Windows error if the API version is insufficient or the plugin is
64/// already initialized.
65#[inline]
66pub fn create_plugin_with_required_capability<T: WSLPluginV1>(
67    api: &'static WSLPluginAPIV1,
68    capability: WSLVersionCapability,
69) -> WinResult<T> {
70    create_plugin_with_required_capabilities(api, once(capability))
71}
72
73/// Creates a WSL plugin instance with a specified set of required API capabilities.
74///
75/// The highest required version among the provided capabilities is selected.
76///
77/// # Errors
78/// Returns a Windows error if the API version is insufficient or the plugin is
79/// already initialized.
80#[inline]
81pub fn create_plugin_with_required_capabilities<T, I>(
82    api: &'static WSLPluginAPIV1,
83    capabilities: I,
84) -> WinResult<T>
85where
86    T: WSLPluginV1,
87    I: IntoIterator<Item = WSLVersionCapability>,
88{
89    let version = capabilities
90        .into_iter()
91        .map(WSLVersionCapability::required_version)
92        .max()
93        .unwrap_or(WSLVersion::new(0, 0, 0));
94    create_plugin_with_required_version(api, version.major(), version.minor(), version.revision())
95}
96
97#[expect(clippy::missing_errors_doc)]
98/// Converts a generic `Result<T>` using the custom `Error` type into a `WinResult<T>`.
99///
100/// This function simplifies the interoperability between the custom error handling
101/// in the WSL plugin system and the Windows error system by mapping the plugin [Error]
102/// into a [`windows_core::Error`] using the `consume_error_message_unwrap` method.
103///
104/// # Arguments
105/// - `result`: A [`Result<T>`] using the custom [Error] type defined in this crate.
106///
107/// # Returns
108/// A `WinResult<T>` where:
109/// - `Ok(value)` contains the successful result `T`.
110/// - `Err(error)` contains a [`windows_core::Error`] converted from the plugin [Error].
111///
112/// # Behavior
113/// - If the `result` is `Ok`, it is returned as-is.
114/// - If the `result` is `Err`, the error is consumed
115///   and sent to WSL and is then
116///   converted into a [`windows_core::Error`].
117///
118/// # Usage
119/// This utility is intended to facilitate the transition between idiomatic Rust
120/// error handling and the Windows API error-handling conventions.
121#[inline]
122pub fn consume_to_win_result<T>(result: Result<T>) -> WinResult<T> {
123    result.map_err(super::error::Error::consume_error_message_unwrap)
124}