Skip to content

Instantly share code, notes, and snippets.

@ivanceras
Created September 25, 2017 05:06
Show Gist options
  • Save ivanceras/fdb05dab4e7c703c6699741ec22667bd to your computer and use it in GitHub Desktop.
Save ivanceras/fdb05dab4e7c703c6699741ec22667bd to your computer and use it in GitHub Desktop.
#![feature(try_from)]
use std::fmt;
use std::convert::TryFrom;
use std::collections::btree_map::BTreeMap;
use std::error::Error;
#[derive(Debug,Clone)]
pub enum Value{
String(String),
Double(f64)
}
#[derive(Debug)]
pub enum DaoError<'a, T>
where T: TryFrom<&'a Value>,
T: TryFrom<Value>,
<T as std::convert::TryFrom<&'a Value>>::Error:fmt::Debug,
<T as std::convert::TryFrom<Value>>::Error:fmt::Debug
{
NoSuchValueError,
ConvertError(ConvertError),
ConvError(<T as TryFrom<&'a Value>>::Error),
ConvErrorClone(<T as TryFrom<Value>>::Error),
UnknownError,
}
#[derive(Debug)]
pub enum ConvertError{
ConvertF64Error,
ConvertStringError,
}
impl fmt::Display for ConvertError{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl Error for ConvertError{
fn description(&self) -> &str {
"convert error"
}
}
pub struct Dao<'a>(BTreeMap<&'a str, Value>);
impl <'a>Dao<'a>{
fn new() -> Self {
Dao(BTreeMap::new())
}
fn insert<V>(&mut self, s:&'a str, v: V)
where V: Into<Value> {
self.0.insert(s, v.into());
}
fn force_get<T>(&'a self, s: &str) -> T
where T: From<&'a Value>{
let value: Option<&'a Value> = self.0.get(s);
match value{
Some(v) => From::from(v),
None => panic!("no such index")
}
}
fn get<T>(&'a self, s: &str) -> Option<T>
where T: TryFrom<&'a Value>,
T: TryFrom<Value>,
<T as std::convert::TryFrom<&'a Value>>::Error:fmt::Debug,
<T as std::convert::TryFrom<Value>>::Error:fmt::Debug {
self.try_get(s).ok()
}
fn try_get<T>(&'a self, s: &str) -> Result<T, DaoError<T>>
where T: TryFrom<&'a Value>,
T: TryFrom<Value>,
<T as std::convert::TryFrom<&'a Value>>::Error: fmt::Debug,
<T as std::convert::TryFrom<Value>>::Error: fmt::Debug {
let value: Option<&'a Value> = self.0.get(s);
match value{
Some(v) => TryFrom::try_from(v).map_err(|e|DaoError::ConvError(e)),
None => Err(DaoError::NoSuchValueError),
}
}
fn try_get_with_error<T>(&'a self, s: &str) -> Result<T, <T as TryFrom<&Value>>::Error>
where T: TryFrom<&'a Value> {
let value: Option<&'a Value> = self.0.get(s);
match value{
Some(v) => TryFrom::try_from(v),
None => panic!(),//Err(DaoError::NoSuchValueError),
}
}
fn try_get_via_cloning<T>(&'a self, s: &str) -> Result<T, DaoError<'a, T>>
where T: TryFrom<&'a Value>,
T: TryFrom<Value>,
<T as std::convert::TryFrom<&'a Value>>::Error: fmt::Debug,
<T as std::convert::TryFrom<Value>>::Error: fmt::Debug {
let value: Option<&Value> = self.0.get(s);
match value{
Some(v) => TryFrom::try_from(v.clone()).map_err(|e|DaoError::ConvErrorClone(e)),
None => Err(DaoError::NoSuchValueError),
}
}
}
impl Into<Value> for f64{
fn into(self) -> Value{
Value::Double(self)
}
}
/// less copies, but has more explicit lifetimes
impl <'a>From<&'a Value> for f64{
fn from(value: &'a Value) -> Self{
match *value{
Value::Double(d) => d,
Value::String(ref s) => panic!("unable to convert"),
}
}
}
impl <'a>Into<Value> for &'a str{
fn into(self) -> Value {
Value::String(self.to_string())
}
}
/// zero copy, no allocation way
impl <'a>TryFrom<&'a Value> for f64{
type Error = ConvertError;
fn try_from(value: &'a Value) -> Result<Self, Self::Error>{
match *value{
Value::Double(d) => Ok(d),
Value::String(ref s) => Err(ConvertError::ConvertF64Error)
}
}
}
impl <'a>TryFrom<&'a Value> for String{
type Error = ConvertError;
fn try_from(value: &'a Value) -> Result<Self, Self::Error>{
match *value{
Value::Double(d) => Err(ConvertError::ConvertStringError),
Value::String(ref s) => Ok(s.to_owned()),
}
}
}
impl <'a>TryFrom<Value> for String{
type Error = ConvertError;
fn try_from(value: Value) -> Result<Self, Self::Error>{
match value{
Value::Double(d) => Err(ConvertError::ConvertStringError),
Value::String(s) => Ok(s),
}
}
}
/// this requires cloning to work
impl TryFrom<Value> for f64{
type Error = ConvertError;
fn try_from(value: Value) -> Result<Self, Self::Error>{
match value{
Value::Double(d) => Ok(d),
Value::String(ref s) => Err(ConvertError::ConvertF64Error)
}
}
}
fn main(){
let mut dao = Dao::new();
dao.insert("life", 42f64);
dao.insert("lemons", "lemonade");
let life:Option<f64> = dao.get("life");
let lemons:Option<String> = dao.get("lemons");
let try_life: Result<f64, _> = dao.try_get("life");
let error: Result<f64, _> = dao.try_get("error");
let conv_error: Result<f64, _> = dao.try_get("lemons");
let try_life_clone: Result<f64, _> = dao.try_get_via_cloning("life");
println!("life: {:?}", life);
println!("lemons: {:?}", lemons);
println!("try_life: {:?}", try_life);
println!("try_life via cloning: {:?}", try_life_clone);
println!("error: {:?}", error);
println!("conv_error: {:?}", conv_error);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment