wslplugins_rs/
wsl_version.rs1use std::{
2 fmt::{self, Debug, Display},
3 hash::Hash,
4 ptr,
5 str::FromStr,
6};
7
8mod parse_error;
9pub use parse_error::WSLVersionParseError;
10
11#[cfg(feature = "semver")]
12mod semver_impl;
13#[cfg(feature = "semver")]
14pub use semver_impl::SemverConversionError;
15
16#[cfg(feature = "serde")]
17mod serde_impl;
18
19#[repr(transparent)]
32#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
33pub struct WSLVersion(wslpluginapi_sys::WSLVersion);
34
35impl WSLVersion {
36 #[must_use]
44 #[inline]
45 pub const fn new(major: u32, minor: u32, revision: u32) -> Self {
46 Self(wslpluginapi_sys::WSLVersion {
47 Major: major,
48 Minor: minor,
49 Revision: revision,
50 })
51 }
52
53 #[must_use]
55 #[inline]
56 pub const fn major(&self) -> u32 {
57 self.0.Major
58 }
59
60 #[inline]
62 pub const fn set_major(&mut self, major: u32) {
63 self.0.Major = major;
64 }
65
66 #[must_use]
68 #[inline]
69 pub const fn minor(&self) -> u32 {
70 self.0.Minor
71 }
72
73 #[inline]
75 pub const fn set_minor(&mut self, minor: u32) {
76 self.0.Minor = minor;
77 }
78
79 #[must_use]
81 #[inline]
82 pub const fn revision(&self) -> u32 {
83 self.0.Revision
84 }
85
86 #[inline]
88 pub const fn set_revision(&mut self, revision: u32) {
89 self.0.Revision = revision;
90 }
91}
92
93impl From<wslpluginapi_sys::WSLVersion> for WSLVersion {
94 #[inline]
95 fn from(value: wslpluginapi_sys::WSLVersion) -> Self {
96 Self(value)
97 }
98}
99
100impl From<WSLVersion> for wslpluginapi_sys::WSLVersion {
101 #[inline]
102 fn from(value: WSLVersion) -> Self {
103 value.0
104 }
105}
106
107impl AsRef<WSLVersion> for wslpluginapi_sys::WSLVersion {
108 #[inline]
109 fn as_ref(&self) -> &WSLVersion {
110 unsafe { &*ptr::from_ref(self).cast::<WSLVersion>() }
113 }
114}
115
116impl AsRef<wslpluginapi_sys::WSLVersion> for WSLVersion {
117 #[inline]
118 fn as_ref(&self) -> &wslpluginapi_sys::WSLVersion {
119 &self.0
120 }
121}
122
123impl Display for WSLVersion {
124 #[inline]
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 write!(f, "{}.{}.{}", self.major(), self.minor(), self.revision())
127 }
128}
129
130impl Debug for WSLVersion {
131 #[inline]
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 f.debug_struct(stringify!(WSLVersion))
134 .field("major", &self.major())
135 .field("minor", &self.minor())
136 .field("revision", &self.revision())
137 .finish()
138 }
139}
140
141impl FromStr for WSLVersion {
142 type Err = WSLVersionParseError;
143
144 #[inline]
145 #[expect(
146 clippy::indexing_slicing,
147 reason = "We check the length of `parts` before indexing it, so this is safe."
148 )]
149 fn from_str(s: &str) -> Result<Self, Self::Err> {
150 let parts: Vec<&str> = s.split('.').collect();
151 if !matches!(parts.len(), 2 | 3) {
152 return Err(WSLVersionParseError::InvalidFormat {
153 input: s.to_owned(),
154 });
155 }
156
157 let major = parts[0]
158 .parse::<u32>()
159 .map_err(|_| WSLVersionParseError::InvalidMajor {
160 input: s.to_owned(),
161 })?;
162 let minor = parts[1]
163 .parse::<u32>()
164 .map_err(|_| WSLVersionParseError::InvalidMinor {
165 input: s.to_owned(),
166 })?;
167 let revision = parts
168 .get(2)
169 .map(|s| s.parse::<u32>())
170 .transpose()
171 .map_err(|_| WSLVersionParseError::InvalidRevision {
172 input: s.to_owned(),
173 })?
174 .unwrap_or(0);
175
176 Ok(Self::new(major, minor, revision))
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183 use crate::utils::test_transparence;
184
185 #[test]
186 fn test_layouts() {
187 test_transparence::<wslpluginapi_sys::WSLVersion, WSLVersion>();
188 }
189
190 #[test]
191 fn test_from_str_rejects_invalid_format() {
192 let result = "2".parse::<WSLVersion>();
193
194 assert_eq!(
195 result,
196 Err(WSLVersionParseError::InvalidFormat {
197 input: "2".to_owned(),
198 })
199 );
200 }
201
202 #[test]
203 fn test_from_str_rejects_invalid_major() {
204 let result = "a.0.0".parse::<WSLVersion>();
205
206 assert_eq!(
207 result,
208 Err(WSLVersionParseError::InvalidMajor {
209 input: "a.0.0".to_owned(),
210 })
211 );
212 }
213
214 #[test]
215 fn test_from_str_rejects_invalid_minor() {
216 let result = "2.a.0".parse::<WSLVersion>();
217
218 assert_eq!(
219 result,
220 Err(WSLVersionParseError::InvalidMinor {
221 input: "2.a.0".to_owned(),
222 })
223 );
224 }
225
226 #[test]
227 fn test_from_str_rejects_invalid_revision() {
228 let result = "2.0.a".parse::<WSLVersion>();
229
230 assert_eq!(
231 result,
232 Err(WSLVersionParseError::InvalidRevision {
233 input: "2.0.a".to_owned(),
234 })
235 );
236 }
237}