astro_float_num/
ctx.rs

1//! Context is used in expressions returning `BigFloat`.
2
3use crate::BigFloat;
4use crate::Consts;
5use crate::Error;
6use crate::Exponent;
7use crate::RoundingMode;
8use crate::EXPONENT_MAX;
9use crate::EXPONENT_MIN;
10
11/// Context contains parameters, like rounding mode and precision, as well as constant values, and is used with `expr!` macro.
12#[derive(Debug)]
13pub struct Context {
14    cc: Consts,
15    p: usize,
16    rm: RoundingMode,
17    emin: Exponent,
18    emax: Exponent,
19}
20
21impl Context {
22    /// Create a new context.
23    /// The value of `emin` will be clamped to a range between EXPONENT_MIN and 0.
24    /// The value of `emax` will be clamped to a range between 0 and EXPONENT_MAX.
25    pub fn new(p: usize, rm: RoundingMode, cc: Consts, emin: Exponent, emax: Exponent) -> Self {
26        Context {
27            cc,
28            p,
29            rm,
30            emin: emin.clamp(EXPONENT_MIN, 0),
31            emax: emax.clamp(0, EXPONENT_MAX),
32        }
33    }
34
35    /// Destructures the context and returns its parts: target precision, rounding mode,
36    /// constant cache, minimum exponent, maximum exponent.
37    pub fn to_raw_parts(self) -> (usize, RoundingMode, Consts, Exponent, Exponent) {
38        let Context {
39            p,
40            rm,
41            cc,
42            emin,
43            emax,
44        } = self;
45        (p, rm, cc, emin, emax)
46    }
47
48    /// Sets the precision of the context.
49    pub fn set_precision(&mut self, p: usize) {
50        self.p = p;
51    }
52
53    /// Sets the rounding mode of the context.
54    pub fn set_rounding_mode(&mut self, rm: RoundingMode) {
55        self.rm = rm;
56    }
57
58    /// Sets the constant cache of the context.
59    pub fn set_consts(&mut self, cc: Consts) {
60        self.cc = cc;
61    }
62
63    /// Sets the minimum exponent.
64    /// The value of `emin` will be clamped to a range between EXPONENT_MIN and 0.
65    pub fn set_emin(&mut self, emin: Exponent) {
66        self.emin = emin.clamp(EXPONENT_MIN, 0);
67    }
68
69    /// Sets the maximum exponent.
70    /// The value of `emax` will be clamped to a range between 0 and EXPONENT_MAX.
71    pub fn set_emax(&mut self, emax: Exponent) {
72        self.emax = emax.clamp(0, EXPONENT_MAX);
73    }
74
75    /// Returns the precision of the context.
76    pub fn precision(&self) -> usize {
77        self.p
78    }
79
80    /// Returns the rounding mode of the context.
81    pub fn rounding_mode(&self) -> RoundingMode {
82        self.rm
83    }
84
85    /// Returns a mutable reference to the constant cache of the context.
86    pub fn consts(&mut self) -> &mut Consts {
87        &mut self.cc
88    }
89
90    /// Returns the value of the pi number.
91    pub fn const_pi(&mut self) -> BigFloat {
92        self.cc.pi(self.p, self.rm)
93    }
94
95    /// Returns the value of the Euler number.
96    pub fn const_e(&mut self) -> BigFloat {
97        self.cc.e(self.p, self.rm)
98    }
99
100    /// Returns the value of the natural logarithm of 2.
101    pub fn const_ln2(&mut self) -> BigFloat {
102        self.cc.ln_2(self.p, self.rm)
103    }
104
105    /// Returns the value of the natural logarithm of 10.
106    pub fn const_ln10(&mut self) -> BigFloat {
107        self.cc.ln_10(self.p, self.rm)
108    }
109
110    /// Returns the minimum exponent.
111    pub fn emin(&self) -> Exponent {
112        self.emin
113    }
114
115    /// Returns the maximum exponent.
116    pub fn emax(&self) -> Exponent {
117        self.emax
118    }
119
120    /// Clones `self` and returns the cloned context.
121    ///
122    /// # Errors
123    ///
124    /// - MemoryAllocation: failed to allocate memory for the constants cache.
125    #[allow(clippy::should_implement_trait)]
126    pub fn clone(&self) -> Result<Self, Error> {
127        let cc = Consts::new()?;
128        Ok(Context {
129            p: self.p,
130            rm: self.rm,
131            cc,
132            emin: self.emin,
133            emax: self.emax,
134        })
135    }
136}
137
138/// Represents a type that can be used as context in `expr!` macro.
139///
140/// ## Examples
141///
142/// ```
143/// # use astro_float_num::RoundingMode;
144/// # use astro_float_num::Consts;
145/// # use astro_float_num::ctx::Contextable;
146/// let p = 123;
147/// let rm = RoundingMode::Down;
148/// let mut cc = Consts::new().expect("Constants cache allocated");
149/// let pi = cc.pi(p, rm);
150///
151/// // Make context out of tuple.
152/// let mut ctx = (p, rm, &mut cc);
153///
154/// assert_eq!(p, ctx.precision());
155/// assert_eq!(rm, ctx.rounding_mode());
156/// assert_eq!(pi, ctx.const_pi());
157/// ```
158pub trait Contextable {
159    /// Returns the precision of the context.
160    fn precision(&self) -> usize;
161
162    /// Returns the rounding mode of the context.
163    fn rounding_mode(&self) -> RoundingMode;
164
165    /// Returns a mutable reference to the constant cache of the context.
166    fn consts(&mut self) -> &mut Consts;
167
168    /// Returns the value of the pi number.
169    fn const_pi(&mut self) -> BigFloat;
170
171    /// Returns the value of the Euler number.
172    fn const_e(&mut self) -> BigFloat;
173
174    /// Returns the value of the natural logarithm of 2.
175    fn const_ln2(&mut self) -> BigFloat;
176
177    /// Returns the value of the natural logarithm of 10.
178    fn const_ln10(&mut self) -> BigFloat;
179
180    /// Returns the minimum exponent.
181    fn emin(&self) -> Exponent;
182
183    /// Returns the maximum exponent.
184    fn emax(&self) -> Exponent;
185}
186
187impl Contextable for (usize, RoundingMode, &mut Consts) {
188    fn precision(&self) -> usize {
189        self.0
190    }
191
192    fn rounding_mode(&self) -> RoundingMode {
193        self.1
194    }
195
196    fn consts(&mut self) -> &mut Consts {
197        self.2
198    }
199
200    fn const_pi(&mut self) -> BigFloat {
201        let (p, rm) = (self.0, self.1);
202        self.consts().pi(p, rm)
203    }
204
205    fn const_e(&mut self) -> BigFloat {
206        let (p, rm) = (self.0, self.1);
207        self.consts().e(p, rm)
208    }
209
210    fn const_ln2(&mut self) -> BigFloat {
211        let (p, rm) = (self.0, self.1);
212        self.consts().ln_2(p, rm)
213    }
214
215    fn const_ln10(&mut self) -> BigFloat {
216        let (p, rm) = (self.0, self.1);
217        self.consts().ln_10(p, rm)
218    }
219
220    fn emin(&self) -> Exponent {
221        EXPONENT_MIN
222    }
223
224    fn emax(&self) -> Exponent {
225        EXPONENT_MAX
226    }
227}
228
229impl Contextable for (usize, RoundingMode, &mut Consts, Exponent, Exponent) {
230    fn precision(&self) -> usize {
231        self.0
232    }
233
234    fn rounding_mode(&self) -> RoundingMode {
235        self.1
236    }
237
238    fn consts(&mut self) -> &mut Consts {
239        self.2
240    }
241
242    fn const_pi(&mut self) -> BigFloat {
243        let (p, rm) = (self.0, self.1);
244        self.consts().pi(p, rm)
245    }
246
247    fn const_e(&mut self) -> BigFloat {
248        let (p, rm) = (self.0, self.1);
249        self.consts().e(p, rm)
250    }
251
252    fn const_ln2(&mut self) -> BigFloat {
253        let (p, rm) = (self.0, self.1);
254        self.consts().ln_2(p, rm)
255    }
256
257    fn const_ln10(&mut self) -> BigFloat {
258        let (p, rm) = (self.0, self.1);
259        self.consts().ln_10(p, rm)
260    }
261
262    fn emin(&self) -> Exponent {
263        self.3.clamp(EXPONENT_MIN, 0)
264    }
265
266    fn emax(&self) -> Exponent {
267        self.4.clamp(0, EXPONENT_MAX)
268    }
269}
270
271impl Contextable for Context {
272    fn precision(&self) -> usize {
273        Context::precision(self)
274    }
275
276    fn rounding_mode(&self) -> RoundingMode {
277        Context::rounding_mode(self)
278    }
279
280    fn consts(&mut self) -> &mut Consts {
281        Context::consts(self)
282    }
283
284    fn const_pi(&mut self) -> BigFloat {
285        Context::const_pi(self)
286    }
287
288    fn const_e(&mut self) -> BigFloat {
289        Context::const_e(self)
290    }
291
292    fn const_ln2(&mut self) -> BigFloat {
293        Context::const_ln2(self)
294    }
295
296    fn const_ln10(&mut self) -> BigFloat {
297        Context::const_ln10(self)
298    }
299
300    fn emin(&self) -> Exponent {
301        Context::emin(self)
302    }
303
304    fn emax(&self) -> Exponent {
305        Context::emax(self)
306    }
307}