1#![deny(warnings, unsafe_code)]
2#![cfg_attr(not(any(doc, test)), no_std)]
3
4#[cfg(feature = "alloc")]
5extern crate alloc;
6
7pub mod pieces;
8
9use core::{ops::Deref, str::FromStr};
10
11use pieces::*;
12
13#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
14pub struct CanonicalTarget {
15 pub arch: Architecture,
16 pub vendor: Option<Vendor>,
17 pub sys: System,
18}
19
20impl CanonicalTarget {
21 pub fn guess_vendor(&self) -> Vendor {
22 if let Some(vendor) = self.vendor {
23 return vendor;
24 }
25 match (self.arch, self.sys.os()) {
26 (
27 Architecture::X86_16(_) | Architecture::X86_32(_) | Architecture::X86_64 { .. },
28 _,
29 ) => Vendor::PC,
30 (Architecture::Wc65c816, _) => Vendor::WDC,
31 _ => Vendor::Unknown,
32 }
33 }
34}
35
36impl core::str::FromStr for CanonicalTarget {
37 type Err = UnknownError;
38
39 fn from_str(s: &str) -> Result<Self, Self::Err> {
40 let (arch, rest) = s.split_once('-').ok_or(UnknownError)?;
41
42 let arch = arch.parse::<Architecture>()?;
43
44 let (vendor, sys) = if let Some((a, b)) = rest.split_once('-') {
45 if b.contains('-') {
46 (Some(Vendor::parse(a)), b.parse::<System>()?)
48 } else if let Ok(sys) = rest.parse::<System>() {
49 (None, sys)
50 } else {
51 (Some(Vendor::parse(a)), b.parse::<System>()?)
52 }
53 } else {
54 (None, rest.parse::<System>()?)
55 };
56
57 Ok(CanonicalTarget { arch, vendor, sys })
58 }
59}
60
61impl core::fmt::Display for CanonicalTarget {
62 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
63 self.arch.fmt(f)?;
64 f.write_str("-")?;
65
66 self.guess_vendor().fmt(f)?;
67
68 f.write_str("-")?;
69
70 self.sys.fmt(f)
71 }
72}
73
74#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
75pub struct TargetRef<'a> {
76 exact: &'a str,
77 canon: CanonicalTarget,
78}
79
80impl<'a> Deref for TargetRef<'a> {
81 type Target = CanonicalTarget;
82
83 fn deref(&self) -> &CanonicalTarget {
84 &self.canon
85 }
86}
87
88impl<'a> TargetRef<'a> {
89 pub fn try_parse(st: &'a str) -> Result<Self, UnknownError> {
90 let canon = CanonicalTarget::from_str(st)?;
91
92 Ok(TargetRef { exact: st, canon })
93 }
94
95 pub fn parse(st: &'a str) -> Self {
96 match Self::try_parse(st) {
97 Ok(targ) => targ,
98 Err(_) => panic!("Unknown target: {}", st),
99 }
100 }
101
102 pub fn exact(&self) -> &'a str {
103 self.exact
104 }
105
106 pub fn canonical(&self) -> CanonicalTarget {
107 self.canon
108 }
109}
110
111#[cfg(feature = "alloc")]
112mod feature_alloc {
113 use core::{ops::Deref, str::FromStr};
114
115 use crate::{pieces::UnknownError, CanonicalTarget, TargetRef};
116 use alloc::string::{String, ToString};
117
118 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
119 pub struct OwnedTarget {
120 exact: String,
121 canon: CanonicalTarget,
122 }
123
124 impl<'a> Deref for OwnedTarget {
125 type Target = CanonicalTarget;
126
127 fn deref(&self) -> &CanonicalTarget {
128 &self.canon
129 }
130 }
131
132 impl OwnedTarget {
133 pub fn from_canonical(canon: CanonicalTarget) -> Self {
134 let exact = canon.to_string();
135
136 Self { exact, canon }
137 }
138 pub fn from_owned(st: String) -> Result<Self, UnknownError> {
139 let canon = CanonicalTarget::from_str(&st)?;
140
141 Ok(OwnedTarget { exact: st, canon })
142 }
143
144 pub fn into_exact(self) -> String {
145 self.exact
146 }
147
148 pub fn borrow<'a>(&'a self) -> TargetRef<'a> {
149 TargetRef {
150 exact: &self.exact,
151 canon: self.canon,
152 }
153 }
154 }
155
156 impl FromStr for OwnedTarget {
157 type Err = UnknownError;
158 fn from_str(s: &str) -> Result<Self, Self::Err> {
159 Self::from_owned(s.to_string())
160 }
161 }
162}
163
164#[cfg(feature = "alloc")]
165pub use feature_alloc::*;
166
167#[doc(hidden)]
168pub use core as __core;
169
170#[doc(hidden)]
171pub use target_tuples_macro::__match_targets;
172
173#[macro_export]
174macro_rules! match_targets {
175 {
176 $expr:tt {
177 $($inner:tt)*
178 }
179 } => {
180 $crate::__match_targets!([$crate] $expr {
181 $($inner)*
182 })
183 };
184}