1#![doc = include_str!(concat!(env!("OUT_DIR"), "/generated.md"))]
5#![no_std]
6
7include!(concat!(env!("OUT_DIR"), "/generated.rs"));
8
9pub mod docs {
11 include!(concat!(env!("OUT_DIR"), "/docs.rs"));
12}
13
14mod simd;
15pub use simd::*;
16
17const fn str_eq(a: &str, b: &str) -> bool {
18 let a = a.as_bytes();
19 let b = b.as_bytes();
20
21 if a.len() != b.len() {
22 return false;
23 }
24
25 let mut i = 0;
26 while i < a.len() {
27 if a[i] != b[i] {
28 return false;
29 }
30 i += 1;
31 }
32 true
33}
34
35#[derive(Copy, Clone, PartialEq, Eq, Debug)]
37pub enum Architecture {
38 Arm,
40 AArch64,
42 Bpf,
44 Hexagon,
46 Mips,
48 PowerPC,
50 RiscV,
52 Wasm,
54 X86,
56 Unsupported,
58}
59
60impl Architecture {
61 pub const fn from_str(architecture: &str) -> Self {
63 if str_eq(architecture, "arm") {
64 Self::Arm
65 } else if str_eq(architecture, "aarch64") {
66 Self::AArch64
67 } else if str_eq(architecture, "bpf") {
68 Self::Bpf
69 } else if str_eq(architecture, "hexagon") {
70 Self::Hexagon
71 } else if str_eq(architecture, "mips") || str_eq(architecture, "mips64") {
72 Self::Mips
73 } else if str_eq(architecture, "powerpc") || str_eq(architecture, "powerpc64") {
74 Self::PowerPC
75 } else if str_eq(architecture, "riscv32") || str_eq(architecture, "riscv64") {
76 Self::RiscV
77 } else if str_eq(architecture, "wasm32") || str_eq(architecture, "wasm64") {
78 Self::Wasm
79 } else if str_eq(architecture, "x86") || str_eq(architecture, "x86_64") {
80 Self::X86
81 } else {
82 Self::Unsupported
83 }
84 }
85}
86
87#[derive(Copy, Clone, Debug)]
89pub struct UnknownFeature;
90
91impl core::fmt::Display for UnknownFeature {
92 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
93 write!(f, "unknown target feature")
94 }
95}
96
97#[derive(Copy, Clone, Debug)]
99pub struct UnknownCpu;
100
101impl core::fmt::Display for UnknownCpu {
102 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
103 write!(f, "unknown target CPU")
104 }
105}
106
107#[derive(Copy, Clone, PartialEq, Eq)]
109pub struct Feature(usize);
110
111impl core::fmt::Debug for Feature {
112 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
113 f.debug_struct("Feature")
114 .field("architecture", &self.architecture())
115 .field("name", &self.name())
116 .finish()
117 }
118}
119
120impl Feature {
121 pub const fn new(architecture: Architecture, feature: &str) -> Result<Self, UnknownFeature> {
123 let mut i = 0;
124 while i < FEATURES.len() {
125 if (architecture as u8) == (FEATURES[i].0 as u8) && str_eq(feature, FEATURES[i].1) {
126 return Ok(Self(i));
127 }
128 i += 1;
129 }
130
131 Err(UnknownFeature)
132 }
133
134 pub const fn name(&self) -> &'static str {
136 FEATURES[self.0].1
137 }
138
139 pub const fn architecture(&self) -> Architecture {
141 FEATURES[self.0].0
142 }
143
144 pub const fn description(&self) -> &'static str {
146 FEATURES[self.0].2
147 }
148
149 pub const fn implies(&self) -> &'static [Feature] {
153 FEATURES[self.0].3
154 }
155}
156
157pub struct FeaturesIter {
159 target: Target,
160 index: usize,
161}
162
163impl Iterator for FeaturesIter {
164 type Item = Feature;
165
166 fn next(&mut self) -> Option<Self::Item> {
167 while self.index < self.target.features.len() {
168 let feature = if self.target.features[self.index] {
169 Some(Feature(self.index))
170 } else {
171 None
172 };
173 self.index += 1;
174 if feature.is_some() {
175 return feature;
176 }
177 }
178 None
179 }
180}
181
182impl core::fmt::Debug for Target {
183 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
184 struct FeaturesHelper(Target);
185 impl core::fmt::Debug for FeaturesHelper {
186 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
187 f.debug_list().entries(self.0.features()).finish()
188 }
189 }
190
191 f.debug_struct("Target")
192 .field("architecture", &self.architecture())
193 .field("features", &FeaturesHelper(*self))
194 .finish()
195 }
196}
197
198#[derive(Copy, Clone, PartialEq, Eq)]
200pub struct Target {
201 architecture: Architecture,
202 features: [bool; FEATURES.len()],
203}
204
205impl Target {
206 pub const fn new(architecture: Architecture) -> Self {
208 Self {
209 architecture,
210 features: [false; FEATURES.len()],
211 }
212 }
213
214 pub const fn from_cpu(architecture: Architecture, cpu: &str) -> Result<Self, UnknownCpu> {
216 let mut target = Self::new(architecture);
217 let mut i = 0;
218 while i < CPUS.len() {
219 if architecture as u8 == CPUS[i].0 as u8 && str_eq(cpu, CPUS[i].1) {
220 let mut j = 0;
221 while j < CPUS[i].2.len() {
222 target = target.with_feature(CPUS[i].2[j]);
223 j += 1;
224 }
225 return Ok(target);
226 }
227 i += 1;
228 }
229 Err(UnknownCpu)
230 }
231
232 pub const fn architecture(&self) -> Architecture {
234 self.architecture
235 }
236
237 pub const fn features(&self) -> FeaturesIter {
239 FeaturesIter {
240 target: *self,
241 index: 0,
242 }
243 }
244
245 pub const fn supports_feature(&self, feature: Feature) -> bool {
247 self.features[feature.0]
248 }
249
250 pub const fn supports_feature_str(&self, feature: &str) -> bool {
255 if let Ok(feature) = Feature::new(self.architecture, feature) {
256 self.supports_feature(feature)
257 } else {
258 panic!("unknown feature");
259 }
260 }
261
262 pub const fn with_feature(mut self, feature: Feature) -> Self {
267 assert!(feature.architecture() as u8 == self.architecture as u8);
268 self.features[feature.0] = true;
269
270 let mut i = 0;
271 let implies = feature.implies();
272 while i < implies.len() {
273 self.features[implies[i].0] = true;
274 i += 1;
275 }
276
277 self
278 }
279
280 pub const fn with_feature_str(self, feature: &str) -> Self {
285 if let Ok(feature) = Feature::new(self.architecture, feature) {
286 self.with_feature(feature)
287 } else {
288 panic!("unknown feature");
289 }
290 }
291}