fpopt/
lib.rs

1#![doc = include_str!("../README")]
2#![no_std]
3#![deny(missing_docs)]
4
5// enforce linking with libc.
6extern crate libc;
7
8#[path = "../binding/binding.rs"]
9#[allow(non_snake_case)]
10#[allow(non_upper_case_globals)]
11#[allow(non_camel_case_types)]
12#[allow(dead_code)]
13#[allow(clippy::useless_transmute)]
14#[allow(missing_docs)]
15mod binding;
16
17use binding::_bindgen_ty_1 as cfexcpt;
18use binding::_bindgen_ty_2 as cfround;
19
20use core::ffi::c_int;
21use core::num::NonZeroI32;
22
23#[allow(missing_docs)]
24pub mod raw {
25    pub use crate::binding::*;
26}
27
28// NOTE: uses NoneZeroI32 for optimization reasons.
29type Result<T> = core::result::Result<T, NonZeroI32>;
30
31#[inline(always)]
32fn result(result: core::ffi::c_int) -> Result<()> {
33    NonZeroI32::new(result).map(Err).unwrap_or(Ok(()))
34}
35
36macro_rules! flag_ty {
37    (
38        $(#[$($attr:meta)*])*
39        struct $ident:ident ($ty:ty);
40        $(
41            const $c_ident:ident = $c_expr:expr;
42        )*
43    ) => {
44        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
45        $(#[$($attr)*])*
46        pub struct $ident($ty);
47
48        impl $ident {
49            $(
50                #[allow(missing_docs)]
51                pub const $c_ident: Self = Self($c_expr);
52            )*
53
54            #[allow(missing_docs)]
55            #[inline(always)]
56            pub fn none() -> Self {
57                Self(0)
58            }
59
60            /// See if the given flags exist.
61            #[inline(always)]
62            pub fn has(self, other: Self) -> bool {
63                self.0 & other.0 != 0
64            }
65
66            /// Return a new set of flags which enbable all mutual flags between `self` and `other`.
67            #[inline(always)]
68            pub fn or(self, other: Self) -> Self {
69                Self(self.0 | other.0)
70            }
71
72            /// Return a new set of flags which remove all mutual flags between `self` and `other`.
73            #[inline(always)]
74            pub fn not(self, other: Self) -> Self {
75                Self(self.0 & !other.0)
76            }
77
78            /// Retrieve the raw representation of the flags.
79            #[inline(always)]
80            pub fn as_raw(self) -> $ty {
81                self.0
82            }
83        }
84
85        impl core::ops::BitOr for $ident {
86            type Output = Self;
87
88            #[inline(always)]
89            fn bitor(self, rhs: Self) -> Self::Output {
90                self.or(rhs)
91            }
92        }
93
94        impl core::ops::BitOrAssign for $ident {
95            #[inline(always)]
96            fn bitor_assign(&mut self, rhs: Self) {
97                *self = self.or(rhs);
98            }
99        }
100    };
101}
102
103flag_ty! (
104    /// A wrapper over floating point exception flags.
105    ///
106    /// This type encapsulate the behaviour of manipulating
107    /// the configuration of floating point exceptions without
108    /// needing to deal with the raw API.
109    struct FExcept(cfexcpt::Type);
110    const INVALID = cfexcpt::FE_INVALID;
111    const DENORM = cfexcpt::__FE_DENORM;
112    const DIV_BY_ZERO = cfexcpt::FE_DIVBYZERO;
113    const OVERFLOW = cfexcpt::FE_OVERFLOW;
114    const UNDERFLOW = cfexcpt::FE_UNDERFLOW;
115    const INEXACT = cfexcpt::FE_INEXACT;
116    const FE_ALL = binding::FE_ALL_EXCEPT;
117);
118
119flag_ty!(
120    /// A wrapper over floating point rounding flags.
121    ///
122    /// This type encapsulates the behaviour of manipulating
123    /// the configuration of floating point rounding without
124    /// needing to deal with the raw API.
125    struct FRound(cfround::Type);
126    const NEAREST = cfround::FE_TONEAREST;
127    const DOWNWARD = cfround::FE_DOWNWARD;
128    const UPWARD = cfround::FE_UPWARD;
129    const TOWARD_ZERO = cfround::FE_TOWARDZERO;
130);
131
132impl FExcept {
133    /// visit: https://en.cppreference.com/w/cpp/numeric/fenv/feclearexcept
134    #[inline(always)]
135    pub fn clear(self) -> Result<()> {
136        result(unsafe { binding::feclearexcept(self.as_raw() as c_int) })
137    }
138
139    /// visit: https://en.cppreference.com/w/c/numeric/fenv/feexceptflag
140    #[inline(always)]
141    pub fn getflag(self) -> Result<Self> {
142        let mut excepts = binding::fexcept_t::default();
143        result(unsafe { binding::fegetexceptflag(&mut excepts as *mut _, self.as_raw() as c_int) })
144            .map(|_| Self(excepts as cfexcpt::Type))
145    }
146
147    /// visit: https://en.cppreference.com/w/c/numeric/fenv/feexceptflag
148    #[inline(always)]
149    pub fn setflag(self) -> Result<()> {
150        let excepts = self.as_raw() as binding::fexcept_t;
151        result(unsafe { binding::fesetexceptflag(&excepts as *const _, self.as_raw() as c_int) })
152    }
153
154    /// visit: https://en.cppreference.com/w/c/numeric/fenv/feraiseexcept
155    #[inline(always)]
156    pub fn raise(self) -> Result<()> {
157        result(unsafe { binding::feraiseexcept(self.as_raw() as c_int) })
158    }
159
160    /// visit: https://en.cppreference.com/w/c/numeric/fenv/fetestexcept
161    #[inline(always)]
162    pub fn test(self) -> Self {
163        Self(unsafe { binding::fetestexcept(self.as_raw() as c_int) } as cfexcpt::Type)
164    }
165}
166
167impl FRound {
168    /// visit: https://en.cppreference.com/w/c/numeric/fenv/feround
169    #[inline(always)]
170    pub fn getround() -> Self {
171        Self(unsafe { binding::fegetround() as cfround::Type })
172    }
173
174    /// visit: https://en.cppreference.com/w/c/numeric/fenv/feround
175    #[inline(always)]
176    pub fn setround(self) -> Result<()> {
177        result(unsafe { binding::fesetround(self.as_raw() as c_int) })
178    }
179}
180
181/// visit: https://en.cppreference.com/w/c/numeric/fenv/feround
182#[inline(always)]
183pub fn set_rounding_mode(flags: FRound) -> Result<()> {
184    flags.setround()
185}
186
187/// visit: https://en.cppreference.com/w/c/numeric/fenv/feround
188#[inline(always)]
189pub fn get_rounding_mode() -> FRound {
190    FRound::getround()
191}
192
193/// A wrapper around the floating point environment.
194///
195/// visit: https://cplusplus.com/reference/cfenv/fenv_t/
196/// for more information about the underlying `fenv_t` type.
197#[derive(Clone, Debug)]
198pub struct FEnv(binding::fenv_t);
199
200impl FEnv {
201    #[allow(missing_docs)]
202    pub fn new() -> Result<Self> {
203        let mut this: Self = unsafe { core::mem::zeroed() };
204        this.get().map(|_| this)
205    }
206
207    /// visit: https://en.cppreference.com/w/c/numeric/fenv/feholdexcept
208    #[inline(always)]
209    pub fn hold(&mut self) -> Result<()> {
210        result(unsafe { binding::feholdexcept(&mut self.0 as *mut _) })
211    }
212
213    /// visit: https://en.cppreference.com/w/c/numeric/fenv/feenv
214    #[inline(always)]
215    pub fn set(&self) -> Result<()> {
216        result(unsafe { binding::fesetenv(&self.0 as *const _) })
217    }
218
219    /// visit: https://en.cppreference.com/w/c/numeric/fenv/feenv
220    #[inline(always)]
221    pub fn get(&mut self) -> Result<()> {
222        result(unsafe { binding::fegetenv(&mut self.0 as *mut _) })
223    }
224
225    /// visit:
226    #[inline(always)]
227    pub fn update(&self) -> Result<()> {
228        result(unsafe { binding::feupdateenv(&self.0 as *const _) })
229    }
230
231    #[allow(missing_docs)]
232    #[inline(always)]
233    pub fn inner(&self) -> &binding::fenv_t {
234        &self.0
235    }
236
237    #[allow(missing_docs)]
238    #[inline(always)]
239    pub fn inner_mut(&mut self) -> &mut binding::fenv_t {
240        &mut self.0
241    }
242}
243
244impl core::ops::Deref for FEnv {
245    type Target = binding::fenv_t;
246
247    fn deref(&self) -> &Self::Target {
248        self.inner()
249    }
250}
251
252impl core::ops::DerefMut for FEnv {
253    fn deref_mut(&mut self) -> &mut Self::Target {
254        self.inner_mut()
255    }
256}