Skip to content

Instantly share code, notes, and snippets.

@cameronp98
Created September 1, 2019 17:50
Show Gist options
  • Save cameronp98/d8b9ff54ed95f7bd933870e93366a87c to your computer and use it in GitHub Desktop.
Save cameronp98/d8b9ff54ed95f7bd933870e93366a87c to your computer and use it in GitHub Desktop.
Filter a collection of elements against a query constructed using the 'builder' pattern
use std::ops::Range;
#[derive(Debug)]
pub struct Person {
name: String,
age: u64,
}
impl Person {
fn new(name: String, age: u64) -> Person {
Person { name, age }
}
}
enum AgeCriteria {
InRange(u64, u64),
Exact(u64),
}
pub struct PersonCriteria {
name: Option<String>,
age: Option<AgeCriteria>,
}
impl PersonCriteria {
fn new() -> PersonCriteria {
PersonCriteria {
name: None,
age: None,
}
}
fn name(self, name: String) -> Self {
PersonCriteria {
name: Some(name),
..self
}
}
fn age_exact(self, age: u64) -> Self {
PersonCriteria {
age: Some(AgeCriteria::Exact(age)),
..self
}
}
fn age_range(self, min: u64, max: u64) -> Self {
PersonCriteria {
age: Some(AgeCriteria::InRange(min, max)),
..self
}
}
fn matches(&self, p: &Person) -> bool {
// match name
if let Some(ref name) = self.name {
if p.name != *name { return false };
}
// match age
if let Some(ref age_crit) = self.age {
match age_crit {
AgeCriteria::Exact(age) => if *age == p.age { return false },
AgeCriteria::InRange(min, max) => if p.age < *min || p.age > *max { return false },
}
}
true
}
}
struct PersonList {
people: Vec<Person>,
}
impl<'a> PersonList {
fn new() -> PersonList {
PersonList {
people: vec![],
}
}
fn add(&mut self, p: Person) {
self.people.push(p);
}
fn find_all(&'a self, criteria: PersonCriteria) -> impl Iterator<Item=&'a Person> {
self.people.iter().filter(move |p| criteria.matches(p))
}
}
fn main() {
let mut people = PersonList::new();
people.add(Person::new("Barry".to_string(), 50));
people.add(Person::new("Bob".to_string(), 20));
people.add(Person::new("Bob".to_string(), 30));
people.add(Person::new("Bob".to_string(), 32));
people.add(Person::new("Bob".to_string(), 16));
let criteria = PersonCriteria::new()
.age_range(20, 30)
.name("Bob".to_string());
println!("{:#?}", people.find_all(criteria).collect::<Vec<_>>());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment