11use std:: borrow:: Cow ;
2+ use std:: fmt;
23use std:: num:: ParseIntError ;
4+ use std:: str:: FromStr ;
5+
6+ use serde:: de;
37
48use crate :: spec:: {
59 Cc , DebuginfoKind , FramePointer , LinkerFlavor , Lld , SplitDebuginfo , StackProbeType , StaticCow ,
@@ -200,14 +204,15 @@ pub fn os_minimum_deployment_target(os: &str) -> OSVersion {
200204 // ```
201205 // $ rustc --print deployment-target
202206 // ```
203- match os {
207+ let ( major , minor , patch ) = match os {
204208 "macos" => ( 10 , 12 , 0 ) ,
205209 "ios" => ( 10 , 0 , 0 ) ,
206210 "tvos" => ( 10 , 0 , 0 ) ,
207211 "watchos" => ( 5 , 0 , 0 ) ,
208212 "visionos" => ( 1 , 0 , 0 ) ,
209213 _ => unreachable ! ( "tried to get deployment target for non-Apple platform" ) ,
210- }
214+ } ;
215+ OSVersion { major, minor, patch }
211216}
212217
213218/// The deployment target for the given target.
@@ -218,7 +223,7 @@ pub fn os_minimum_deployment_target(os: &str) -> OSVersion {
218223/// This matches what LLVM does, see in part:
219224/// <https://github.com/llvm/llvm-project/blob/llvmorg-18.1.8/llvm/lib/TargetParser/Triple.cpp#L1900-L1932>
220225pub 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 ) {
222227 ( "macos" , "aarch64" , _) => ( 11 , 0 , 0 ) ,
223228 ( "ios" , "aarch64" , "macabi" ) => ( 14 , 0 , 0 ) ,
224229 ( "ios" , "aarch64" , "sim" ) => ( 14 , 0 , 0 ) ,
@@ -227,8 +232,9 @@ pub fn minimum_deployment_target(target: &Target) -> OSVersion {
227232 ( "ios" , _, "macabi" ) => ( 13 , 1 , 0 ) ,
228233 ( "tvos" , "aarch64" , "sim" ) => ( 14 , 0 , 0 ) ,
229234 ( "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 }
232238}
233239
234240/// 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>]> {
287293/// Deployment target or SDK version.
288294///
289295/// 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+ }
298355 } else {
299- Ok ( ( major, minor. parse ( ) ?, 0 ) )
356+ let major = version. parse ( ) ?;
357+ Ok ( Self { major, minor : 0 , patch : 0 } )
300358 }
301- } else {
302- Ok ( ( version. parse ( ) ?, 0 , 0 ) )
303359 }
304360}
0 commit comments