#[cfg(test)]
#[macro_use]
extern crate matches;
use ::std::{io, fmt};
use ::std::str::FromStr;
use ::std::cell::{Cell, RefCell};
use ::std::string::ToString;
use ::std::borrow::Borrow;
use ::std::error::Error as StdError;
pub mod console;
pub const JOINER: u8 = b'.';
pub trait INode {
fn name(&self) -> &str;
fn description(&self) -> &str;
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Pass;
pub type BoxResult<T> = Result<T, Box<StdError>>;
#[derive(Debug)]
pub enum InnerError {
NameError,
ListError,
PropError,
ActionError,
ParseError(Box<StdError>),
ChangeError(Box<StdError>),
ConstError,
InvokeError(Box<StdError>),
}
impl fmt::Display for InnerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(self.description().fmt(f));
match *self {
InnerError::ParseError(ref err) |
InnerError::ChangeError(ref err) |
InnerError::InvokeError(ref err) => {
write!(f, ": {}", err)
},
_ => Ok(()),
}
}
}
impl StdError for InnerError {
fn description(&self) -> &str {
match *self {
InnerError::NameError => "name not found",
InnerError::PropError => "property expected",
InnerError::ListError => "list expected",
InnerError::ActionError => "action expected",
InnerError::ParseError(_) => "parse error",
InnerError::ChangeError(_) => "change error",
InnerError::ConstError => "property is read-only",
InnerError::InvokeError(_) => "invoke error",
}
}
fn cause(&self) -> Option<&StdError> {
match *self {
InnerError::ParseError(ref err) |
InnerError::ChangeError(ref err) |
InnerError::InvokeError(ref err) => {
Some(&**err)
},
_ => None,
}
}
}
#[derive(Debug)]
pub struct Error<'a> {
pub id: &'a str,
pub name: &'a str,
pub inner: InnerError,
_private: (),
}
impl<'a> Error<'a> {
pub fn new(id: &'a str, name: &'a str, inner: InnerError) -> Error<'a> {
Error {
id: id,
name: name,
inner: inner,
_private: (),
}
}
}
impl<'a> fmt::Display for Error<'a> {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}
impl<'a> StdError for Error<'a> {
fn description(&self) -> &str {
self.inner.description()
}
fn cause(&self) -> Option<&StdError> {
self.inner.cause()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum PropState {
Default,
UserSet,
Invalid,
}
pub trait IProperty: INode {
fn get(&self) -> String;
fn set(&self, val: &str) -> Result<(), InnerError>;
fn reset(&self);
fn default(&self) -> String;
fn state(&self) -> PropState;
}
impl<'a> fmt::Debug for &'a IProperty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Property")
.field("name", &self.name())
.field("desc", &self.description())
.field("value", &self.get())
.field("default", &self.default())
.field("state", &self.state())
.finish()
}
}
impl<'a> From<&'a IProperty> for Node<'a> {
fn from(prop: &'a IProperty) -> Node<'a> {
Node::Prop(prop)
}
}
pub trait Variable<T> where T: fmt::Debug {
fn get(&self) -> T;
fn set(&self, val: T);
fn with<R, F>(&self, f: F) -> R where F: FnOnce(&T) -> R;
}
impl<'a, T, V> Variable<T> for &'a V where T: fmt::Debug, V: Variable<T> {
fn get(&self) -> T {
Variable::get(*self)
}
fn set(&self, val: T) {
Variable::set(*self, val)
}
fn with<R, F: FnOnce(&T) -> R>(&self, f: F) -> R {
Variable::with(*self, f)
}
}
impl<T> Variable<T> for Cell<T> where T: Copy + fmt::Debug {
fn get(&self) -> T {
Cell::get(self)
}
fn set(&self, val: T) {
Cell::set(self, val)
}
fn with<R, F>(&self, f: F) -> R where F: FnOnce(&T) -> R {
(f)(&Cell::get(self))
}
}
impl<T> Variable<T> for RefCell<T> where T: Clone + fmt::Debug {
fn get(&self) -> T {
self.borrow().clone()
}
fn set(&self, val: T) {
*self.borrow_mut() = val;
}
fn with<R, F>(&self, f: F) -> R where F: FnOnce(&T) -> R {
(f)(&*self.borrow())
}
}
pub trait Value: Clone + PartialEq + fmt::Debug {
fn parse(val: &str) -> BoxResult<Self>;
fn to_string(&self) -> String;
}
pub trait AutoValue: Copy + PartialEq + FromStr + ToString + fmt::Debug
where Self::Err: 'static + StdError {}
impl AutoValue for i8 {}
impl AutoValue for i16 {}
impl AutoValue for i32 {}
impl AutoValue for i64 {}
impl AutoValue for isize {}
impl AutoValue for u8 {}
impl AutoValue for u16 {}
impl AutoValue for u32 {}
impl AutoValue for u64 {}
impl AutoValue for usize {}
impl AutoValue for f32 {}
impl AutoValue for f64 {}
impl AutoValue for bool {}
impl<T> Value for T
where T: AutoValue,
T::Err: 'static + StdError
{
fn parse(val: &str) -> BoxResult<Self> {
Ok(try!(val.parse()))
}
fn to_string(&self) -> String {
ToString::to_string(self)
}
}
impl<T> Value for Option<T>
where T: AutoValue,
T::Err: 'static + StdError
{
fn parse(val: &str) -> BoxResult<Self> {
if val == "None" {
Ok(None)
}
else {
Ok(Some(try!(val.parse())))
}
}
fn to_string(&self) -> String {
match *self {
Some(ref val) => ToString::to_string(val),
None => String::from("None"),
}
}
}
impl Value for String {
fn parse(val: &str) -> BoxResult<String> {
Ok(String::from(val))
}
fn to_string(&self) -> String {
self.clone()
}
}
pub trait OnChange<T> {
fn change(&self, old: &T, val: T) -> BoxResult<T>;
}
impl<T> OnChange<T> for Pass {
fn change(&self, _: &T, val: T) -> BoxResult<T> {
Ok(val)
}
}
impl<T, F> OnChange<T> for F where F: Fn(&T, T) -> BoxResult<T> {
fn change(&self, old: &T, val: T) -> BoxResult<T> {
(self)(old, val)
}
}
pub struct Property<N, D, T, V, F>
where N: Borrow<str>,
D: Borrow<str>,
T: Value,
V: Variable<T>,
F: OnChange<T>
{
name: N,
desc: D,
var: V,
def: T,
change: F,
}
impl<N, D, T, V> Property<N, D, T, V, Pass> where N: Borrow<str>, D: Borrow<str>, T: Value, V: Variable<T> {
pub fn new<I>(name: N, desc: D, var: V, def: I) -> Property<N, D, T, V, Pass> where I: Into<T> {
Property {
name: name,
desc: desc,
var: var,
def: def.into(),
change: Pass,
}
}
}
impl<N, D, T, V> Property<N, D, T, V, Pass> where N: Borrow<str>, D: Borrow<str>, T: Value, V: Variable<T> {
pub fn change<F>(self, change: F) -> Property<N, D, T, V, F> where F: Fn(&T, T) -> BoxResult<T> {
debug_assert!(self.var.with(|old| (change)(old, self.def.clone()).is_ok()), "default value did not validate");
Property {
name: self.name,
desc: self.desc,
var: self.var,
def: self.def,
change: change,
}
}
}
impl<N, D, T, V, F> INode for Property<N, D, T, V, F> where N: Borrow<str>, D: Borrow<str>, T: Value, V: Variable<T>, F: OnChange<T> {
fn name(&self) -> &str {
self.name.borrow()
}
fn description(&self) -> &str {
self.desc.borrow()
}
}
impl<N, D, T, V, F> IProperty for Property<N, D, T, V, F> where N: Borrow<str>, D: Borrow<str>, T: Value, V: Variable<T>, F: OnChange<T> {
fn get(&self) -> String {
self.var.get().to_string()
}
fn set(&self, val: &str) -> Result<(), InnerError> {
match Value::parse(val) {
Ok(val) => {
match self.var.with(|old| self.change.change(old, val)) {
Ok(val) => self.var.set(val),
Err(err) => return Err(InnerError::ChangeError(err)),
}
},
Err(err) => return Err(InnerError::ParseError(err)),
};
Ok(())
}
fn reset(&self) {
let val = self.var.with(|old| self.change.change(old, self.def.clone())).unwrap();
self.var.set(val);
}
fn default(&self) -> String {
self.def.to_string()
}
fn state(&self) -> PropState {
match self.var.with(|val| val == &self.def) {
true => PropState::Default,
false => PropState::UserSet,
}
}
}
impl<'s, N, D, T, V, F> From<&'s Property<N, D, T, V, F>> for Node<'s> where N: Borrow<str>, D: Borrow<str>, T: Value, V: Variable<T>, F: OnChange<T> {
fn from(prop: &'s Property<N, D, T, V, F>) -> Node<'s> {
Node::Prop(prop)
}
}
#[derive(Copy, Clone)]
pub enum Node<'a> {
Prop(&'a IProperty),
List(&'a IList),
Action(&'a IAction),
}
impl<'a> INode for Node<'a> {
fn name(&self) -> &str {
match *self {
Node::Prop(prop) => prop.name(),
Node::List(list) => list.name(),
Node::Action(act) => act.name(),
}
}
fn description(&self) -> &str {
match *self {
Node::Prop(prop) => prop.description(),
Node::List(list) => list.description(),
Node::Action(act) => act.description(),
}
}
}
impl<'a> fmt::Debug for Node<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Node::Prop(prop) => {
prop.fmt(f)
},
Node::List(list) => {
list.fmt(f)
},
Node::Action(act) => {
act.fmt(f)
},
}
}
}
pub trait IVisit {
fn visit(&self, f: &mut FnMut(Node));
}
impl<'a> fmt::Debug for &'a IVisit {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut f = f.debug_list();
self.visit(&mut |node| {
f.entry(&node);
});
f.finish()
}
}
pub trait IList: INode {
fn as_visit(&self) -> &IVisit;
}
impl<'a> fmt::Debug for &'a IList {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("List")
.field("name", &self.name())
.field("desc", &self.description())
.field("children", &self.as_visit())
.finish()
}
}
impl<'a> From<&'a IList> for Node<'a> {
fn from(list: &'a IList) -> Node<'a> {
Node::List(list)
}
}
pub struct List<'a, N, D>
where N: Borrow<str>,
D: Borrow<str>
{
name: N,
desc: D,
visit: &'a IVisit,
}
impl<'a, N, D> List<'a, N, D> where N: Borrow<str>, D: Borrow<str> {
pub fn new(name: N, desc: D, visit: &'a IVisit) -> List<'a, N, D> {
List {
name: name,
desc: desc,
visit: visit,
}
}
}
impl<'a, N, D> INode for List<'a, N, D> where N: Borrow<str>, D: Borrow<str> {
fn name(&self) -> &str {
self.name.borrow()
}
fn description(&self) -> &str {
self.desc.borrow()
}
}
impl<'a, N, D> IList for List<'a, N, D> where N: Borrow<str>, D: Borrow<str> {
fn as_visit(&self) -> &IVisit {
self.visit
}
}
impl<'s, 'a, N, D> From<&'s List<'a, N, D>> for Node<'s> where N: Borrow<str>, D: Borrow<str> {
fn from(val: &'s List<'a, N, D>) -> Node<'s> {
Node::List(val)
}
}
pub struct Context<'a> {
pub args: &'a str,
pub write: &'a mut io::Write,
_private: (),
}
impl<'a> Context<'a> {
pub fn new(args: &'a str, write: &'a mut io::Write) -> Context<'a> {
Context {
args: args,
write: write,
_private: (),
}
}
}
pub trait IAction: INode {
fn invoke(&self, ctx: &mut Context) -> Result<(), InnerError>;
}
impl<'a> fmt::Debug for &'a IAction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Action")
.field("name", &self.name())
.field("desc", &self.description())
.finish()
}
}
impl<'a> From<&'a IAction> for Node<'a> {
fn from(act: &'a IAction) -> Node<'a> {
Node::Action(act)
}
}
pub trait OnInvoke {
fn invoke(&self, ctx: &mut Context) -> BoxResult<()>;
}
impl OnInvoke for Pass {
fn invoke(&self, _: &mut Context) -> BoxResult<()> {
Ok(())
}
}
impl<F> OnInvoke for F where F: Fn(&mut Context) -> BoxResult<()> {
fn invoke(&self, ctx: &mut Context) -> BoxResult<()> {
(self)(ctx)
}
}
pub struct Action<N, D, F>
where N: Borrow<str>,
D: Borrow<str>,
F: OnInvoke
{
name: N,
desc: D,
f: F,
}
impl<N, D> Action<N, D, Pass> where N: Borrow<str>, D: Borrow<str> {
pub fn new<F>(name: N, desc: D, f: F) -> Action<N, D, F> where F: Fn(&mut Context) -> BoxResult<()> {
Action {
name: name,
desc: desc,
f: f,
}
}
}
impl<N, D, F> INode for Action<N, D, F> where N: Borrow<str>, D: Borrow<str>, F: OnInvoke {
fn name(&self) -> &str {
self.name.borrow()
}
fn description(&self) -> &str {
self.desc.borrow()
}
}
impl<N, D, F> IAction for Action<N, D, F> where N: Borrow<str>, D: Borrow<str>, F: OnInvoke {
fn invoke(&self, ctx: &mut Context) -> Result<(), InnerError> {
match self.f.invoke(ctx) {
Ok(ok) => Ok(ok),
Err(err) => Err(InnerError::InvokeError(err)),
}
}
}
impl<'s, N, D, F> From<&'s Action<N, D, F>> for Node<'s> where N: Borrow<str>, D: Borrow<str>, F: OnInvoke {
fn from(val: &'s Action<N, D, F>) -> Node<'s> {
Node::Action(val)
}
}