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}