Skip to content

Instantly share code, notes, and snippets.

@mxgrey
Last active February 19, 2023 06:17
Show Gist options
  • Select an option

  • Save mxgrey/992a48150bba909cf86d0e196589b2f0 to your computer and use it in GitHub Desktop.

Select an option

Save mxgrey/992a48150bba909cf86d0e196589b2f0 to your computer and use it in GitHub Desktop.
Sketch of optional trait bounds idea for Rust
fn serve_customer<C>(mut customer: &C) -> u32
where
// When a trait bound is wrapped in [], that means it's optional
C: Noisy + [Hungry] + [Thirsty]
{
// Mandatory trait bounds can always be called
let order = customer.talk();
let food_price: u32 = with C as Hungry {
// This block only gets compiled if C implements Hungry.
// Otherwise, only the else block will be compiled.
let food_order: C::Food = order.into();
let food_price = food_order.price();
customer.eat(food_order);
food_price
} else {
0
};
let drink_price: u32 = with C as Thirsty {
// This block only gets compiled if C implements Thirsty.
let drink_order: C::Drink = order.into();
let drink_price = drink_order.price();
customer.drink(drink_order);
drink_price
} else {
0
};
let price = with C as Hungry + Thirsty {
// This block only gets compiled if C implements both Hungry and Thirsty.
// Apply a set meal discount
let sum = food_price + drink_price;
sum - sum/10
} else {
food_price + drink_price
};
price
}
trait Noisy {
fn talk(&self) -> Order;
}
trait Costly {
fn price(&self) -> u32;
}
trait Hungry {
type Food: From<Order> + Costly;
fn eat(&mut self, food: Self::Food);
}
trait Thirsty {
type Drink: From<Order> + Costly;
fn drink(&mut self, drink: Self::Drink);
}
#[derive(Clone, Copy)]
struct Order { /* ignore details */ }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment