wslplugins_rs/
user_distribution_id.rs1use std::{
2 fmt::{Debug, Display, LowerHex, UpperHex},
3 str::FromStr,
4};
5use thiserror::Error;
6pub mod fmt;
7mod parse_error;
8use fmt::DefaultFormatter;
9pub use parse_error::ParseError;
10
11use crate::{CoreWSLDistributionInformation, DistributionID};
12#[cfg(feature = "serde")]
13mod serde_impl;
14#[cfg(feature = "uuid")]
15mod uuid_impl;
16
17#[repr(transparent)]
18#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
24pub struct UserDistributionID(pub windows_core::GUID);
25
26#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, Hash)]
28#[error("Cannot convert System distribution to UserDistribution.")]
29pub struct UserDistributionIDConversionError;
30
31impl From<windows_core::GUID> for UserDistributionID {
32 #[inline]
33 fn from(value: windows_core::GUID) -> Self {
34 Self(value)
35 }
36}
37
38impl From<wslpluginapi_sys::windows_sys::core::GUID> for UserDistributionID {
39 #[inline]
40 fn from(value: wslpluginapi_sys::windows_sys::core::GUID) -> Self {
41 let guid = unsafe {
43 std::mem::transmute::<wslpluginapi_sys::windows_sys::core::GUID, windows_core::GUID>(
44 value,
45 )
46 };
47 Self(guid)
48 }
49}
50
51impl<T: CoreWSLDistributionInformation> From<&T> for UserDistributionID {
52 #[inline]
54 fn from(value: &T) -> Self {
55 value.id()
56 }
57}
58
59impl TryFrom<DistributionID> for UserDistributionID {
60 type Error = UserDistributionIDConversionError;
61 #[inline]
62 fn try_from(value: DistributionID) -> Result<Self, Self::Error> {
63 match value {
64 DistributionID::User(id) => Ok(id),
65 DistributionID::System => Err(UserDistributionIDConversionError),
66 }
67 }
68}
69
70impl From<UserDistributionID> for wslpluginapi_sys::windows_sys::core::GUID {
71 #[inline]
72 fn from(value: UserDistributionID) -> Self {
73 unsafe { std::mem::transmute(value.0) }
75 }
76}
77
78impl From<UserDistributionID> for windows_core::GUID {
79 #[inline]
80 fn from(value: UserDistributionID) -> Self {
81 value.0
82 }
83}
84
85impl UpperHex for UserDistributionID {
86 #[inline]
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 UpperHex::fmt(&DefaultFormatter::from(*self), f)
89 }
90}
91
92impl LowerHex for UserDistributionID {
93 #[inline]
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 LowerHex::fmt(&DefaultFormatter::from(*self), f)
96 }
97}
98
99impl Debug for UserDistributionID {
100 #[inline]
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 if f.alternate() {
103 f.debug_tuple(stringify!(UserDistributionID))
104 .field(&self.0)
105 .finish()
106 } else {
107 write!(f, "{self}")
108 }
109 }
110}
111
112impl Display for UserDistributionID {
113 #[inline]
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 UpperHex::fmt(&self, f)
116 }
117}
118
119#[cfg(any(windows, feature = "uuid"))]
120impl FromStr for UserDistributionID {
121 type Err = ParseError;
122 #[inline]
123 fn from_str(s: &str) -> Result<Self, Self::Err> {
124 DefaultFormatter::from_str(s).map(Self::from)
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use proptest::prelude::*;
132 proptest! {
133 #[test]
134 fn test_user_distribution_id_formating(int_value in any::<u128>()) {
135 let guid = windows_core::GUID::from_u128(int_value);
136 let user_dist_id: UserDistributionID = guid.into();
137 prop_assert_eq!(format!("{:?}", guid), format!("{:X}", user_dist_id));
138 prop_assert_eq!(format!("{:X}", user_dist_id), format!("{:}", user_dist_id));
139 prop_assert_eq!(format!("{:X}", user_dist_id), format!("{:?}", user_dist_id));
140 prop_assert_eq!(format!("{:x}", user_dist_id), format!("{user_dist_id:X}").to_ascii_lowercase());
141 }
142 }
143
144 #[test]
145 fn try_from_system_returns_error() {
146 assert_eq!(
147 UserDistributionID::try_from(DistributionID::System),
148 Err(UserDistributionIDConversionError)
149 );
150 }
151}