Implement Integers and Rationals

This commit is contained in:
Eryn Wells 2017-04-09 15:58:20 -07:00
parent 0d3021fb74
commit 3e03ca7e4c
4 changed files with 166 additions and 9 deletions

View file

@ -1,5 +1,6 @@
mod bool;
mod char;
mod number;
mod value;
#[cfg(test)]

View file

@ -0,0 +1,55 @@
/* types/src/number/integer.rs
* Eryn Wells <eryn@erynwells.me>
*/
use std::any::Any;
use value::*;
use super::*;
#[derive(Debug, Eq, PartialEq)]
pub struct Integer(pub Int);
impl Number for Integer {
fn convert_down(&self) -> Option<Box<Number>> { None }
}
impl Value for Integer {
fn as_value(&self) -> &Value { self }
}
impl IsBool for Integer { }
impl IsChar for Integer { }
impl IsNumber for Integer {
fn is_integer(&self) -> bool { true }
}
impl ValueEq for Integer {
fn eq(&self, other: &Value) -> bool {
other.as_any().downcast_ref::<Self>().map_or(false, |x| x == self)
}
fn as_any(&self) -> &Any { self }
}
#[cfg(test)]
mod tests {
use super::Integer;
use value::*;
#[test]
fn equal_integers_are_equal() {
assert_eq!(Integer(3), Integer(3));
assert_ne!(Integer(12), Integer(9));
assert_eq!(Integer(4).as_value(), Integer(4).as_value());
assert_ne!(Integer(5).as_value(), Integer(7).as_value());
}
#[test]
fn integers_are_integers() {
assert_eq!(Integer(4).is_integer(), true);
assert_eq!(Integer(4).is_number(), true);
assert_eq!(Integer(6).is_char(), false);
assert_eq!(Integer(6).is_bool(), false);
}
}

View file

@ -1,4 +1,4 @@
/* number.rs
/* types/src/number/mod.rs
* Eryn Wells <eryn@erynwells.me>
*/
@ -6,19 +6,40 @@
///
/// Scheme numbers are complex, literally.
pub mod integer;
pub mod rational;
pub use self::integer::Integer;
pub use self::rational::Rational;
use std::any::Any;
use std::fmt::Debug;
use std::ops::Deref;
use super::value::*;
type Int = i64;
type Flt = f64;
trait Number {
fn is_number(&self) -> bool { true }
fn is_complex(&self) -> bool { false }
fn is_real(&self) -> bool { false }
fn is_rational(&self) -> bool { false }
fn is_integer(&self) -> bool { false }
trait Number: Debug + IsBool + IsChar + IsNumber + Value {
fn convert_down(&self) -> Option<Box<Number>>;
}
impl Value for Box<Number> {
fn as_value(&self) -> &Value { self.deref().as_value() }
}
impl IsBool for Box<Number> { }
impl IsChar for Box<Number> { }
impl IsNumber for Box<Number> { }
impl ValueEq for Box<Number> {
fn eq(&self, other: &Value) -> bool {
self.deref().eq(other)
}
fn as_any(&self) -> &Any { self }
}
struct Integer(Int);
struct Rational(Int, Int);
struct Real(Flt);
struct Complex<'a>(&'a Number, &'a Number);

View file

@ -0,0 +1,80 @@
/* types/src/number/rational.rs
* Eryn Wells <eryn@erynwells.me>
*/
use std::any::Any;
use value::*;
use super::*;
#[derive(Debug, Eq, PartialEq)]
pub struct Rational(pub Int, pub Int);
impl Number for Rational {
fn convert_down(&self) -> Option<Box<Number>> {
if self.1 == 1 {
Some(Box::new(Integer(self.0)))
}
else {
None
}
}
}
impl Value for Rational {
fn as_value(&self) -> &Value { self }
}
impl IsBool for Rational { }
impl IsChar for Rational { }
impl IsNumber for Rational {
fn is_rational(&self) -> bool { true }
}
impl ValueEq for Rational {
fn eq(&self, other: &Value) -> bool {
other.as_any().downcast_ref::<Self>().map_or(false, |x| x == self)
}
fn as_any(&self) -> &Any { self }
}
#[cfg(test)]
mod tests {
use std::ops::Deref;
use number::*;
use value::*;
#[test]
fn equal_rationals_are_equal() {
assert_eq!(Rational(3, 2), Rational(3, 2));
assert_ne!(Rational(12, 4), Rational(9, 7));
assert_eq!(Rational(4, 5).as_value(), Rational(4, 5).as_value());
assert_ne!(Rational(5, 6).as_value(), Rational(7, 6).as_value());
}
#[test]
fn rationals_are_rationals() {
assert_eq!(Rational(4, 3).is_rational(), true);
assert_eq!(Rational(4, 3).is_integer(), false);
assert_eq!(Rational(4, 3).is_number(), true);
assert_eq!(Rational(6, 8).is_char(), false);
assert_eq!(Rational(6, 9).is_bool(), false);
}
#[test]
fn rationals_should_reduce_to_integers_where_possible() {
let rational_as_integer = Rational(3, 1).convert_down();
assert!(rational_as_integer.is_some());
// Oh my god this line is so dumb.
let rational_as_integer = rational_as_integer.unwrap();
let rational_as_integer = rational_as_integer.as_value();
assert_eq!(rational_as_integer.deref(), Integer(3).as_value());
}
#[test]
fn rationals_should_not_reduce_to_integers_where_impossible() {
let rational_as_integer = Rational(3, 2).convert_down();
assert!(rational_as_integer.is_none());
}
}