Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| #![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) | |
| } | |
| } | |
| } |