rustberry 0.1.0

All-purpose Raspberry Pi library for Rust
Documentation
// Copyright (C) 2018  Adam Gausmann
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

//! Implementation of "reservations", a system using handles to keep track of
//! what items are currently owned and which can be "reserved".

use std::cell::RefCell;
use std::collections::HashSet;
use std::hash::Hash;
use std::rc::Rc;

use error::{Error, ErrorKind};

/// A reservation manager that hands out `Reservation`s, where each one
/// corresponds to a unique key provided upon creation.
///
/// Only one `Reservation` object may exist for a single key at any given
/// time; however, once the reservation is dropped, the key may be reserved
/// again.
pub struct Reservations<K>
where
    K: Eq + Hash,
{
    reserved: Rc<RefCell<HashSet<K>>>,
}

impl<K> Reservations<K>
where
    K: Eq + Hash + Clone,
{
    /// Constructs a new manager object with no reservations.
    pub fn new() -> Reservations<K> {
        Reservations {
            reserved: Rc::new(RefCell::new(HashSet::new())),
        }
    }

    /// Returns `true` if the given key is currently reserved.
    pub fn is_reserved(&self, key: &K) -> bool {
        let reserved = self.reserved.borrow();

        reserved.contains(key)
    }

    /// Attempts to reserve the given key, returning its reservation upon
    /// success.
    ///
    /// # Errors
    ///
    /// Returns `Error` with the kind `Reserved` if the key is currently
    /// reserved by another reservation.
    pub fn try_reserve(&self, key: K) -> Result<Reservation<K>, Error> {
        let mut reserved = self.reserved.borrow_mut();

        if reserved.insert(key.clone()) {
            Ok(Reservation {
                key, 
                reserved: Rc::clone(&self.reserved),
            })
        } else {
            Err(Error::new(ErrorKind::Reserved))
        }
    }
}

/// A lock managing a single reservation, which will exist for the lifetime
/// of this object. Once this object is dropped, the reservation is, and the
/// key may be reused.
pub struct Reservation<K>
where
    K: Eq + Hash,
{
    key: K,
    reserved: Rc<RefCell<HashSet<K>>>,
}

impl<K> Drop for Reservation<K>
where
    K: Eq + Hash,
{
    fn drop(&mut self) {
        // Free the key!
        let mut reserved = self.reserved.borrow_mut();
        reserved.take(&self.key).unwrap();
    }
}