tachyon_math_library/
accessors.rs

1use crate::{reduce_value_codes, FunctionType, Interpolation, ValueCode, NUM_VALUES};
2use anchor_lang::prelude::*;
3use num_traits::{FromPrimitive, ToPrimitive};
4use rust_decimal::Decimal;
5
6use crate::error::ErrorCode;
7
8pub trait FunctionDataAccessors {
9    fn eval(&self, x: Decimal, interp: Interpolation, saturating: bool) -> Result<Decimal>;
10    fn eval_load(&self, x_in: Decimal, y_in: Decimal) -> Result<(Decimal, ValueCode)>;
11
12    fn get_values_array(&self) -> &[[u8; 16]; NUM_VALUES];
13    fn get_value_codes_array(&self) -> &[u8; NUM_VALUES];
14
15    fn get_values_array_mut(&mut self) -> &mut [[u8; 16]; NUM_VALUES];
16    fn get_value_codes_array_mut(&mut self) -> &mut [u8; NUM_VALUES];
17
18    fn get_function_type(&self) -> u32;
19    fn set_function_type(&mut self, ft: FunctionType) -> Result<()>;
20
21    fn get_domain_start(&self) -> Result<Decimal>;
22    fn set_domain_start(&mut self, domain_start_raw: [u8; 16]) -> Result<()>;
23
24    fn get_domain_end(&self) -> Result<Decimal>;
25    fn set_domain_end(&mut self, domain_end_raw: [u8; 16]) -> Result<()>;
26
27    fn get_interval(&self) -> Result<Decimal>;
28    fn set_interval(&mut self, interval: [u8; 16]) -> Result<()>;
29
30    fn get_num_values_loaded(&self) -> u32;
31    fn increment_num_values_loaded(&mut self) -> Result<()>;
32
33    fn get_is_initialized(&self) -> bool;
34    fn set_initialized_true(&mut self) -> Result<()>;
35
36    fn set_value(&mut self, index: u32, value: [u8; 16], value_code: u8) -> Result<()> {
37        let existing_code_u8 = self.get_value_code(index)?;
38        let existing_code = ValueCode::try_from(existing_code_u8).unwrap();
39
40        // throw an error here so that we keep an accurate count of the number of values loaded, to verify that all data has been loaded
41        if existing_code != ValueCode::Empty {
42            return err!(ErrorCode::DataAtIndexAlreadyLoaded);
43        }
44
45        self.get_values_array_mut()[index as usize] = value;
46        self.get_value_codes_array_mut()[index as usize] = value_code;
47
48        Ok(())
49    }
50
51    fn get_value(&self, index: u32) -> Result<Decimal> {
52        Ok(Decimal::deserialize(self.get_values_array()[index as usize]))
53    }
54
55    fn get_value_code(&self, index: u32) -> Result<u8> {
56        Ok(self.get_value_codes_array()[index as usize])
57    }
58
59    fn reduce_value_codes_from_indices(&self, indices: Vec<u32>) -> Result<ValueCode> {
60        let codes = indices.into_iter().map(|x| self.get_value_code(x).unwrap()).collect::<Vec<u8>>();
61        Ok(reduce_value_codes(codes))
62    }
63
64    fn get_domain(&self) -> Result<Decimal> {
65        let domain = (self.get_domain_end()? - self.get_domain_start()?).abs();
66        Ok(domain)
67    }
68
69    fn get_x_from_index(&self, index: u32) -> Result<Decimal> {
70        let index_prop = Decimal::from_u32(index).unwrap() / (Decimal::from_u32(self.get_num_values()?).unwrap() - Decimal::ONE);
71        let x = index_prop * self.get_domain()? + self.get_domain_start()?;
72        Ok(x)
73    }
74
75    fn get_num_values(&self) -> Result<u32>;
76    fn set_num_values(&mut self, num_values: u32) -> Result<()>;
77
78    fn get_index_bounds(&self, x: Decimal) -> Result<(u32, u32, Decimal)> {
79        let domain_start = self.get_domain_start()?;
80        let domain_end = self.get_domain_end()?;
81        let num_values = Decimal::from_u32(self.get_num_values()?).unwrap();
82
83        // decimal value of the index based on the domain range
84        let index_decimal = ((x - domain_start) / (domain_end - domain_start)) * (num_values - Decimal::ONE);
85
86        // round the decimal value into the nearest lower and higher index numbers
87        let lower_index = index_decimal.floor().to_u32().unwrap();
88        let upper_index = index_decimal.ceil().to_u32().unwrap();
89
90        Ok((lower_index, upper_index, index_decimal))
91    }
92}