Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle targets with more than one family #44

Merged
merged 1 commit into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 23 additions & 14 deletions src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl TargetMatcher for targ::TargetInfo {
Some(e) => env == e,
None => env.0.is_empty(),
},
Family(fam) => Some(fam) == self.family.as_ref(),
Family(fam) => self.families.contains(fam),
Os(os) => Some(os) == self.os.as_ref(),
PointerWidth(w) => *w == self.pointer_width,
Vendor(ven) => match &self.vendor {
Expand Down Expand Up @@ -211,8 +211,8 @@ impl TargetMatcher for target_lexicon::Triple {
Netbsd, None_, Openbsd, Redox, Solaris, Tvos, Uefi, Unknown, VxWorks, Wasi,
Windows,
};
let lexicon_fam = match self.operating_system {
AmdHsa | Bitrig | Cloudabi | Cuda | Hermit | Nebulet | None_ | Uefi => None,
match self.operating_system {
AmdHsa | Bitrig | Cloudabi | Cuda | Hermit | Nebulet | None_ | Uefi => false,
Darwin
| Dragonfly
| Espidf
Expand All @@ -229,30 +229,39 @@ impl TargetMatcher for target_lexicon::Triple {
| Redox
| Solaris
| Tvos
| VxWorks => Some(crate::targets::Family::unix),
Emscripten | Unknown => {
| VxWorks => fam == &crate::targets::Family::unix,
Emscripten => {
match self.architecture {
// asmjs, wasm32 and wasm64 are part of both the wasm and unix families
Architecture::Asmjs | Architecture::Wasm32 => {
fam == &crate::targets::Family::wasm
|| fam == &crate::targets::Family::unix
}
_ => false,
}
}
Unknown => {
// asmjs, wasm32 and wasm64 are part of the wasm family.
match self.architecture {
Architecture::Asmjs | Architecture::Wasm32 | Architecture::Wasm64 => {
Some(crate::targets::Family::wasm)
fam == &crate::targets::Family::wasm
}
_ => None,
_ => false,
}
}
Linux => {
// The 'kernel' environment is treated specially as not-unix
if self.environment != Environment::Kernel {
Some(crate::targets::Family::unix)
fam == &crate::targets::Family::unix
} else {
None
false
}
}
Wasi => Some(crate::targets::Family::wasm),
Windows => Some(crate::targets::Family::windows),
Wasi => fam == &crate::targets::Family::wasm,
Windows => fam == &crate::targets::Family::windows,
// I really dislike non-exhaustive :(
_ => None,
};
Some(fam) == lexicon_fam.as_ref()
_ => false,
}
}
Os(os) => match os.0.parse::<OperatingSystem>() {
Ok(o) => match self.environment {
Expand Down
74 changes: 69 additions & 5 deletions src/targets.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::Reason;
use std::borrow::Cow;
use std::{borrow::Cow, ops::Deref};

mod builtins;

Expand All @@ -24,8 +24,8 @@ pub struct Vendor(pub Cow<'static, str>);
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Os(pub Cow<'static, str>);

/// The target family, which describes a set of targets grouped in some logical manner, typically by
/// operating system. This includes values like `unix` and `windows`.
/// Individual target families, which describe a set of targets grouped in some logical manner,
/// typically by operating system. This includes values like `unix` and `windows`.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Family(pub Cow<'static, str>);

Expand Down Expand Up @@ -81,6 +81,70 @@ field_impls!(Os);
field_impls!(Family);
field_impls!(Env);

/// A set of families for a target.
///
/// Each target can be part of one or more families. This struct represents them.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Families(Cow<'static, [Family]>);

impl Families {
/// Constructs a new instance.
///
/// This method accepts both owned `String`s and `&'static str`s.
///
/// If you have a `&'static [&'static str]`, prefer [`Self::new_const`].
#[inline]
pub fn new(val: impl IntoIterator<Item = Family>) -> Self {
let mut families: Vec<_> = val.into_iter().collect();
families.sort_unstable();
Self(Cow::Owned(families))
}

/// Constructs a new instance of this field from a static slice of `&'static str`.
///
/// `val` must be in sorted order: this constructor cannot check for that due to
/// limitations in current versions of Rust.
#[inline]
pub const fn new_const(val: &'static [Family]) -> Self {
// TODO: Check that val is sorted.
Self(Cow::Borrowed(val))
}

/// Returns true if this list of families contains a given family.
pub fn contains(&self, val: &Family) -> bool {
// This relies on the sorted-ness of its contents.
self.0.binary_search(val).is_ok()
}
}
Comment on lines +96 to +118
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the maximum for a reasonable target is 2, at least at this time, it feels like sorting/binary searching is unnecessary and should just be linear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Note that while the binary searching is probably unnecessary, the sorting is not: incorrectly sorted lists will cause the Eq, Hash and Ord implementations to behave incorrectly.


impl Deref for Families {
type Target = [Family];
fn deref(&self) -> &Self::Target {
&*self.0
}
}

impl AsRef<[Family]> for Families {
#[inline]
fn as_ref(&self) -> &[Family] {
&*self.0
}
}

impl std::fmt::Display for Families {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{{")?;
let len = self.0.len();
for (idx, family) in self.0.iter().enumerate() {
write!(f, "{}", family)?;
if idx + 1 < len {
write!(f, ", ")?;
}
}
write!(f, "}}")
}
}

macro_rules! target_enum {
(
$(#[$outer:meta])*
Expand Down Expand Up @@ -162,10 +226,10 @@ pub struct TargetInfo {
/// [target_vendor](https://doc.rust-lang.org/reference/conditional-compilation.html#target_vendor)
/// predicate.
pub vendor: Option<Vendor>,
/// The target's family, if any. Used by the
/// The target's families, if any. Used by the
/// [target_family](https://doc.rust-lang.org/reference/conditional-compilation.html#target_family)
/// predicate.
pub family: Option<Family>,
pub families: Families,
/// The size of the target's pointer type. Used by the
/// [target_pointer_width](https://doc.rust-lang.org/reference/conditional-compilation.html#target_pointer_width)
/// predicate.
Expand Down
Loading