Skip to content

Instantly share code, notes, and snippets.

@mmstick
Last active May 30, 2017 20:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmstick/3dcece7ff31d739cdb48f0b1f333f3cb to your computer and use it in GitHub Desktop.
Save mmstick/3dcece7ff31d739cdb48f0b1f333f3cb to your computer and use it in GitHub Desktop.
An example implementation of a friends list without shared references.
use std::collections::{HashSet, HashMap};
struct Person {
/// The unique name of this person that no other person may have.
name: String,
/// Use of a `HashSet` ensures that a friend is never listed twice.
friends: HashSet<usize>,
}
#[derive(Debug)]
enum PeopleErr {
PersonDoesNotExist
}
struct People {
/// Positions are unique IDs for each respective person.
/// When a person is removed, replace their value with None.
people: Vec<Option<Person>>,
/// In the event that you do not know the ID, perform a lookup
/// based on the name of that person.
lookup: HashMap<String, usize>
}
impl People {
/// If an empty position is available, add the person in that position.
/// Otherwise, add them at the end of the list.
fn add_person(&mut self, name: String) -> usize {
let new_person = Person {
name: name,
friends: HashSet::new()
};
let mut pos = 0;
for person in &mut self.people {
if let Some(_) = *person {
pos += 1;
continue
}
self.lookup.insert(new_person.name.clone(), pos);
*person = Some(new_person);
return pos;
}
self.lookup.insert(new_person.name.clone(), pos);
self.people.push(Some(new_person));
pos
}
/// Given two people, adds them as friends to each other.
fn add_friends(&mut self, a_id: usize, b_id: usize) -> Result<(), PeopleErr> {
// Check if person A exists.
match self.people.get(a_id) {
Some(&Some(_)) => (),
_ => return Err(PeopleErr::PersonDoesNotExist)
}
// Check if person B exists.
match self.people.get(b_id) {
Some(&Some(_)) => (),
_ => return Err(PeopleErr::PersonDoesNotExist)
}
{ // Add person B to person A's friends list.
let person_a = self.get_person_mut(a_id).unwrap();
person_a.friends.insert(b_id);
}
{ // Add person A to person B's friends list.
let person_b = self.get_person_mut(b_id).unwrap();
person_b.friends.insert(a_id);
}
Ok(())
}
/// Obtain the ID of the associated person's name, if they exist.
fn get_id(&self, name: &str) -> Option<usize> {
self.lookup.get(name).cloned()
}
/// Get an immutable reference to a person by their ID.
fn get_person<'p>(&'p self, id: usize) -> Option<&'p Person> {
match self.people.get(id) {
Some(people) => people.as_ref(),
None => None
}
}
/// Get a mutable reference to a person by their ID.
fn get_person_mut<'p>(&'p mut self, id: usize) -> Option<&'p mut Person> {
match self.people.get_mut(id) {
Some(people) => people.as_mut(),
None => None
}
}
fn new() -> People {
People { people: Vec::new(), lookup: HashMap::new() }
}
}
fn main() {
// Initialize the list of people.
let mut people = People::new();
let spongebob = people.add_person("Spongebob".into());
let patrick = people.add_person("Patrick".into());
let sandy = people.add_person("Sandy".into());
// Make them friends of each other.
people.add_friends(spongebob, patrick).unwrap();
people.add_friends(spongebob, sandy).unwrap();
// Exchange ID's for temporary references. This one is immutable.
if let Some(ref person) = people.get_person(spongebob) {
println!("Friends of {}:", person.name);
for friend in person.friends.iter().flat_map(|&x| people.get_person(x)) {
println!(" {}", friend.name);
}
}
// Same as above
if let Some(ref person) = people.get_person(patrick) {
println!("Friends of {}:", person.name);
for friend in person.friends.iter().flat_map(|&x| people.get_person(x)) {
println!(" {}", friend.name);
}
}
println!("ID of Sandy is {:?}", people.get_id(&String::from("Sandy")));
// Change the name of a person through a mutable borrow
if let Some(ref mut person) = people.get_person_mut(sandy) {
person.name = String::from("Mr. Krabs");
}
// Now verify that Sandy's name has changed.
if let Some(ref person) = people.get_person(spongebob) {
println!("Friends of {}:", person.name);
for friend in person.friends.iter().flat_map(|&x| people.get_person(x)) {
println!(" {}", friend.name);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment