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 SubtractFn { }
11+ impl ToValue for SubtractFn {
12+ fn to_value ( & self ) -> Value {
13+ Value :: IFn ( Rc :: new ( self . clone ( ) ) )
14+ }
15+ }
16+ impl IFn for SubtractFn {
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 :: I32 ( -a_) ,
24+ Value :: F64 ( f_) => Value :: F64 ( -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 subtract_tests {
64+ use crate :: rust_core:: _subtract_:: SubtractFn ;
65+ use crate :: ifn:: IFn ;
66+ use crate :: value:: Value ;
67+ use std:: rc:: Rc ;
68+
69+ #[ test]
70+ fn subtract_without_arguments_returns_one ( ) {
71+ let subtract = SubtractFn { } ;
72+ let args = vec ! [ ] ;
73+ assert_eq ! ( Value :: Condition ( String :: from( "Wrong number of arguments given to function (Given: 0)" ) ) ,
74+ subtract. invoke( args) ) ;
75+ }
76+
77+ #[ test]
78+ fn subtract_with_one_positive_argument_returns_negated_value ( ) {
79+ let subtract = SubtractFn { } ;
80+ let args = vec ! [ Rc :: new( Value :: I32 ( 5 ) ) ] ;
81+ assert_eq ! ( Value :: I32 ( -5 ) , subtract. invoke( args) ) ;
82+ }
83+
84+ #[ test]
85+ fn subtract_with_one_negative_argument_returns_positive_value ( ) {
86+ let subtract = SubtractFn { } ;
87+ let args = vec ! [ Rc :: new( Value :: I32 ( -5 ) ) ] ;
88+ assert_eq ! ( Value :: I32 ( 5 ) , subtract. invoke( args) ) ;
89+ }
90+
91+ #[ test]
92+ fn subtract_with_two_argument_returns_negative_difference ( ) {
93+ let subtract = SubtractFn { } ;
94+ let args = vec ! [ Rc :: new( Value :: I32 ( 5 ) ) , Rc :: new( Value :: I32 ( 6 ) ) ] ;
95+ assert_eq ! ( Value :: I32 ( -1 ) , subtract. invoke( args) ) ;
96+ }
97+
98+ #[ test]
99+ fn subtract_with_two_argument_returns_positive_difference ( ) {
100+ let subtract = SubtractFn { } ;
101+ let args = vec ! [ Rc :: new( Value :: I32 ( 6 ) ) , Rc :: new( Value :: I32 ( 5 ) ) ] ;
102+ assert_eq ! ( Value :: I32 ( 1 ) , subtract. invoke( args) ) ;
103+ }
104+
105+ #[ test]
106+ fn subtract_with_multiple_arguments_returns_difference_case1 ( ) {
107+ let subtract = SubtractFn { } ;
108+ let args = vec ! [
109+ Rc :: new( Value :: I32 ( -3 ) ) ,
110+ Rc :: new( Value :: I32 ( 7 ) ) ,
111+ Rc :: new( Value :: I32 ( 7 ) ) ,
112+ Rc :: new( Value :: I32 ( 4 ) ) ] ;
113+ assert_eq ! ( Value :: I32 ( -21 ) , subtract. invoke( args) ) ;
114+ }
115+
116+ #[ test]
117+ fn subtract_with_multiple_arguments_returns_difference_case2 ( ) {
118+ let subtract = SubtractFn { } ;
119+ let args = vec ! [
120+ Rc :: new( Value :: I32 ( -3 ) ) ,
121+ Rc :: new( Value :: I32 ( 7 ) ) ,
122+ Rc :: new( Value :: I32 ( -7 ) ) ,
123+ Rc :: new( Value :: I32 ( -4 ) ) ] ;
124+ assert_eq ! ( Value :: I32 ( 1 ) , subtract. invoke( args) ) ;
125+ }
126+ }
127+ }
0 commit comments