Implement Integers and Rationals
This commit is contained in:
parent
0d3021fb74
commit
3e03ca7e4c
4 changed files with 166 additions and 9 deletions
|
@ -1,5 +1,6 @@
|
|||
mod bool;
|
||||
mod char;
|
||||
mod number;
|
||||
mod value;
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
55
types/src/number/integer.rs
Normal file
55
types/src/number/integer.rs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
80
types/src/number/rational.rs
Normal file
80
types/src/number/rational.rs
Normal 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());
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue