Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
269 lines (255 sloc) 9.56 KB
#![feature(try_from)]
#![feature(proc_macro_hygiene)]
mod error;
use std::convert::TryFrom;
use std::fmt; // impl Display
use std::ops::{Add, Div, Mul, Sub};
use std::num::ParseFloatError; // impl FromStr
use std::str::FromStr;
use rust_decimal::Decimal;
use rust_decimal_macros::*;
#[derive(Clone, Debug)] pub struct Celsius{ pub value: f32 }
#[derive(Clone, Debug)] pub struct Fahrenheit{ pub value: f32 }
#[derive(Clone, Debug)] pub struct Kelvin{ pub value: f32 }
#[derive(Clone, Debug)] pub struct Rankine{ pub value: f32 }
pub trait AbsoluteZero<'a> { // defines the absolute zero for a temperature unit.
fn is_baz(self) -> bool; // is below absolute zero. false == good
}
macro_rules! impl_abszero {
($t:ty, $absz:expr) => {
impl <'a>AbsoluteZero<'a> for $t {
fn is_baz(self) -> bool {
!self.value.ge($absz)
}
}
}
}
macro_rules! impl_display {
( $t:ty ) => {
impl fmt::Display for $t {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let unit: Vec<char> = String::from(stringify!($t)).chars().collect();
match stringify!($t) {
"Kelvin" => { write!(f, "{}{}", self.value, unit[0]) },
_ => { write!(f, "{}°{}", self.value, unit[0]) }
}
}
}
}
}
impl_abszero!(Celsius, &-273.15);
impl_abszero!(Fahrenheit, &-459.67);
impl_abszero!(Kelvin, &0.0);
impl_abszero!(Rankine, &0.0);
impl_display!(Celsius);
impl_display!(Fahrenheit);
impl_display!(Kelvin);
impl_display!(Rankine);
impl FromStr for Celsius {
type Err = ParseFloatError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let temp = s.parse::<f32>()?;
Ok(Celsius{ value: temp } )
}
}
impl FromStr for Fahrenheit {
type Err = ParseFloatError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let temp = s.parse::<f32>()?;
Ok(Fahrenheit{ value: temp } )
}
}
impl FromStr for Kelvin {
type Err = ParseFloatError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let temp = s.parse::<f32>()?;
Ok(Kelvin{ value: temp } )
}
}
impl FromStr for Rankine {
type Err = ParseFloatError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let temp = s.parse::<f32>()?;
Ok(Rankine{ value: temp } )
}
}
macro_rules! into_dec {
( $( $c:expr ),* ) => {
{
let mut consts: Vec<Decimal> = Vec::new();
$(
consts.push(Decimal::from_str($c).unwrap());
)*
consts
}
};
}
// used for conversion
impl TryFrom<Fahrenheit> for Celsius {
type Error = crate::error::BelowAbsoluteZeroError;
fn try_from(temp: Fahrenheit) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("5", "9", "32");
let temp: Decimal = ( t.sub( consts[2] ) ) * consts[0] / consts[1];
Ok ( Celsius{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Kelvin> for Celsius {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Kelvin) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("273.15");
let temp: Decimal = t.sub(consts[0]);
Ok ( Celsius{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Rankine> for Celsius {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Rankine) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("5", "9", "491.67");
let temp: Decimal = t.sub(consts[2]).mul(consts[0]).div(consts[1]);
Ok ( Celsius{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Celsius> for Fahrenheit {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Celsius) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("5", "9", "32");
let temp: Decimal = t.mul(consts[1]).div(consts[0]).add(consts[2]);
Ok( Fahrenheit{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Kelvin> for Fahrenheit {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Kelvin) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("5", "9", "32", "273.15");
let temp: Decimal = t.sub(consts[3]).mul(consts[1]).div(consts[0]).add(consts[2]);
Ok( Fahrenheit{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Rankine> for Fahrenheit {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Rankine) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("459.67");
let temp: Decimal = t.sub(consts[0]);
Ok( Fahrenheit{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Celsius> for Kelvin {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Celsius) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("273.15");
let temp: Decimal = t.add(consts[0]);
Ok( Kelvin{ value: temp.to_string().parse().unwrap()} )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Fahrenheit> for Kelvin {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Fahrenheit) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("5", "9", "32", "273.15");
let temp: Decimal = t.sub(consts[2]).mul(consts[0]).div(consts[1]).add(consts[3]);
Ok( Kelvin{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Rankine> for Kelvin {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Rankine) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("5", "9");
let temp: Decimal = t.mul(consts[0]).div(consts[1]);
Ok( Kelvin{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Celsius> for Rankine {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Celsius) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("5", "9");
let temp: Decimal = t.mul(consts[0]).div(consts[1]);
Ok( Rankine{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Fahrenheit> for Rankine {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Fahrenheit) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("5", "9", "273.15");
let temp: Decimal = t.add(consts[2]).mul(consts[1]).div(consts[0]);
Ok( Rankine{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}
impl TryFrom<Kelvin> for Rankine {
type Error = error::BelowAbsoluteZeroError;
fn try_from(temp: Kelvin) -> Result<Self, Self::Error> {
match temp.clone().is_baz() {
false => {
let t: Decimal = Decimal::from_str(&temp.value.to_string()).unwrap();
let consts = into_dec!("5", "9");
let temp: Decimal = t.mul(consts[1]).div(consts[0]);
Ok( Rankine{ value: temp.to_string().parse().unwrap() } )
},
true => Err(error::BelowAbsoluteZeroError)
}
}
}