diff options
Diffstat (limited to 'servo/components/selectors/kleene_value.rs')
-rw-r--r-- | servo/components/selectors/kleene_value.rs | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/servo/components/selectors/kleene_value.rs b/servo/components/selectors/kleene_value.rs new file mode 100644 index 0000000000..58141c1156 --- /dev/null +++ b/servo/components/selectors/kleene_value.rs @@ -0,0 +1,131 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +//! Kleen logic: https://en.wikipedia.org/wiki/Three-valued_logic#Kleene_and_Priest_logics + +/// A "trilean" value based on Kleen logic. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum KleeneValue { + /// False + False = 0, + /// True + True = 1, + /// Either true or false, but we’re not sure which yet. + Unknown, +} + +impl From<bool> for KleeneValue { + fn from(b: bool) -> Self { + if b { + Self::True + } else { + Self::False + } + } +} + +impl KleeneValue { + /// Turns this Kleene value to a bool, taking the unknown value as an + /// argument. + pub fn to_bool(self, unknown: bool) -> bool { + match self { + Self::True => true, + Self::False => false, + Self::Unknown => unknown, + } + } + + /// Return true if any result of f() is true. Otherwise, return the strongest value seen. + /// Returns false if empty, like that of `Iterator`. + pub fn any<T>( + iter: impl Iterator<Item = T>, + f: impl FnMut(T) -> Self, + ) -> Self { + Self::any_value(iter, Self::True, Self::False, f) + } + + /// Return false if any results of f() is false. Otherwise, return the strongest value seen. + /// Returns true if empty, opposite of `Iterator`. + pub fn any_false<T>( + iter: impl Iterator<Item = T>, + f: impl FnMut(T) -> Self, + ) -> Self { + Self::any_value(iter, Self::False, Self::True, f) + } + + fn any_value<T>( + iter: impl Iterator<Item = T>, + value: Self, + on_empty: Self, + mut f: impl FnMut(T) -> Self, + ) -> Self { + let mut result = None; + for item in iter { + let r = f(item); + if r == value { + return r; + } + if let Some(v) = result.as_mut() { + *v = *v & r; + } else { + result = Some(r); + } + } + result.unwrap_or(on_empty) + } +} + +impl std::ops::Not for KleeneValue { + type Output = Self; + + fn not(self) -> Self { + match self { + Self::True => Self::False, + Self::False => Self::True, + Self::Unknown => Self::Unknown, + } + } +} + +// Implements the logical and operation. +impl std::ops::BitAnd for KleeneValue { + type Output = Self; + + fn bitand(self, other: Self) -> Self { + if self == Self::False || other == Self::False { + return Self::False; + } + if self == Self::Unknown || other == Self::Unknown { + return Self::Unknown; + } + Self::True + } +} + +// Implements the logical or operation. +impl std::ops::BitOr for KleeneValue { + type Output = Self; + + fn bitor(self, other: Self) -> Self { + if self == Self::True || other == Self::True { + return Self::True; + } + if self == Self::Unknown || other == Self::Unknown { + return Self::Unknown; + } + Self::False + } +} + +impl std::ops::BitOrAssign for KleeneValue { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +impl std::ops::BitAndAssign for KleeneValue { + fn bitand_assign(&mut self, other: Self) { + *self = *self & other; + } +} |