diff --git a/src/hashdb.rs b/src/hashdb.rs index b686da78d..d023fe70d 100644 --- a/src/hashdb.rs +++ b/src/hashdb.rs @@ -2,8 +2,81 @@ use hash::*; use bytes::Bytes; pub trait HashDB { + /// Look up a given hash into the bytes that hash to it, returning None if the + /// hash is not known. + /// + /// # Examples + /// ```rust + /// extern crate ethcore_util; + /// use ethcore_util::hashdb::*; + /// use ethcore_util::memorydb::*; + /// fn main() { + /// let mut m = MemoryDB::new(); + /// let hello_bytes = "Hello world!".as_bytes(); + /// let hash = m.insert(hello_bytes); + /// assert_eq!(m.lookup(&hash).unwrap(), &hello_bytes); + /// } + /// ``` fn lookup(&self, key: &H256) -> Option<&Bytes>; + + /// Check for the existance of a hash-key. + /// + /// # Examples + /// ```rust + /// extern crate ethcore_util; + /// use ethcore_util::hashdb::*; + /// use ethcore_util::memorydb::*; + /// use ethcore_util::sha3::*; + /// fn main() { + /// let mut m = MemoryDB::new(); + /// let hello_bytes = "Hello world!".as_bytes(); + /// assert!(!m.exists(&hello_bytes.sha3())); + /// let key = m.insert(hello_bytes); + /// assert!(m.exists(&key)); + /// m.kill(&key); + /// assert!(!m.exists(&key)); + /// } + /// ``` fn exists(&self, key: &H256) -> bool; + + /// Insert a datum item into the DB and return the datum's hash for a later lookup. Insertions + /// are counted and the equivalent number of `kill()`s must be performed before the data + /// is considered dead. + /// + /// # Examples + /// ```rust + /// extern crate ethcore_util; + /// use ethcore_util::hashdb::*; + /// use ethcore_util::memorydb::*; + /// use ethcore_util::hash::*; + /// fn main() { + /// let mut m = MemoryDB::new(); + /// let key = m.insert("Hello world!".as_bytes()); + /// assert!(m.exists(&key)); + /// } + /// ``` fn insert(&mut self, value: &[u8]) -> H256; + + /// Remove a datum previously inserted. Insertions can be "owed" such that the same number of `insert()`s may + /// happen without the data being eventually being inserted into the DB. + /// + /// # Examples + /// ```rust + /// extern crate ethcore_util; + /// use ethcore_util::hashdb::*; + /// use ethcore_util::memorydb::*; + /// use ethcore_util::sha3::*; + /// fn main() { + /// let mut m = MemoryDB::new(); + /// let d = "Hello world!".as_bytes(); + /// let key = &d.sha3(); + /// m.kill(key); // OK - we now owe an insertion. + /// assert!(!m.exists(key)); + /// m.insert(d); // OK - now it's "empty" again. + /// assert!(!m.exists(key)); + /// m.insert(d); // OK - now we've + /// assert_eq!(m.lookup(key).unwrap(), &d); + /// } + /// ``` fn kill(&mut self, key: &H256); } diff --git a/src/memorydb.rs b/src/memorydb.rs index d732b9e5f..55fdc12da 100644 --- a/src/memorydb.rs +++ b/src/memorydb.rs @@ -1,36 +1,5 @@ //! Reference-counted memory-based HashDB implementation. -//! -//! # Example -//! ```rust -//! extern crate ethcore_util; -//! use ethcore_util::hashdb::*; -//! use ethcore_util::memorydb::*; -//! fn main() { -//! let mut m = MemoryDB::new(); -//! let d = "Hello world!".as_bytes(); -//! -//! let k = m.insert(d); -//! assert!(m.exists(&k)); -//! assert_eq!(m.lookup(&k).unwrap(), &d); -//! -//! m.insert(d); -//! assert!(m.exists(&k)); -//! -//! m.kill(&k); -//! assert!(m.exists(&k)); -//! -//! m.kill(&k); -//! assert!(!m.exists(&k)); -//! -//! m.insert(d); -//! assert!(m.exists(&k)); -//! assert_eq!(m.lookup(&k).unwrap(), &d); -//! -//! m.kill(&k); -//! assert!(!m.exists(&k)); -//! } -//! ``` use hash::*; use bytes::*; use sha3::*; @@ -38,31 +7,56 @@ use hashdb::*; use std::collections::HashMap; #[derive(Debug,Clone)] +/// Reference-counted memory-based HashDB implementation. +/// +/// Use `new()` to create a new database. Insert items with `insert()`, remove items +/// with `kill()`, check for existance with `exists()` and lookup a hash to derive +/// the data with `lookup()`. Clear with `clear()` and purge the portions of the data +/// that have no references with `purge()`. +/// +/// # Example +/// ```rust +/// extern crate ethcore_util; +/// use ethcore_util::hashdb::*; +/// use ethcore_util::memorydb::*; +/// fn main() { +/// let mut m = MemoryDB::new(); +/// let d = "Hello world!".as_bytes(); +/// +/// let k = m.insert(d); +/// assert!(m.exists(&k)); +/// assert_eq!(m.lookup(&k).unwrap(), &d); +/// +/// m.insert(d); +/// assert!(m.exists(&k)); +/// +/// m.kill(&k); +/// assert!(m.exists(&k)); +/// +/// m.kill(&k); +/// assert!(!m.exists(&k)); +/// +/// m.insert(d); +/// assert!(m.exists(&k)); +/// assert_eq!(m.lookup(&k).unwrap(), &d); +/// +/// m.kill(&k); +/// assert!(!m.exists(&k)); +/// } +/// ``` pub struct MemoryDB { data: HashMap, } impl MemoryDB { + /// Create a new instance of the memory DB. pub fn new() -> MemoryDB { MemoryDB { data: HashMap::new() } } - pub fn clear(&mut self) { - self.data.clear(); - } - - pub fn purge(&mut self) { - let empties: Vec<_> = self.data.iter().filter(|&(_, &(_, rc))| rc <= 0).map(|(k, _)| k.clone()).collect(); - for empty in empties { self.data.remove(&empty); } - } -} - -impl HashDB for MemoryDB { - /// Do a hash dereference and look up a given hash into the bytes that make it up, - /// returning None if nothing is found (or if the only entries have 0 or fewer - /// references). + /// Clear all data from the database. /// /// # Examples /// ```rust @@ -73,9 +67,26 @@ impl HashDB for MemoryDB { /// let mut m = MemoryDB::new(); /// let hello_bytes = "Hello world!".as_bytes(); /// let hash = m.insert(hello_bytes); - /// assert_eq!(m.lookup(&hash).unwrap(), &hello_bytes); + /// assert!(m.exists(&hash)); + /// m.clear(); + /// assert!(!m.exists(&hash)); /// } /// ``` + pub fn clear(&mut self) { + self.data.clear(); + } + + /// Purge all zero-referenced data from the database. + pub fn purge(&mut self) { + let empties: Vec<_> = self.data.iter() + .filter(|&(_, &(_, rc))| rc == 0) + .map(|(k, _)| k.clone()) + .collect(); + for empty in empties { self.data.remove(&empty); } + } +} + +impl HashDB for MemoryDB { fn lookup(&self, key: &H256) -> Option<&Bytes> { match self.data.get(key) { Some(&(ref d, rc)) if rc > 0 => Some(d), @@ -83,24 +94,6 @@ impl HashDB for MemoryDB { } } - /// Check for the existance of a hash-key. - /// - /// # Examples - /// ```rust - /// extern crate ethcore_util; - /// use ethcore_util::hashdb::*; - /// use ethcore_util::memorydb::*; - /// use ethcore_util::sha3::*; - /// fn main() { - /// let mut m = MemoryDB::new(); - /// let hello_bytes = "Hello world!".as_bytes(); - /// assert!(!m.exists(&hello_bytes.sha3())); - /// let key = m.insert(hello_bytes); - /// assert!(m.exists(&key)); - /// m.kill(&key); - /// assert!(!m.exists(&key)); - /// } - /// ``` fn exists(&self, key: &H256) -> bool { match self.data.get(key) { Some(&(_, x)) if x > 0 => true, @@ -108,60 +101,27 @@ impl HashDB for MemoryDB { } } - /// Insert a datum item into the DB and return the datum's hash for a later lookup. Insertions - /// are counted and the equivalent number of `kill()`s must be performed before the data - /// is considered dead. - /// - /// # Examples - /// ```rust - /// extern crate ethcore_util; - /// use ethcore_util::hashdb::*; - /// use ethcore_util::memorydb::*; - /// use ethcore_util::hash::*; - /// fn main() { - /// let mut m = MemoryDB::new(); - /// let key = m.insert("Hello world!".as_bytes()); - /// assert!(m.exists(&key)); - /// } - /// ``` fn insert(&mut self, value: &[u8]) -> H256 { let key = value.sha3(); if match self.data.get_mut(&key) { - Some(&mut (ref mut old_value, ref mut rc @ 0)) => { *old_value = From::from(value.bytes()); *rc = 1; false }, + Some(&mut (ref mut old_value, ref mut rc @ 0)) => { + *old_value = From::from(value.bytes()); + *rc = 1; + false + }, Some(&mut (_, ref mut x)) => { *x += 1; false } , None => true, }{ // ... None falls through into... - self.data.insert(key, (From::from(value.bytes()), 1)); + self.data.insert(key.clone(), (From::from(value.bytes()), 1)); } key } - /// Remove a datum previously inserted. Insertions can be "owed" such that the same number of inserts may - /// happen without the data being eventually being inserted into the DB. - /// - /// # Examples - /// ```rust - /// extern crate ethcore_util; - /// use ethcore_util::hashdb::*; - /// use ethcore_util::memorydb::*; - /// use ethcore_util::sha3::*; - /// fn main() { - /// let mut m = MemoryDB::new(); - /// let d = "Hello world!".as_bytes(); - /// let key = &d.sha3(); - /// m.kill(key); // OK - we now owe an insertion. - /// assert!(!m.exists(key)); - /// m.insert(d); // OK - now it's "empty" again. - /// assert!(!m.exists(key)); - /// m.insert(d); // OK - now we've - /// assert_eq!(m.lookup(key).unwrap(), &d); - /// } - /// ``` fn kill(&mut self, key: &H256) { if match self.data.get_mut(key) { Some(&mut (_, ref mut x)) => { *x -= 1; false } None => true }{ // ... None falls through into... - self.data.insert(*key, (Bytes::new(), -1)); + self.data.insert(key.clone(), (Bytes::new(), -1)); } } }