Initial sketch of user-defined short-circuiting && and || operators in Rust.
trait And<Rhs=Self> { | |
type Output; | |
fn short(&self) -> Option<Self::Output>; | |
fn and(self, rhs: Rhs) -> Self::Output; | |
} | |
trait Or<Rhs=Self> { | |
type Output; | |
fn short(&self) -> Option<Self::Output>; | |
fn or(self, rhs: Rhs) -> Self::Output; | |
} | |
impl And for bool { | |
type Output = bool; | |
fn short(&self) -> Option<bool> { | |
match *self { | |
false => Some(false), | |
true => None, | |
} | |
} | |
fn and(self, rhs: bool) -> bool { | |
match (self, rhs) { | |
(true, true) => true, | |
_ => false, | |
} | |
} | |
} | |
impl Or for bool { | |
type Output = bool; | |
fn short(&self) -> Option<bool> { | |
match *self { | |
true => Some(true), | |
false => None, | |
} | |
} | |
fn or(self, rhs: bool) -> bool { | |
match (self, rhs) { | |
(false, false) => false, | |
_ => true, | |
} | |
} | |
} | |
macro_rules! and { | |
($a:expr, $b:expr) => {{ | |
let a = $a; | |
match And::short(&a) { | |
Some(v) => v, | |
None => And::and(a, $b), | |
} | |
}} | |
} | |
macro_rules! or { | |
($a:expr, $b:expr) => {{ | |
let a = $a; | |
match Or::short(&a) { | |
Some(v) => v, | |
None => Or::or(a, $b), | |
} | |
}} | |
} | |
// ---- | |
#[derive(Debug, Clone, Copy)] | |
enum Tri { | |
False = -1, | |
None = 0, | |
True = 1, | |
} | |
impl And for Tri { | |
type Output = Tri; | |
fn short(&self) -> Option<Tri> { | |
println!(" and-short({:?})", self); | |
match *self { | |
Tri::False => Some(Tri::False), | |
_ => None, | |
} | |
} | |
fn and(self, rhs: Tri) -> Tri { | |
println!(" and({:?}, {:?})", self, rhs); | |
match (self, rhs) { | |
(Tri::False, _) | | |
(_, Tri::False) => Tri::False, | |
(Tri::None, _) | | |
(_, Tri::None) => Tri::None, | |
(Tri::True, Tri::True) => Tri::True, | |
} | |
} | |
} | |
impl Or for Tri { | |
type Output = Tri; | |
fn short(&self) -> Option<Tri> { | |
println!(" or-short({:?})", self); | |
match *self { | |
Tri::True => Some(Tri::True), | |
_ => None, | |
} | |
} | |
fn or(self, rhs: Tri) -> Tri { | |
println!(" or({:?}, {:?})", self, rhs); | |
match (self, rhs) { | |
(Tri::True, _) | | |
(_, Tri::True) => Tri::True, | |
(Tri::None, _) | | |
(_, Tri::None) => Tri::None, | |
(Tri::False, Tri::False) => Tri::False, | |
} | |
} | |
} | |
fn main() { | |
for l in [Tri::False, Tri::None, Tri::True].iter().cloned() { | |
for r in [Tri::False, Tri::None, Tri::True].iter().cloned() { | |
println!("{:?} && {:?}", l, r); | |
println!(" {:?}", and!(l, { | |
println!(" rhs evaluated"); | |
r | |
})); | |
println!("{:?} || {:?}", l, r); | |
println!(" {:?}", or!(l, { | |
println!(" rhs evaluated"); | |
r | |
})); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment