Crate coatcheck [-] [src]

CoatCheck

CoatCheck is a library for storing values and referencing them by "handles" (Tickets). This library is designed to be used where you would otherwise use a hash table but you don't actually need to be able to choose the keys.

Advantages over a hash table:

  1. You don't have to generate your keys.
  2. CoatCheck is at least 5x faster than the stdlib HashTable for insert/remove operations.
  3. CoatCheck is about 40x faster for lookup operations.

Example

use coatcheck::{CoatCheck, Ticket};
use std::convert::From;

let mut cc = CoatCheck::new();

// Check two values.
let ticket1 = cc.check("my value");
let ticket2 = cc.check("my other value");

// Look at the first one.
println!("{}", cc[&ticket1]);

// Claim the second one.
println!("{}", cc.claim(ticket2).unwrap());

// Claiming again will fail at compile time.
// println!("{}", cc.claim(ticket2).unwrap());

// Drain the items into a vector.
let items: Vec<&str> = cc.into_iter().collect();
assert_eq!(items[0], "my value");

// Create a second coat check:
let mut cc2: CoatCheck<&str> = CoatCheck::new();

// `ticket1` was never claimed so let's try claiming it in this coat check...
let ticket: Ticket = From::from(cc2.claim(ticket1).unwrap_err());
// It fails and returns the ticket.

Use Case

For example, let's say you were implementing a callback system:

struct System {
    callbacks: Vec<Box<FnMut() + 'static>>,
}

impl System {
    fn add_callback<C>(&mut self, cb: C) where C: FnMut() + 'static {
        self.callbacks.push(Box::new(cb));
    }
    fn fire(&mut self) {
        for cb in self.callbacks.iter_mut() {
            (cb)();
        }
    }
}

This system works but doesn't allow unregistering. If you wanted to allow unregistering individual callbacks, you could do something like:

use std::collections::HashMap;

struct System {
    callbacks: HashMap<usize, Box<FnMut() + 'static>>,
    next_id: usize,
}

struct Handle {
    id: usize,
}

impl System {
    fn add_callback<C>(&mut self, cb: C) -> Handle where C: FnMut() + 'static {
        let id = self.next_id;
        self.next_id += 1;
        self.callbacks.insert(id, Box::new(cb));
        Handle { id: id }
    }
    fn fire(&mut self) {
        for (_, cb) in self.callbacks.iter_mut() {
            (cb)();
        }
    }
    fn remove_callback(&mut self, handle: Handle) {
        self.callbacks.remove(&handle.id);
    }
}

However, we don't REALLY need a hash table because we don't care about the keys.

This is where this library comes in. It acts like the above system but takes advantage of the fact that it can choose the IDs:

use coatcheck::{CoatCheck, Ticket};

struct System {
    callbacks: CoatCheck<Box<FnMut() + 'static>>,
}

struct Handle {
    ticket: Ticket, // Wrap it for type safety
}

impl System {
    fn add_callback<C>(&mut self, cb: C) -> Handle where C: FnMut() + 'static {
        Handle { ticket: self.callbacks.check(Box::new(cb)) }
    }
    fn remove_callback(&mut self, handle: Handle) {
        self.callbacks.claim(handle.ticket);
    }
    fn fire(&mut self) {
        for cb in self.callbacks.iter_mut() {
            (*cb)();
        }
    }
}

Discussion

One thing you might note when using this library is that Tickets can't be duplicated in any way.

Pros:

Cons:

Structs

AccessError

The error yielded an access fails.

ClaimError

The error yielded when a claim fails.

CoatCheck

A data structure storing values indexed by tickets.

Ticket

A Ticket is an opaque data structure that can be used to claim the associated value.

Tickets

Iterator that checks-in values in exchange for tickets.

Enums

ErrorKind

Coat check error types