1
1
use std:: borrow:: Cow ;
2
+ use std:: fmt;
2
3
use std:: num:: ParseIntError ;
4
+ use std:: str:: FromStr ;
5
+
6
+ use serde:: de;
3
7
4
8
use crate :: spec:: {
5
9
Cc , DebuginfoKind , FramePointer , LinkerFlavor , Lld , SplitDebuginfo , StackProbeType , StaticCow ,
@@ -200,14 +204,15 @@ pub fn os_minimum_deployment_target(os: &str) -> OSVersion {
200
204
// ```
201
205
// $ rustc --print deployment-target
202
206
// ```
203
- match os {
207
+ let ( major , minor , patch ) = match os {
204
208
"macos" => ( 10 , 12 , 0 ) ,
205
209
"ios" => ( 10 , 0 , 0 ) ,
206
210
"tvos" => ( 10 , 0 , 0 ) ,
207
211
"watchos" => ( 5 , 0 , 0 ) ,
208
212
"visionos" => ( 1 , 0 , 0 ) ,
209
213
_ => unreachable ! ( "tried to get deployment target for non-Apple platform" ) ,
210
- }
214
+ } ;
215
+ OSVersion { major, minor, patch }
211
216
}
212
217
213
218
/// The deployment target for the given target.
@@ -218,7 +223,7 @@ pub fn os_minimum_deployment_target(os: &str) -> OSVersion {
218
223
/// This matches what LLVM does, see in part:
219
224
/// <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L1900-L1932>
220
225
pub fn minimum_deployment_target ( target : & Target ) -> OSVersion {
221
- match ( & * target. os , & * target. arch , & * target. abi ) {
226
+ let ( major , minor , patch ) = match ( & * target. os , & * target. arch , & * target. abi ) {
222
227
( "macos" , "aarch64" , _) => ( 11 , 0 , 0 ) ,
223
228
( "ios" , "aarch64" , "macabi" ) => ( 14 , 0 , 0 ) ,
224
229
( "ios" , "aarch64" , "sim" ) => ( 14 , 0 , 0 ) ,
@@ -227,8 +232,9 @@ pub fn minimum_deployment_target(target: &Target) -> OSVersion {
227
232
( "ios" , _, "macabi" ) => ( 13 , 1 , 0 ) ,
228
233
( "tvos" , "aarch64" , "sim" ) => ( 14 , 0 , 0 ) ,
229
234
( "watchos" , "aarch64" , "sim" ) => ( 7 , 0 , 0 ) ,
230
- ( os, _, _) => os_minimum_deployment_target ( os) ,
231
- }
235
+ ( os, _, _) => return os_minimum_deployment_target ( os) ,
236
+ } ;
237
+ OSVersion { major, minor, patch }
232
238
}
233
239
234
240
/// Name of the environment variable used to fetch the deployment target on the given OS.
@@ -287,18 +293,68 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
287
293
/// Deployment target or SDK version.
288
294
///
289
295
/// The size of the numbers in here are limited by Mach-O's `LC_BUILD_VERSION`.
290
- pub type OSVersion = ( u16 , u8 , u8 ) ;
291
-
292
- /// Parse an OS version triple (SDK version or deployment target).
293
- pub fn parse_version ( version : & str ) -> Result < OSVersion , ParseIntError > {
294
- if let Some ( ( major, minor) ) = version. split_once ( '.' ) {
295
- let major = major. parse ( ) ?;
296
- if let Some ( ( minor, patch) ) = minor. split_once ( '.' ) {
297
- Ok ( ( major, minor. parse ( ) ?, patch. parse ( ) ?) )
296
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
297
+ pub struct OSVersion {
298
+ pub major : u16 ,
299
+ pub minor : u8 ,
300
+ pub patch : u8 ,
301
+ }
302
+
303
+ impl OSVersion {
304
+ pub const MIN : Self = Self { major : u16:: MIN , minor : u8:: MIN , patch : u8:: MIN } ;
305
+
306
+ pub const MAX : Self = Self { major : u16:: MAX , minor : u8:: MAX , patch : u8:: MAX } ;
307
+
308
+ pub fn pretty ( self ) -> impl fmt:: Display {
309
+ let OSVersion { major, minor, patch } = self ;
310
+ fmt:: from_fn ( move |f| {
311
+ write ! ( f, "{major}.{minor}" ) ?;
312
+ if patch != 0 {
313
+ write ! ( f, ".{patch}" ) ?;
314
+ }
315
+ Ok ( ( ) )
316
+ } )
317
+ }
318
+ }
319
+
320
+ impl < ' de > de:: Deserialize < ' de > for OSVersion {
321
+ fn deserialize < D : de:: Deserializer < ' de > > ( deserializer : D ) -> Result < OSVersion , D :: Error > {
322
+ struct OSVersionVisitor ;
323
+
324
+ impl < ' de > de:: Visitor < ' de > for OSVersionVisitor {
325
+ type Value = OSVersion ;
326
+
327
+ fn expecting ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
328
+ f. write_str ( "a valid `major.minor.patch` version" )
329
+ }
330
+
331
+ fn visit_str < E : de:: Error > ( self , value : & str ) -> Result < Self :: Value , E > {
332
+ OSVersion :: from_str ( value) . map_err ( E :: custom)
333
+ }
334
+ }
335
+
336
+ deserializer. deserialize_str ( OSVersionVisitor )
337
+ }
338
+ }
339
+
340
+ impl FromStr for OSVersion {
341
+ type Err = ParseIntError ;
342
+
343
+ /// Parse an OS version triple (SDK version or deployment target).
344
+ fn from_str ( version : & str ) -> Result < Self , Self :: Err > {
345
+ if let Some ( ( major, minor) ) = version. split_once ( '.' ) {
346
+ let major = major. parse ( ) ?;
347
+ if let Some ( ( minor, patch) ) = minor. split_once ( '.' ) {
348
+ let minor = minor. parse ( ) ?;
349
+ let patch = patch. parse ( ) ?;
350
+ Ok ( Self { major, minor, patch } )
351
+ } else {
352
+ let minor = minor. parse ( ) ?;
353
+ Ok ( Self { major, minor, patch : 0 } )
354
+ }
298
355
} else {
299
- Ok ( ( major, minor. parse ( ) ?, 0 ) )
356
+ let major = version. parse ( ) ?;
357
+ Ok ( Self { major, minor : 0 , patch : 0 } )
300
358
}
301
- } else {
302
- Ok ( ( version. parse ( ) ?, 0 , 0 ) )
303
359
}
304
360
}
0 commit comments