1+ use crate :: ifn:: IFn ;
2+ use crate :: value:: { Value , ToValue } ;
3+ use std:: rc:: Rc ;
4+
5+ use crate :: error_message;
6+
7+ /// (/ x y & xys)
8+ ///
9+ #[ derive( Debug , Clone ) ]
10+ pub struct DivideFn { }
11+ impl ToValue for DivideFn {
12+ fn to_value ( & self ) -> Value {
13+ Value :: IFn ( Rc :: new ( self . clone ( ) ) )
14+ }
15+ }
16+ impl IFn for DivideFn {
17+ fn invoke ( & self , args : Vec < Rc < Value > > ) -> Value {
18+ match args. len ( ) {
19+ 0 => { error_message:: zero_arg_count ( args. len ( ) ) } ,
20+ 1 => {
21+ let val = args. get ( 0 ) . unwrap ( ) . to_value ( ) ;
22+ match val {
23+ Value :: I32 ( a_) => Value :: F64 ( 1.0 / a_ as f64 ) ,
24+ Value :: F64 ( f_) => Value :: F64 ( 1.0 / f_) ,
25+ _ => Value :: Condition ( format ! ( // TODO: what error message should be returned regarding using typetags?
26+ "Type mismatch; Expecting: (i32 | i64 | f32 | f64), Found: {}" ,
27+ val. type_tag( )
28+ ) )
29+ }
30+ } ,
31+ _ => {
32+ let mut args_iterator = args. into_iter ( ) ;
33+ let first_arg = args_iterator. next ( ) . unwrap ( ) ;
34+ args_iterator. fold ( first_arg. to_value ( ) , |a, b| match a {
35+ Value :: I32 ( a_) => match * b {
36+ Value :: I32 ( b_) => Value :: I32 ( a_ / b_) ,
37+ Value :: F64 ( b_) => Value :: F64 ( a_ as f64 / b_) ,
38+ _ => Value :: Condition ( format ! ( // TODO: what error message should be returned regarding using typetags?
39+ "Type mismatch; Expecting: (i32 | i64 | f32 | f64), Found: {}" ,
40+ b. type_tag( )
41+ ) ) ,
42+ } ,
43+ Value :: F64 ( a_) => match * b {
44+ Value :: I32 ( b_) => Value :: F64 ( a_ / b_ as f64 ) ,
45+ Value :: F64 ( b_) => Value :: F64 ( a_ / b_) ,
46+ _ => Value :: Condition ( format ! ( // TODO: what error message should be returned regarding using typetags?
47+ "Type mismatch; Expecting: (i32 | i64 | f32 | f64), Found: {}" ,
48+ b. type_tag( )
49+ ) ) ,
50+ } ,
51+ _ => Value :: Condition ( format ! ( // TODO: what error message should be returned regarding using typetags?
52+ "Type mismatch: Expecting: (i32 | i64 | f32 | f64), Found: {}" ,
53+ a. type_tag( )
54+ ) ) ,
55+ } )
56+ }
57+ }
58+ }
59+ }
60+
61+ #[ cfg( test) ]
62+ mod tests {
63+ mod Divide_tests {
64+ use crate :: rust_core:: _divide_:: DivideFn ;
65+ use crate :: ifn:: IFn ;
66+ use crate :: value:: Value ;
67+ use std:: rc:: Rc ;
68+
69+ #[ test]
70+ fn Divide_without_arguments_returns_one ( ) {
71+ let Divide = DivideFn { } ;
72+ let args = vec ! [ ] ;
73+ assert_eq ! ( Value :: Condition ( String :: from( "Wrong number of arguments given to function (Given: 0)" ) ) ,
74+ Divide . invoke( args) ) ;
75+ }
76+
77+ #[ test]
78+ fn Divide_with_one_positive_argument_returns_reciprocal ( ) {
79+ let divide = DivideFn { } ;
80+ let args = vec ! [ Rc :: new( Value :: I32 ( 5 ) ) ] ;
81+ assert_eq ! ( Value :: F64 ( 1.0 /5.0 ) , divide. invoke( args) ) ;
82+ }
83+
84+ #[ test]
85+ fn Divide_with_one_negative_argument_returns_reciprocal ( ) {
86+ let divide = DivideFn { } ;
87+ let args = vec ! [ Rc :: new( Value :: I32 ( -5 ) ) ] ;
88+ assert_eq ! ( Value :: F64 ( 1.0 / -5.0 ) , divide. invoke( args) ) ;
89+ }
90+
91+ #[ test]
92+ fn Divide_with_two_integer_argument_returns_quotient ( ) {
93+ let divide = DivideFn { } ;
94+ let args = vec ! [ Rc :: new( Value :: I32 ( 24 ) ) , Rc :: new( Value :: I32 ( 6 ) ) ] ;
95+ assert_eq ! ( Value :: I32 ( 4 ) , divide. invoke( args) ) ;
96+ }
97+
98+ #[ test]
99+ fn Divide_with_one_double_argument_returns_quotient ( ) {
100+ let divide = DivideFn { } ;
101+ let args = vec ! [ Rc :: new( Value :: I32 ( 24 ) ) , Rc :: new( Value :: F64 ( 1.5 ) ) ] ;
102+ assert_eq ! ( Value :: F64 ( 16.0 ) , divide. invoke( args) ) ;
103+ }
104+
105+ #[ test]
106+ fn Divide_with_multiple_integer_arguments_returns_quotient ( ) {
107+ let Divide = DivideFn { } ;
108+ let args = vec ! [
109+ Rc :: new( Value :: I32 ( 100 ) ) ,
110+ Rc :: new( Value :: I32 ( 5 ) ) ,
111+ Rc :: new( Value :: I32 ( 4 ) ) ] ;
112+ assert_eq ! ( Value :: I32 ( 5 ) , Divide . invoke( args) ) ;
113+ }
114+
115+ #[ test]
116+ fn Divide_with_multiple_mixed_arguments_returns_quotient ( ) {
117+ let Divide = DivideFn { } ;
118+ let args = vec ! [
119+ Rc :: new( Value :: I32 ( 100 ) ) ,
120+ Rc :: new( Value :: I32 ( 5 ) ) ,
121+ Rc :: new( Value :: I32 ( 4 ) ) ,
122+ Rc :: new( Value :: F64 ( 2.0 ) ) ] ;
123+ assert_eq ! ( Value :: F64 ( 2.5 ) , Divide . invoke( args) ) ;
124+ }
125+
126+ }
127+ }
0 commit comments