use crate::platform::{Platform, PlatformSpec};
use std::ops::{BitAnd, BitOr};
use target_spec::TargetSpec;
#[derive(Copy, Clone, Debug)]
pub enum PlatformStatus<'g> {
Never,
Always,
PlatformDependent {
eval: PlatformEval<'g>,
},
}
assert_covariant!(PlatformStatus);
impl<'g> PlatformStatus<'g> {
pub(crate) fn new(specs: &'g PlatformStatusImpl) -> Self {
match specs {
PlatformStatusImpl::Always => PlatformStatus::Always,
PlatformStatusImpl::Specs(specs) => {
if specs.is_empty() {
PlatformStatus::Never
} else {
PlatformStatus::PlatformDependent {
eval: PlatformEval { specs },
}
}
}
}
}
pub fn is_always(&self) -> bool {
match self {
PlatformStatus::Always => true,
PlatformStatus::PlatformDependent { .. } | PlatformStatus::Never => false,
}
}
pub fn is_never(&self) -> bool {
match self {
PlatformStatus::Never => true,
PlatformStatus::PlatformDependent { .. } | PlatformStatus::Always => false,
}
}
pub fn is_present(&self) -> bool {
!self.is_never()
}
pub fn enabled_on(&self, platform_spec: &PlatformSpec) -> EnabledTernary {
match (self, platform_spec) {
(PlatformStatus::Always, _) => EnabledTernary::Enabled,
(PlatformStatus::Never, _) => EnabledTernary::Disabled,
(PlatformStatus::PlatformDependent { .. }, PlatformSpec::Any) => {
EnabledTernary::Enabled
}
(PlatformStatus::PlatformDependent { eval }, PlatformSpec::Platform(platform)) => {
eval.eval(platform)
}
(PlatformStatus::PlatformDependent { .. }, PlatformSpec::Always) => {
EnabledTernary::Disabled
}
}
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum EnabledTernary {
Disabled,
Unknown,
Enabled,
}
impl EnabledTernary {
fn new(x: Option<bool>) -> Self {
match x {
Some(false) => EnabledTernary::Disabled,
None => EnabledTernary::Unknown,
Some(true) => EnabledTernary::Enabled,
}
}
pub fn is_known(self) -> bool {
match self {
EnabledTernary::Disabled | EnabledTernary::Enabled => true,
EnabledTernary::Unknown => false,
}
}
}
impl BitAnd for EnabledTernary {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
use EnabledTernary::*;
match (self, rhs) {
(Enabled, Enabled) => Enabled,
(Disabled, _) | (_, Disabled) => Disabled,
_ => Unknown,
}
}
}
impl BitOr for EnabledTernary {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
use EnabledTernary::*;
match (self, rhs) {
(Disabled, Disabled) => Disabled,
(Enabled, _) | (_, Enabled) => Enabled,
_ => Unknown,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct PlatformEval<'g> {
specs: &'g [TargetSpec],
}
assert_covariant!(PlatformEval);
impl<'g> PlatformEval<'g> {
pub fn eval(&self, platform: &Platform) -> EnabledTernary {
let mut res = EnabledTernary::Disabled;
for spec in self.specs.iter() {
let matches = spec.eval(platform);
if matches == Some(true) {
return EnabledTernary::Enabled;
}
res = res | EnabledTernary::new(matches);
}
res
}
pub fn target_specs(&self) -> &'g [TargetSpec] {
self.specs
}
}
#[derive(Clone, Debug)]
pub(crate) enum PlatformStatusImpl {
Always,
Specs(Vec<TargetSpec>),
}
impl PlatformStatusImpl {
pub(crate) fn is_never(&self) -> bool {
match self {
PlatformStatusImpl::Always => false,
PlatformStatusImpl::Specs(specs) => specs.is_empty(),
}
}
pub(crate) fn extend(&mut self, other: &PlatformStatusImpl) {
match (&mut *self, other) {
(PlatformStatusImpl::Always, _) => {
}
(PlatformStatusImpl::Specs(_), PlatformStatusImpl::Always) => {
*self = PlatformStatusImpl::Always;
}
(PlatformStatusImpl::Specs(specs), PlatformStatusImpl::Specs(other)) => {
specs.extend_from_slice(other.as_slice());
}
}
}
pub(crate) fn add_spec(&mut self, spec: Option<&TargetSpec>) {
match (&mut *self, spec) {
(PlatformStatusImpl::Always, _) => {
}
(PlatformStatusImpl::Specs(_), None) => {
*self = PlatformStatusImpl::Always;
}
(PlatformStatusImpl::Specs(specs), Some(spec)) => {
specs.push(spec.clone());
}
}
}
}
impl Default for PlatformStatusImpl {
fn default() -> Self {
PlatformStatusImpl::Specs(vec![])
}
}