summaryrefslogtreecommitdiffstats
path: root/libimagcounter
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2016-02-13 19:51:52 +0100
committerMatthias Beyer <mail@beyermatthias.de>2016-03-12 16:06:10 +0100
commit2bc9f2ec25d638a82eb7f439c1c3fbf05fddb76a (patch)
tree07aceb3a6c87a2a5075af58739b63ac8c179873f /libimagcounter
parent9a918c925225d6cf241aca43e4a90167efbf6b60 (diff)
libimagcounter: init
Diffstat (limited to 'libimagcounter')
-rw-r--r--libimagcounter/Cargo.toml13
-rw-r--r--libimagcounter/src/counter.rs144
-rw-r--r--libimagcounter/src/error.rs89
-rw-r--r--libimagcounter/src/lib.rs12
-rw-r--r--libimagcounter/src/result.rs6
5 files changed, 264 insertions, 0 deletions
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 <mail@beyermatthias.de>"]
+
+[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<Counter> {
+ 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<CounterName> {
+ 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<i64> {
+ 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<Counter> {
+ 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<Box<Error>>,
+}
+
+impl CounterError {
+
+ /**
+ * Build a new CounterError from an CounterErrorKind, optionally with cause
+ */
+ pub fn new(errtype: CounterErrorKind, cause: Option<Box<Error>>)
+ -> 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<T> = RResult<T, CounterError>;
+