Skip to main content

wslplugins_rs/
distribution_id.rs

1//! # Module `DistributionID`
2//!
3//! This module defines an abstraction to represent WSL distributions through a
4//! [`DistributionID`]. It supports two types of identifiers: system-level distributions
5//! and user-specific installed distributions identified by a GUID.
6//!
7//! ## Key Features
8//!
9//! - Bi-directional conversion between [`DistributionID`] and [`UserDistributionID`].
10//! - Robust error handling for conversions via [`ConversionError`].
11//! - Display implementation ([Display]) and support for other idiomatic conversions.
12//!
13//! ## Usage Context
14//!
15//! This abstraction is particularly useful in environments where WSL requires
16//! distribution identification via GUIDs or when a distinction between a system-level
17//! distribution and a user-specific distribution is necessary. The associated functions
18//! and conversions simplify integration with APIs like those defined in `WslPluginApi`.
19
20use crate::{CoreDistributionInformation, UserDistributionID};
21use std::{convert::TryFrom, fmt::Display};
22use thiserror::Error;
23
24/// Represents a distribution identifier in the Windows Subsystem for Linux (WSL).
25///
26/// A distribution can either be the system-level distribution or a user-specific distribution
27/// identified by a [`UserDistributionID`].
28///
29/// ## Variants
30///
31/// - `System`: Represents the system distribution, a central distribution used by WSL
32///   for managing low-level functionalities such as audio and graphical interaction.
33///   Refer to the [WSLg Architecture blogpost](https://devblogs.microsoft.com/commandline/wslg-architecture/#system-distro).
34///
35/// - `User(UserDistributionID)`: Represents an individual distribution installed by a user. Each distribution
36///   is uniquely identified by a [`UserDistributionID`], which is consistent across reboots.
37///
38/// ## Note
39///
40/// - The system distribution serves as a foundational component in WSL, often interacting with
41///   user distributions for operations like Linux GUI apps.
42/// - User distributions provide isolated environments for specific Linux distributions, allowing
43///   users to install and run various Linux distributions on their Windows machines.
44#[derive(Debug, Clone, Copy)]
45pub enum DistributionID {
46    /// Represents the system-level distribution.
47    /// For more info about the system distribution please check the [WSLg architecture blogpost](https://devblogs.microsoft.com/commandline/wslg-architecture/#system-distro)
48    System,
49    /// Represents an installed user-specific distribution identified by a [`UserDistributionID`].
50    User(UserDistributionID),
51}
52
53/// Error type for conversion failures between [`DistributionID`] and [`UserDistributionID`].
54#[derive(Debug, Error)]
55#[error("Cannot convert System distribution to UserDistribution.")]
56pub struct ConversionError;
57
58impl TryFrom<DistributionID> for UserDistributionID {
59    type Error = ConversionError;
60    #[inline]
61    fn try_from(value: DistributionID) -> Result<Self, Self::Error> {
62        match value {
63            DistributionID::User(id) => Ok(id),
64            DistributionID::System => Err(ConversionError),
65        }
66    }
67}
68
69impl From<UserDistributionID> for DistributionID {
70    #[inline]
71    fn from(value: UserDistributionID) -> Self {
72        Self::User(value)
73    }
74}
75
76impl<T: CoreDistributionInformation> From<T> for DistributionID {
77    /// Converts a type implementing `CoreDistributionInformation` into a `DistributionID`.
78    #[inline]
79    fn from(value: T) -> Self {
80        value.id().into()
81    }
82}
83
84impl From<Option<UserDistributionID>> for DistributionID {
85    /// Converts an `Option<GUID>` into a `DistributionID`, defaulting to `System` if `None`.
86    #[inline]
87    fn from(value: Option<UserDistributionID>) -> Self {
88        value.map_or(Self::System, Self::User)
89    }
90}
91
92impl From<DistributionID> for Option<UserDistributionID> {
93    /// Converts a `DistributionID` into an `Option<GUID>`.
94    #[inline]
95    fn from(value: DistributionID) -> Self {
96        match value {
97            DistributionID::System => None,
98            DistributionID::User(id) => Some(id),
99        }
100    }
101}
102
103impl Display for DistributionID {
104    /// Formats the `DistributionID` for display.
105    ///
106    /// Displays "System" for the system-level distribution, or the GUID for a user-specific distribution.
107    #[inline]
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        match self {
110            Self::System => f.write_str("System"),
111            Self::User(id) => std::fmt::Display::fmt(id, f),
112        }
113    }
114}