more tests/start on code instructions
This commit is contained in:
parent
5fe9ca40c6
commit
8eeef3a928
296
src/instructions/code.rs
Normal file
296
src/instructions/code.rs
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
use std::ops::Not;
|
||||||
|
|
||||||
|
use crate::push::state::{Gene, PushState};
|
||||||
|
|
||||||
|
/// Checks to see if a single gene is a block.
|
||||||
|
fn _is_block(vals: Vec<Gene>) -> Option<bool> {
|
||||||
|
Some(match vals[0] {
|
||||||
|
Gene::Block(_) => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
make_instruction_clone!(code, boolean, _is_block, Gene, 1);
|
||||||
|
|
||||||
|
/// Checks to see if a single gene is not a block.
|
||||||
|
fn _is_singular(vals: Vec<Gene>) -> Option<bool> {
|
||||||
|
Some(_is_block(vals)?.not())
|
||||||
|
}
|
||||||
|
make_instruction_clone!(code, boolean, _is_singular, Gene, 1);
|
||||||
|
|
||||||
|
/// Returns the length of a block, else 1 if not a block
|
||||||
|
fn _length(vals: Vec<Gene>) -> Option<i128> {
|
||||||
|
Some(match &vals[0] {
|
||||||
|
Gene::Block(x) => x.len() as i128,
|
||||||
|
_ => 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
make_instruction_clone!(code, int, _length, Gene, 1);
|
||||||
|
|
||||||
|
/// Returns the first item in a block if doable, else None
|
||||||
|
fn _first(vals: Vec<Gene>) -> Option<Gene> {
|
||||||
|
match &vals[0] {
|
||||||
|
Gene::Block(x) => {
|
||||||
|
if x.len() > 1 {
|
||||||
|
Some(x[0].clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
make_instruction_clone!(code, code, _first, Gene, 1);
|
||||||
|
|
||||||
|
/// Returns the first item in a block if applicable, else None
|
||||||
|
fn _last(vals: Vec<Gene>) -> Option<Gene> {
|
||||||
|
match &vals[0] {
|
||||||
|
Gene::Block(x) => {
|
||||||
|
if x.len() > 1 {
|
||||||
|
Some(x.last()?.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
make_instruction_clone!(code, code, _last, Gene, 1);
|
||||||
|
|
||||||
|
/// Returns all but the first code item in a block if applicable, else None
|
||||||
|
fn _rest(vals: Vec<Gene>) -> Option<Gene> {
|
||||||
|
match &vals[0] {
|
||||||
|
Gene::Block(x) => {
|
||||||
|
if x.len() > 1 {
|
||||||
|
Some(Gene::Block(Box::new(x[1..].to_vec())))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
make_instruction_clone!(code, code, _rest, Gene, 1);
|
||||||
|
|
||||||
|
/// Returns all but the first code item in a block if applicable, else None
|
||||||
|
fn _but_last(vals: Vec<Gene>) -> Option<Gene> {
|
||||||
|
match &vals[0] {
|
||||||
|
Gene::Block(x) => {
|
||||||
|
let x_len = x.len();
|
||||||
|
if x_len > 1 {
|
||||||
|
Some(Gene::Block(Box::new(x[..x_len - 1].to_vec())))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
make_instruction_clone!(code, code, _but_last, Gene, 1);
|
||||||
|
|
||||||
|
/// Returns all of the vals wrapped in a code block
|
||||||
|
fn _wrap_block(vals: Vec<Gene>) -> Option<Gene> {
|
||||||
|
Some(Gene::Block(Box::new(vals)))
|
||||||
|
}
|
||||||
|
make_instruction_clone!(code, code, _wrap_block, Gene, 1);
|
||||||
|
|
||||||
|
/// Combines two genes into one. Accounts for blocks.
|
||||||
|
/// If the second gene is a block and the first one isn't,
|
||||||
|
/// appends the first gene to the second gene.
|
||||||
|
fn _combine(vals: Vec<Gene>) -> Option<Gene> {
|
||||||
|
match (&vals[0], &vals[1]) {
|
||||||
|
(Gene::Block(x), Gene::Block(y)) => {
|
||||||
|
let mut x_clone = x.clone();
|
||||||
|
let y_clone = y.clone();
|
||||||
|
x_clone.extend(y_clone.into_iter());
|
||||||
|
Some(Gene::Block(x_clone))
|
||||||
|
}
|
||||||
|
(Gene::Block(x), y) => {
|
||||||
|
let mut x_clone = x.clone();
|
||||||
|
x_clone.push(y.clone());
|
||||||
|
Some(Gene::Block(x_clone))
|
||||||
|
}
|
||||||
|
(x, Gene::Block(y)) => {
|
||||||
|
let mut y_clone = y.clone();
|
||||||
|
y_clone.push(x.clone());
|
||||||
|
Some(Gene::Block(y_clone))
|
||||||
|
}
|
||||||
|
(x, y) => Some(Gene::Block(Box::new(vec![x.clone(), y.clone()]))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
make_instruction_clone!(code, code, _combine, Gene, 1);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::push::state::EMPTY_STATE;
|
||||||
|
use rust_decimal::dec;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is_block_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::Block(Box::new(vec![]))];
|
||||||
|
code_is_block(&mut test_state);
|
||||||
|
assert_eq!(vec![true], test_state.boolean);
|
||||||
|
test_state.boolean.clear();
|
||||||
|
|
||||||
|
test_state.code = vec![(Gene::GeneInt(1))];
|
||||||
|
code_is_block(&mut test_state);
|
||||||
|
assert_eq!(vec![false], test_state.boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn is_singular_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::Block(Box::new(vec![]))];
|
||||||
|
code_is_singular(&mut test_state);
|
||||||
|
assert_eq!(vec![false], test_state.boolean);
|
||||||
|
test_state.boolean.clear();
|
||||||
|
|
||||||
|
test_state.code = vec![(Gene::GeneInt(1))];
|
||||||
|
code_is_singular(&mut test_state);
|
||||||
|
assert_eq!(vec![true], test_state.boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn length_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneFloat(dec!(3.8)),
|
||||||
|
]))];
|
||||||
|
code_length(&mut test_state);
|
||||||
|
assert_eq!(vec![2], test_state.int);
|
||||||
|
test_state.int.clear();
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::Block(Box::new(vec![]))];
|
||||||
|
code_length(&mut test_state);
|
||||||
|
assert_eq!(vec![0], test_state.int);
|
||||||
|
test_state.int.clear();
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::GeneInt(3)];
|
||||||
|
code_length(&mut test_state);
|
||||||
|
assert_eq!(vec![1], test_state.int);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn first_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneFloat(dec!(3.8)),
|
||||||
|
]))];
|
||||||
|
code_first(&mut test_state);
|
||||||
|
assert_eq!(vec![Gene::GeneInt(1)], test_state.code);
|
||||||
|
|
||||||
|
test_state.code = vec![];
|
||||||
|
code_first(&mut test_state);
|
||||||
|
let empty_vec: Vec<Gene> = vec![];
|
||||||
|
assert_eq!(empty_vec, test_state.code);
|
||||||
|
drop(empty_vec);
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::GeneInt(1)];
|
||||||
|
code_first(&mut test_state);
|
||||||
|
assert_eq!(vec![Gene::GeneInt(1)], test_state.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn last_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneFloat(dec!(3.8)),
|
||||||
|
]))];
|
||||||
|
code_last(&mut test_state);
|
||||||
|
assert_eq!(vec![Gene::GeneFloat(dec!(3.8))], test_state.code);
|
||||||
|
|
||||||
|
test_state.code = vec![];
|
||||||
|
code_last(&mut test_state);
|
||||||
|
let empty_vec: Vec<Gene> = vec![];
|
||||||
|
assert_eq!(empty_vec, test_state.code);
|
||||||
|
drop(empty_vec);
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::GeneInt(1)];
|
||||||
|
code_last(&mut test_state);
|
||||||
|
assert_eq!(vec![Gene::GeneInt(1)], test_state.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rest_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneFloat(dec!(3.8)),
|
||||||
|
Gene::GeneBoolean(true),
|
||||||
|
]))];
|
||||||
|
code_rest(&mut test_state);
|
||||||
|
assert_eq!(
|
||||||
|
vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneFloat(dec!(3.8)),
|
||||||
|
Gene::GeneBoolean(true)
|
||||||
|
]))],
|
||||||
|
test_state.code
|
||||||
|
);
|
||||||
|
|
||||||
|
test_state.code = vec![];
|
||||||
|
code_rest(&mut test_state);
|
||||||
|
let empty_vec: Vec<Gene> = vec![];
|
||||||
|
assert_eq!(empty_vec, test_state.code);
|
||||||
|
drop(empty_vec);
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::GeneInt(1)];
|
||||||
|
code_rest(&mut test_state);
|
||||||
|
assert_eq!(vec![Gene::GeneInt(1)], test_state.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn but_last_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneFloat(dec!(3.8)),
|
||||||
|
Gene::GeneBoolean(true),
|
||||||
|
]))];
|
||||||
|
code_but_last(&mut test_state);
|
||||||
|
assert_eq!(
|
||||||
|
vec![Gene::Block(Box::new(vec![
|
||||||
|
Gene::GeneInt(1),
|
||||||
|
Gene::GeneFloat(dec!(3.8)),
|
||||||
|
]))],
|
||||||
|
test_state.code
|
||||||
|
);
|
||||||
|
|
||||||
|
test_state.code = vec![];
|
||||||
|
code_but_last(&mut test_state);
|
||||||
|
let empty_vec: Vec<Gene> = vec![];
|
||||||
|
assert_eq!(empty_vec, test_state.code);
|
||||||
|
drop(empty_vec);
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::GeneInt(1)];
|
||||||
|
code_but_last(&mut test_state);
|
||||||
|
assert_eq!(vec![Gene::GeneInt(1)], test_state.code);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wrap_block_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.code = vec![Gene::GeneInt(1)];
|
||||||
|
code_wrap_block(&mut test_state);
|
||||||
|
assert_eq!(
|
||||||
|
vec![Gene::Block(Box::new(vec![Gene::GeneInt(1)]))],
|
||||||
|
test_state.code
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn combine_test() {
|
||||||
|
// TODO: This later
|
||||||
|
}
|
||||||
|
}
|
@ -2,8 +2,9 @@
|
|||||||
//!
|
//!
|
||||||
//! This file holds instructions for the boolean stack.
|
//! This file holds instructions for the boolean stack.
|
||||||
|
|
||||||
use super::utils::{LogicalTrait, NumericTrait};
|
use super::utils::{CastingTrait, LogicalTrait};
|
||||||
use crate::push::state::PushState;
|
use crate::push::state::PushState;
|
||||||
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
/// Runs logical and on two values
|
/// Runs logical and on two values
|
||||||
fn _and<T>(vals: Vec<T>) -> Option<T>
|
fn _and<T>(vals: Vec<T>) -> Option<T>
|
||||||
@ -59,17 +60,40 @@ where
|
|||||||
}
|
}
|
||||||
make_instruction!(boolean, boolean, _invert_second_then_and, bool, 2);
|
make_instruction!(boolean, boolean, _invert_second_then_and, bool, 2);
|
||||||
|
|
||||||
// fn _to_int<T>(vals: Vec<T>) -> Option<T>
|
fn _from_int<T>(vals: Vec<i128>) -> Option<T>
|
||||||
// where
|
where
|
||||||
// T: Copy + NumericTrait,
|
T: Copy + CastingTrait,
|
||||||
// {
|
{
|
||||||
// Some(T::from_bool(vals))
|
T::from_int(vals[0])
|
||||||
// }
|
}
|
||||||
|
make_instruction_out!(int, boolean, _from_int, i128, 1);
|
||||||
|
|
||||||
|
fn _from_float<T>(vals: Vec<Decimal>) -> Option<T>
|
||||||
|
where
|
||||||
|
T: Copy + CastingTrait,
|
||||||
|
{
|
||||||
|
T::from_float(vals[0])
|
||||||
|
}
|
||||||
|
make_instruction_out!(float, boolean, _from_float, Decimal, 1);
|
||||||
|
|
||||||
|
pub fn boolean_instructions() -> Vec<fn(&mut PushState)> {
|
||||||
|
vec![
|
||||||
|
boolean_and,
|
||||||
|
boolean_or,
|
||||||
|
boolean_not,
|
||||||
|
boolean_xor,
|
||||||
|
boolean_invert_first_then_and,
|
||||||
|
boolean_invert_second_then_and,
|
||||||
|
boolean_from_int,
|
||||||
|
boolean_from_float,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::push::state::EMPTY_STATE;
|
use crate::push::state::EMPTY_STATE;
|
||||||
|
use rust_decimal::dec;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn and_test() {
|
fn and_test() {
|
||||||
@ -147,4 +171,28 @@ mod tests {
|
|||||||
boolean_invert_second_then_and(&mut test_state);
|
boolean_invert_second_then_and(&mut test_state);
|
||||||
assert_eq!(vec![true], test_state.boolean);
|
assert_eq!(vec![true], test_state.boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_test() {
|
||||||
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
|
test_state.int = vec![1];
|
||||||
|
boolean_from_int(&mut test_state);
|
||||||
|
assert_eq!(vec![true], test_state.boolean);
|
||||||
|
test_state.boolean.clear();
|
||||||
|
|
||||||
|
test_state.int = vec![0];
|
||||||
|
boolean_from_int(&mut test_state);
|
||||||
|
assert_eq!(vec![false], test_state.boolean);
|
||||||
|
test_state.boolean.clear();
|
||||||
|
|
||||||
|
test_state.float = vec![dec!(2.0)];
|
||||||
|
boolean_from_float(&mut test_state);
|
||||||
|
assert_eq!(vec![true], test_state.boolean);
|
||||||
|
test_state.boolean.clear();
|
||||||
|
|
||||||
|
test_state.float = vec![dec!(0.0)];
|
||||||
|
boolean_from_float(&mut test_state);
|
||||||
|
assert_eq!(vec![false], test_state.boolean);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,66 @@ pub mod macros {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The same as make_instruction above but prepends the output
|
||||||
|
/// stack to the function name rather than the input stack.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! make_instruction_out {
|
||||||
|
($in_stack:ident, $out_stack:ident, $fn_name:ident, $fn_type:ty, $fn_arity:stmt) => {
|
||||||
|
paste::item! {
|
||||||
|
/// Runs the $fn_name function on the top $fn_arity items from
|
||||||
|
/// the $in_stack and places the calculated value on the $out_stack.
|
||||||
|
pub fn [< $out_stack $fn_name >] (state: &mut PushState) {
|
||||||
|
let in_stack_len = state.$in_stack.len();
|
||||||
|
if in_stack_len < $fn_arity {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut inputs: Vec<$fn_type> = Vec::with_capacity($fn_arity);
|
||||||
|
for n in 1..=$fn_arity {
|
||||||
|
inputs.push(state.$in_stack[in_stack_len - n]);
|
||||||
|
}
|
||||||
|
if let Some(result) = $fn_name(inputs) {
|
||||||
|
for _ in 0..$fn_arity {
|
||||||
|
state.$in_stack.pop();
|
||||||
|
}
|
||||||
|
state.$out_stack.push(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The same as make_instruction but uses clone() to fill the arguments
|
||||||
|
/// to each function rather than a reference. Is slower, but will be okay
|
||||||
|
/// for the time being.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! make_instruction_clone {
|
||||||
|
($in_stack:ident, $out_stack:ident, $fn_name:ident, $fn_type:ty, $fn_arity:stmt) => {
|
||||||
|
paste::item! {
|
||||||
|
/// Runs the $fn_name function on the top $fn_arity items from
|
||||||
|
/// the $in_stack and places the calculated value on the $out_stack.
|
||||||
|
pub fn [< $in_stack $fn_name >] (state: &mut PushState) {
|
||||||
|
let in_stack_len = state.$in_stack.len();
|
||||||
|
if in_stack_len < $fn_arity {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut inputs: Vec<$fn_type> = Vec::with_capacity($fn_arity);
|
||||||
|
for n in 1..=$fn_arity {
|
||||||
|
inputs.push(state.$in_stack[in_stack_len - n].clone());
|
||||||
|
}
|
||||||
|
if let Some(result) = $fn_name(inputs) {
|
||||||
|
for _ in 0..$fn_arity {
|
||||||
|
state.$in_stack.pop();
|
||||||
|
}
|
||||||
|
state.$out_stack.push(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod code;
|
||||||
pub mod logical;
|
pub mod logical;
|
||||||
pub mod numeric;
|
pub mod numeric;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
@ -11,7 +11,7 @@ use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
|
|||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::ops::{Add, Div, Mul, Sub};
|
use std::ops::{Add, Div, Mul, Sub};
|
||||||
|
|
||||||
use super::utils::NumericTrait;
|
use super::utils::{CastingTrait, NumericTrait};
|
||||||
|
|
||||||
/// Adds two addable values together.
|
/// Adds two addable values together.
|
||||||
fn _add<T>(vals: Vec<T>) -> Option<T>
|
fn _add<T>(vals: Vec<T>) -> Option<T>
|
||||||
@ -203,27 +203,33 @@ where
|
|||||||
make_instruction!(int, int, _arctan, i128, 1);
|
make_instruction!(int, int, _arctan, i128, 1);
|
||||||
make_instruction!(float, float, _arctan, Decimal, 1);
|
make_instruction!(float, float, _arctan, Decimal, 1);
|
||||||
|
|
||||||
/// Converts the top int to a float.
|
/// Converts a single value from a float to an arbitrary type.
|
||||||
fn _to_int(vals: Vec<Decimal>) -> Option<i128> {
|
fn _from_int<T>(vals: Vec<i128>) -> Option<T>
|
||||||
vals[0].to_i128()
|
|
||||||
}
|
|
||||||
make_instruction!(float, int, _to_int, Decimal, 1);
|
|
||||||
|
|
||||||
/// Converts the top float to an int.
|
|
||||||
fn _to_float(vals: Vec<i128>) -> Option<Decimal> {
|
|
||||||
Decimal::from_i128(vals[0])
|
|
||||||
}
|
|
||||||
make_instruction!(int, float, _to_float, i128, 1);
|
|
||||||
|
|
||||||
/// Converts a single number to a bool.
|
|
||||||
fn _from_bool<T>(vals: Vec<bool>) -> Option<T>
|
|
||||||
where
|
where
|
||||||
T: Copy + NumericTrait,
|
T: Copy + CastingTrait,
|
||||||
{
|
{
|
||||||
Some(T::from_bool(vals[0]))
|
T::from_int(vals[0])
|
||||||
}
|
}
|
||||||
make_instruction!(int, boolean, _from_bool, bool, 1);
|
make_instruction_out!(int, float, _from_int, i128, 1);
|
||||||
make_instruction!(float, boolean, _from_bool, bool, 1);
|
|
||||||
|
/// Converts a single value from a float to an arbitrary type.
|
||||||
|
fn _from_float<T>(vals: Vec<Decimal>) -> Option<T>
|
||||||
|
where
|
||||||
|
T: Copy + CastingTrait,
|
||||||
|
{
|
||||||
|
T::from_float(vals[0])
|
||||||
|
}
|
||||||
|
make_instruction_out!(float, int, _from_float, Decimal, 1);
|
||||||
|
|
||||||
|
/// Converts a bool to a to a new type.
|
||||||
|
fn _from_boolean<T>(vals: Vec<bool>) -> Option<T>
|
||||||
|
where
|
||||||
|
T: Copy + CastingTrait,
|
||||||
|
{
|
||||||
|
T::from_bool(vals[0])
|
||||||
|
}
|
||||||
|
make_instruction_out!(boolean, int, _from_boolean, bool, 1);
|
||||||
|
make_instruction_out!(boolean, float, _from_boolean, bool, 1);
|
||||||
|
|
||||||
/// Takes the log base 10 of a single Decimal. Acts as a
|
/// Takes the log base 10 of a single Decimal. Acts as a
|
||||||
/// NoOp if the value is 0. If the value is negative, takes
|
/// NoOp if the value is 0. If the value is negative, takes
|
||||||
@ -321,8 +327,8 @@ pub fn int_instructions() -> Vec<fn(&mut PushState)> {
|
|||||||
int_arccos,
|
int_arccos,
|
||||||
int_tan,
|
int_tan,
|
||||||
int_arctan,
|
int_arctan,
|
||||||
int_to_float,
|
int_from_float,
|
||||||
int_to_bool,
|
int_from_boolean,
|
||||||
int_log,
|
int_log,
|
||||||
int_exp,
|
int_exp,
|
||||||
int_sqrt,
|
int_sqrt,
|
||||||
@ -355,8 +361,8 @@ pub fn float_instructions() -> Vec<fn(&mut PushState)> {
|
|||||||
float_arccos,
|
float_arccos,
|
||||||
float_tan,
|
float_tan,
|
||||||
float_arctan,
|
float_arctan,
|
||||||
float_to_int,
|
float_from_int,
|
||||||
float_to_bool,
|
float_from_boolean,
|
||||||
float_log,
|
float_log,
|
||||||
float_exp,
|
float_exp,
|
||||||
float_sqrt,
|
float_sqrt,
|
||||||
@ -542,17 +548,6 @@ mod tests {
|
|||||||
assert_eq!(Some(dec!(1.0000000043184676055890307049)), _arctan(vals));
|
assert_eq!(Some(dec!(1.0000000043184676055890307049)), _arctan(vals));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tests the functions that cast from one numeric type
|
|
||||||
/// to another
|
|
||||||
#[test]
|
|
||||||
fn cast_tests() {
|
|
||||||
let vals = vec![dec!(1.2)];
|
|
||||||
assert_eq!(Some(1), _to_int(vals));
|
|
||||||
|
|
||||||
let vals: Vec<i128> = vec![2];
|
|
||||||
assert_eq!(Some(dec!(2.0)), _to_float(vals));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tests that the various addition functions.
|
/// Tests that the various addition functions.
|
||||||
#[test]
|
#[test]
|
||||||
fn state_add() {
|
fn state_add() {
|
||||||
@ -793,32 +788,13 @@ mod tests {
|
|||||||
let mut test_state = EMPTY_STATE;
|
let mut test_state = EMPTY_STATE;
|
||||||
|
|
||||||
test_state.int = vec![0, 1];
|
test_state.int = vec![0, 1];
|
||||||
int_to_float(&mut test_state);
|
float_from_int(&mut test_state);
|
||||||
assert_eq!(vec![dec!(1.0)], test_state.float);
|
assert_eq!(vec![dec!(1.0)], test_state.float);
|
||||||
|
|
||||||
test_state.int.clear();
|
test_state.int.clear();
|
||||||
|
|
||||||
test_state.float = vec![dec!(2.1)];
|
test_state.float = vec![dec!(2.1)];
|
||||||
float_to_int(&mut test_state);
|
int_from_float(&mut test_state);
|
||||||
assert_eq!(vec![2], test_state.int);
|
assert_eq!(vec![2], test_state.int);
|
||||||
|
|
||||||
test_state.int = vec![1];
|
|
||||||
int_to_bool(&mut test_state);
|
|
||||||
assert_eq!(vec![true], test_state.boolean);
|
|
||||||
test_state.boolean.clear();
|
|
||||||
|
|
||||||
test_state.int = vec![0];
|
|
||||||
int_to_bool(&mut test_state);
|
|
||||||
assert_eq!(vec![false], test_state.boolean);
|
|
||||||
test_state.boolean.clear();
|
|
||||||
|
|
||||||
test_state.float = vec![dec!(2.0)];
|
|
||||||
float_to_bool(&mut test_state);
|
|
||||||
assert_eq!(vec![true], test_state.boolean);
|
|
||||||
test_state.boolean.clear();
|
|
||||||
|
|
||||||
test_state.float = vec![dec!(0.0)];
|
|
||||||
float_to_bool(&mut test_state);
|
|
||||||
assert_eq!(vec![false], test_state.boolean);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tests the log function
|
/// Tests the log function
|
||||||
|
@ -21,10 +21,8 @@ pub trait NumericTrait: Sized + Div<Output = Self> {
|
|||||||
fn absolute(self) -> Self;
|
fn absolute(self) -> Self;
|
||||||
fn safe_log10(self) -> Option<Self>;
|
fn safe_log10(self) -> Option<Self>;
|
||||||
fn safe_sqrt(self) -> Option<Self>;
|
fn safe_sqrt(self) -> Option<Self>;
|
||||||
fn to_bool(self) -> bool;
|
|
||||||
fn sign_reverse(self) -> Self;
|
fn sign_reverse(self) -> Self;
|
||||||
fn square(self) -> Self;
|
fn square(self) -> Self;
|
||||||
fn from_bool(v: bool) -> Self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NumericTrait for Decimal {
|
impl NumericTrait for Decimal {
|
||||||
@ -64,18 +62,12 @@ impl NumericTrait for Decimal {
|
|||||||
fn safe_sqrt(self) -> Option<Self> {
|
fn safe_sqrt(self) -> Option<Self> {
|
||||||
self.absolute().sqrt()
|
self.absolute().sqrt()
|
||||||
}
|
}
|
||||||
fn to_bool(self) -> bool {
|
|
||||||
if self == dec!(0.0) { false } else { true }
|
|
||||||
}
|
|
||||||
fn sign_reverse(self) -> Self {
|
fn sign_reverse(self) -> Self {
|
||||||
self * dec!(-1)
|
self * dec!(-1)
|
||||||
}
|
}
|
||||||
fn square(self) -> Self {
|
fn square(self) -> Self {
|
||||||
self * self
|
self * self
|
||||||
}
|
}
|
||||||
fn from_bool(v: bool) -> Self {
|
|
||||||
if v { dec!(1.0) } else { dec!(0.0) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NumericTrait for i128 {
|
impl NumericTrait for i128 {
|
||||||
@ -120,20 +112,16 @@ impl NumericTrait for i128 {
|
|||||||
fn safe_sqrt(self) -> Option<Self> {
|
fn safe_sqrt(self) -> Option<Self> {
|
||||||
Decimal::from_i128(self)?.absolute().sqrt()?.to_i128()
|
Decimal::from_i128(self)?.absolute().sqrt()?.to_i128()
|
||||||
}
|
}
|
||||||
fn to_bool(self) -> bool {
|
|
||||||
if self == 0 { false } else { true }
|
|
||||||
}
|
|
||||||
fn sign_reverse(self) -> Self {
|
fn sign_reverse(self) -> Self {
|
||||||
-1 * self
|
-1 * self
|
||||||
}
|
}
|
||||||
fn square(self) -> Self {
|
fn square(self) -> Self {
|
||||||
self * self
|
self * self
|
||||||
}
|
}
|
||||||
fn from_bool(v: bool) -> Self {
|
|
||||||
if v { 1 } else { 0 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait for types to implement logical functions that work
|
||||||
|
/// for push types.
|
||||||
pub trait LogicalTrait {
|
pub trait LogicalTrait {
|
||||||
fn logical_and(self, v: Self) -> Self;
|
fn logical_and(self, v: Self) -> Self;
|
||||||
fn logical_or(self, v: Self) -> Self;
|
fn logical_or(self, v: Self) -> Self;
|
||||||
@ -158,3 +146,46 @@ impl LogicalTrait for bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait for uniform conversions between types.
|
||||||
|
pub trait CastingTrait: Sized {
|
||||||
|
fn from_bool(v: bool) -> Option<Self>;
|
||||||
|
fn from_int(v: i128) -> Option<Self>;
|
||||||
|
fn from_float(v: Decimal) -> Option<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CastingTrait for i128 {
|
||||||
|
fn from_bool(v: bool) -> Option<Self> {
|
||||||
|
Some(if v { 1 } else { 0 })
|
||||||
|
}
|
||||||
|
fn from_int(v: i128) -> Option<Self> {
|
||||||
|
Some(v)
|
||||||
|
}
|
||||||
|
fn from_float(v: Decimal) -> Option<Self> {
|
||||||
|
v.to_i128()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CastingTrait for Decimal {
|
||||||
|
fn from_bool(v: bool) -> Option<Self> {
|
||||||
|
Some(if v { dec!(1.0) } else { dec!(0.0) })
|
||||||
|
}
|
||||||
|
fn from_int(v: i128) -> Option<Self> {
|
||||||
|
Decimal::from_i128(v)
|
||||||
|
}
|
||||||
|
fn from_float(v: Decimal) -> Option<Self> {
|
||||||
|
Some(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CastingTrait for bool {
|
||||||
|
fn from_bool(v: bool) -> Option<Self> {
|
||||||
|
Some(v)
|
||||||
|
}
|
||||||
|
fn from_int(v: i128) -> Option<Self> {
|
||||||
|
Some(if v != 0 { true } else { false })
|
||||||
|
}
|
||||||
|
fn from_float(v: Decimal) -> Option<Self> {
|
||||||
|
Some(if v != dec!(0.0) { true } else { false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
12
src/main.rs
12
src/main.rs
@ -20,13 +20,17 @@ fn main() {
|
|||||||
// let result = dec!(1.0) / Decimal::QUARTER_PI.tan();
|
// let result = dec!(1.0) / Decimal::QUARTER_PI.tan();
|
||||||
// let result = dec!(1.0) / Decimal::QUARTER_PI.cos();
|
// let result = dec!(1.0) / Decimal::QUARTER_PI.cos();
|
||||||
// let result = dec!(1.2).checked_exp();
|
// let result = dec!(1.2).checked_exp();
|
||||||
let result = dec!(2).log10();
|
// let result = dec!(2).log10();
|
||||||
|
let result = vec![0, 1, 2];
|
||||||
|
let r_len = result.len();
|
||||||
|
let fin_result = &result[..r_len - 1];
|
||||||
|
println!("{fin_result:?}");
|
||||||
|
|
||||||
println!("{result:?}");
|
// println!("{result:?}");
|
||||||
// println!("{sixth_pi}");
|
// println!("{sixth_pi}");
|
||||||
|
|
||||||
// casting a function call to a usize is a way to
|
// casting a function call to a usize is a way to
|
||||||
// test for function equality.
|
// test for function equality.
|
||||||
let test_func_result = test_func as usize == test_func as usize;
|
// let test_func_result = test_func as usize == test_func as usize;
|
||||||
println!("{test_func_result}");
|
// println!("{test_func_result}");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user