11use std:: borrow:: Cow ;
2- use std:: env;
32use std:: num:: ParseIntError ;
3+ use std:: str:: FromStr ;
4+ use std:: { env, fmt} ;
5+
6+ use serde:: de;
47
58use crate :: spec:: {
69 Cc , DebuginfoKind , FramePointer , LinkerFlavor , Lld , SplitDebuginfo , StackProbeType , StaticCow ,
@@ -201,14 +204,15 @@ pub fn os_minimum_deployment_target(os: &str) -> OSVersion {
201204 // ```
202205 // $ rustc --print deployment-target
203206 // ```
204- match os {
207+ let ( major , minor , patch ) = match os {
205208 "macos" => ( 10 , 12 , 0 ) ,
206209 "ios" => ( 10 , 0 , 0 ) ,
207210 "tvos" => ( 10 , 0 , 0 ) ,
208211 "watchos" => ( 5 , 0 , 0 ) ,
209212 "visionos" => ( 1 , 0 , 0 ) ,
210213 _ => unreachable ! ( "tried to get deployment target for non-Apple platform" ) ,
211- }
214+ } ;
215+ OSVersion { major, minor, patch }
212216}
213217
214218/// The deployment target for the given target.
@@ -219,7 +223,7 @@ pub fn os_minimum_deployment_target(os: &str) -> OSVersion {
219223/// This matches what LLVM does, see in part:
220224/// <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L1900-L1932>
221225pub fn minimum_deployment_target ( target : & Target ) -> OSVersion {
222- match ( & * target. os , & * target. arch , & * target. abi ) {
226+ let ( major , minor , patch ) = match ( & * target. os , & * target. arch , & * target. abi ) {
223227 ( "macos" , "aarch64" , _) => ( 11 , 0 , 0 ) ,
224228 ( "ios" , "aarch64" , "macabi" ) => ( 14 , 0 , 0 ) ,
225229 ( "ios" , "aarch64" , "sim" ) => ( 14 , 0 , 0 ) ,
@@ -228,8 +232,9 @@ pub fn minimum_deployment_target(target: &Target) -> OSVersion {
228232 ( "ios" , _, "macabi" ) => ( 13 , 1 , 0 ) ,
229233 ( "tvos" , "aarch64" , "sim" ) => ( 14 , 0 , 0 ) ,
230234 ( "watchos" , "aarch64" , "sim" ) => ( 7 , 0 , 0 ) ,
231- ( os, _, _) => os_minimum_deployment_target ( os) ,
232- }
235+ ( os, _, _) => return os_minimum_deployment_target ( os) ,
236+ } ;
237+ OSVersion { major, minor, patch }
233238}
234239
235240/// Name of the environment variable used to fetch the deployment target on the given OS.
@@ -307,18 +312,68 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
307312/// Deployment target or SDK version.
308313///
309314/// The size of the numbers in here are limited by Mach-O's `LC_BUILD_VERSION`.
310- pub type OSVersion = ( u16 , u8 , u8 ) ;
311-
312- /// Parse an OS version triple (SDK version or deployment target).
313- pub fn parse_version ( version : & str ) -> Result < OSVersion , ParseIntError > {
314- if let Some ( ( major, minor) ) = version. split_once ( '.' ) {
315- let major = major. parse ( ) ?;
316- if let Some ( ( minor, patch) ) = minor. split_once ( '.' ) {
317- Ok ( ( major, minor. parse ( ) ?, patch. parse ( ) ?) )
315+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
316+ pub struct OSVersion {
317+ pub major : u16 ,
318+ pub minor : u8 ,
319+ pub patch : u8 ,
320+ }
321+
322+ impl OSVersion {
323+ pub const MIN : Self = Self { major : u16:: MIN , minor : u8:: MIN , patch : u8:: MIN } ;
324+
325+ pub const MAX : Self = Self { major : u16:: MAX , minor : u8:: MAX , patch : u8:: MAX } ;
326+
327+ pub fn pretty ( self ) -> impl fmt:: Display {
328+ let OSVersion { major, minor, patch } = self ;
329+ fmt:: from_fn ( move |f| {
330+ write ! ( f, "{major}.{minor}" ) ?;
331+ if patch != 0 {
332+ write ! ( f, ".{patch}" ) ?;
333+ }
334+ Ok ( ( ) )
335+ } )
336+ }
337+ }
338+
339+ impl < ' de > de:: Deserialize < ' de > for OSVersion {
340+ fn deserialize < D : de:: Deserializer < ' de > > ( deserializer : D ) -> Result < OSVersion , D :: Error > {
341+ struct OSVersionVisitor ;
342+
343+ impl < ' de > de:: Visitor < ' de > for OSVersionVisitor {
344+ type Value = OSVersion ;
345+
346+ fn expecting ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
347+ f. write_str ( "a valid `major.minor.patch` version" )
348+ }
349+
350+ fn visit_str < E : de:: Error > ( self , value : & str ) -> Result < Self :: Value , E > {
351+ OSVersion :: from_str ( value) . map_err ( E :: custom)
352+ }
353+ }
354+
355+ deserializer. deserialize_str ( OSVersionVisitor )
356+ }
357+ }
358+
359+ impl FromStr for OSVersion {
360+ type Err = ParseIntError ;
361+
362+ /// Parse an OS version triple (SDK version or deployment target).
363+ fn from_str ( version : & str ) -> Result < Self , Self :: Err > {
364+ if let Some ( ( major, minor) ) = version. split_once ( '.' ) {
365+ let major = major. parse ( ) ?;
366+ if let Some ( ( minor, patch) ) = minor. split_once ( '.' ) {
367+ let minor = minor. parse ( ) ?;
368+ let patch = patch. parse ( ) ?;
369+ Ok ( Self { major, minor, patch } )
370+ } else {
371+ let minor = minor. parse ( ) ?;
372+ Ok ( Self { major, minor, patch : 0 } )
373+ }
318374 } else {
319- Ok ( ( major, minor. parse ( ) ?, 0 ) )
375+ let major = version. parse ( ) ?;
376+ Ok ( Self { major, minor : 0 , patch : 0 } )
320377 }
321- } else {
322- Ok ( ( version. parse ( ) ?, 0 , 0 ) )
323378 }
324379}
0 commit comments