From 2bc9f2ec25d638a82eb7f439c1c3fbf05fddb76a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 13 Feb 2016 19:51:52 +0100 Subject: [PATCH] libimagcounter: init --- libimagcounter/Cargo.toml | 13 +++ libimagcounter/src/counter.rs | 144 ++++++++++++++++++++++++++++++++++ libimagcounter/src/error.rs | 89 +++++++++++++++++++++ libimagcounter/src/lib.rs | 12 +++ libimagcounter/src/result.rs | 6 ++ 5 files changed, 264 insertions(+) create mode 100644 libimagcounter/Cargo.toml create mode 100644 libimagcounter/src/counter.rs create mode 100644 libimagcounter/src/error.rs create mode 100644 libimagcounter/src/lib.rs create mode 100644 libimagcounter/src/result.rs diff --git a/libimagcounter/Cargo.toml b/libimagcounter/Cargo.toml new file mode 100644 index 00000000..15ec9add --- /dev/null +++ b/libimagcounter/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "libimagcounter" +version = "0.1.0" +authors = ["Matthias Beyer "] + +[dependencies] +log = "0.3.5" +toml = "0.1.25" +semver = "0.2" + +[dependencies.libimagstore] +path = "../libimagstore" + diff --git a/libimagcounter/src/counter.rs b/libimagcounter/src/counter.rs new file mode 100644 index 00000000..d233e80d --- /dev/null +++ b/libimagcounter/src/counter.rs @@ -0,0 +1,144 @@ +use std::convert::From; +use std::convert::Into; +use std::ops::DerefMut; +use std::ops::Deref; + +use toml::Value; + +use std::collections::BTreeMap; + +use libimagstore::store::Store; +use libimagstore::store::FileLockEntry; +use libimagstore::storeid::StoreId; +use libimagstore::error::StoreError; +use libimagstore::store::Entry; +use libimagstore::storeid::IntoStoreId; + +use module_path::ModuleEntryPath; +use result::Result; +use error::CounterError as CE; +use error::CounterErrorKind as CEK; + +pub type CounterName = String; + +pub struct Counter<'a> { + fle: FileLockEntry<'a>, +} + +impl<'a> Counter<'a> { + + pub fn new(store: &Store, name: CounterName, init: i64) -> Result { + use std::ops::DerefMut; + + debug!("Creating new counter: '{}' with value: {}", name, init); + let fle = { + let mut lockentry = store.create(ModuleEntryPath::new(name.clone()).into_storeid()); + if lockentry.is_err() { + return Err(CE::new(CEK::StoreWriteError, Some(Box::new(lockentry.err().unwrap())))); + } + let mut lockentry = lockentry.unwrap(); + + { + let mut entry = lockentry.deref_mut(); + let mut header = entry.get_header_mut(); + let setres = header.set("counter", Value::Table(BTreeMap::new())); + if setres.is_err() { + return Err(CE::new(CEK::StoreWriteError, Some(Box::new(setres.err().unwrap())))); + } + + let setres = header.set("counter.name", Value::String(name)); + if setres.is_err() { + return Err(CE::new(CEK::StoreWriteError, Some(Box::new(setres.err().unwrap())))); + } + + let setres = header.set("counter.value", Value::Integer(init)); + if setres.is_err() { + return Err(CE::new(CEK::StoreWriteError, Some(Box::new(setres.err().unwrap())))); + } + } + + lockentry + }; + + Ok(Counter { fle: fle }) + } + + pub fn inc(&mut self) -> Result<()> { + let mut header = self.fle.deref_mut().get_header_mut(); + match header.read("counter.value") { + Ok(Some(Value::Integer(i))) => { + header.set("counter.value", Value::Integer(i + 1)) + .map_err(|e| CE::new(CEK::StoreWriteError, Some(Box::new(e)))) + .map(|_| ()) + }, + Err(e) => Err(CE::new(CEK::StoreReadError, Some(Box::new(e)))), + _ => Err(CE::new(CEK::StoreReadError, None)), + } + } + + pub fn dec(&mut self) -> Result<()> { + let mut header = self.fle.deref_mut().get_header_mut(); + match header.read("counter.value") { + Ok(Some(Value::Integer(i))) => { + header.set("counter.value", Value::Integer(i - 1)) + .map_err(|e| CE::new(CEK::StoreWriteError, Some(Box::new(e)))) + .map(|_| ()) + }, + Err(e) => Err(CE::new(CEK::StoreReadError, Some(Box::new(e)))), + _ => Err(CE::new(CEK::StoreReadError, None)), + } + } + + pub fn reset(&mut self) -> Result<()> { + let mut header = self.fle.deref_mut().get_header_mut(); + header.set("counter.value", Value::Integer(0)) + .map_err(|e| CE::new(CEK::StoreWriteError, Some(Box::new(e)))) + .map(|_| ()) + } + + pub fn set(&mut self, v: i64) -> Result<()> { + let mut header = self.fle.deref_mut().get_header_mut(); + header.set("counter.value", Value::Integer(v)) + .map_err(|e| CE::new(CEK::StoreWriteError, Some(Box::new(e)))) + .map(|_| ()) + } + + pub fn name(&self) -> Result { + let mut header = self.fle.deref().get_header(); + header.read("counter.name") + .map_err(|e| CE::new(CEK::StoreWriteError, Some(Box::new(e)))) + .and_then(|v| { + match v { + Some(Value::String(s)) => Ok(s), + _ => Err(CE::new(CEK::HeaderTypeError, None)), + } + }) + } + + pub fn value(&self) -> Result { + let mut header = self.fle.deref().get_header(); + header.read("counter.value") + .map_err(|e| CE::new(CEK::StoreWriteError, Some(Box::new(e)))) + .and_then(|v| { + match v { + Some(Value::Integer(i)) => Ok(i), + _ => Err(CE::new(CEK::HeaderTypeError, None)), + } + }) + } + + pub fn load(name: CounterName, store: &Store) -> Result { + debug!("Loading counter: '{}'", name); + match store.retrieve(ModuleEntryPath::new(name).into_storeid()) { + Err(e) => Err(CE::new(CEK::StoreReadError, Some(Box::new(e)))), + Ok(c) => Ok(Counter { fle: c }), + } + } + + pub fn delete(name: CounterName, store: &Store) -> Result<()> { + debug!("Deleting counter: '{}'", name); + store.delete(ModuleEntryPath::new(name).into_storeid()) + .map_err(|e| CE::new(CEK::StoreWriteError, Some(Box::new(e)))) + } +} + diff --git a/libimagcounter/src/error.rs b/libimagcounter/src/error.rs new file mode 100644 index 00000000..78d0cf46 --- /dev/null +++ b/libimagcounter/src/error.rs @@ -0,0 +1,89 @@ +use std::error::Error; +use std::fmt::Error as FmtError; +use std::clone::Clone; +use std::fmt::{Debug, Display, Formatter}; +use std::fmt; +use std::convert::From; + +/** + * Kind of error + */ +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum CounterErrorKind { + StoreReadError, + StoreWriteError, + HeaderTypeError, + HeaderFieldMissingError, +} + +fn counter_error_type_as_str(e: &CounterErrorKind) -> &'static str { + match e { + &CounterErrorKind::StoreReadError => "Store read error", + &CounterErrorKind::StoreWriteError => "Store write error", + &CounterErrorKind::HeaderTypeError => "Header type error", + &CounterErrorKind::HeaderFieldMissingError => "Header field missing error", + } +} + +impl Display for CounterErrorKind { + + fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { + try!(write!(fmt, "{}", counter_error_type_as_str(self))); + Ok(()) + } + +} + +/** + * Store error type + */ +#[derive(Debug)] +pub struct CounterError { + err_type: CounterErrorKind, + cause: Option>, +} + +impl CounterError { + + /** + * Build a new CounterError from an CounterErrorKind, optionally with cause + */ + pub fn new(errtype: CounterErrorKind, cause: Option>) + -> CounterError + { + CounterError { + err_type: errtype, + cause: cause, + } + } + + /** + * Get the error type of this CounterError + */ + pub fn err_type(&self) -> CounterErrorKind { + self.err_type.clone() + } + +} + +impl Display for CounterError { + + fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { + try!(write!(fmt, "[{}]", counter_error_type_as_str(&self.err_type.clone()))); + Ok(()) + } + +} + +impl Error for CounterError { + + fn description(&self) -> &str { + counter_error_type_as_str(&self.err_type.clone()) + } + + fn cause(&self) -> Option<&Error> { + self.cause.as_ref().map(|e| &**e) + } + +} + diff --git a/libimagcounter/src/lib.rs b/libimagcounter/src/lib.rs new file mode 100644 index 00000000..8b7a333a --- /dev/null +++ b/libimagcounter/src/lib.rs @@ -0,0 +1,12 @@ +extern crate toml; +#[macro_use] extern crate log; +#[macro_use] extern crate semver; + +#[macro_use] extern crate libimagstore; + +module_entry_path_mod!("counter", "0.1.0"); + +pub mod counter; +pub mod error; +pub mod result; + diff --git a/libimagcounter/src/result.rs b/libimagcounter/src/result.rs new file mode 100644 index 00000000..91a26599 --- /dev/null +++ b/libimagcounter/src/result.rs @@ -0,0 +1,6 @@ +use std::result::Result as RResult; + +use error::CounterError; + +pub type Result = RResult; +