Skip to content

Instantly share code, notes, and snippets.

@SpaceManiac
Created September 17, 2016 23:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SpaceManiac/35565f1516ed1adc03ade2c9461398a1 to your computer and use it in GitHub Desktop.
Save SpaceManiac/35565f1516ed1adc03ade2c9461398a1 to your computer and use it in GitHub Desktop.
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