Created
September 25, 2017 05:06
-
-
Save ivanceras/fdb05dab4e7c703c6699741ec22667bd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![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