1#![doc = include_str!("../README")]
2#![no_std]
3#![deny(missing_docs)]
4
5extern 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
28type 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 #[allow(missing_docs)]
61 #[inline(always)]
62 pub fn is_empty(self) -> bool {
63 self.as_raw() == 0
64 }
65
66 #[inline(always)]
68 pub fn has(self, other: Self) -> bool {
69 self.0 & other.0 == other.0
70 }
71
72 #[inline(always)]
74 pub fn or(self, other: Self) -> Self {
75 Self(self.0 | other.0)
76 }
77
78 #[inline(always)]
80 pub fn not(self, other: Self) -> Self {
81 Self(self.0 & !other.0)
82 }
83
84 #[inline(always)]
86 pub fn as_raw(self) -> $ty {
87 self.0
88 }
89 }
90
91 impl core::ops::BitOr for $ident {
92 type Output = Self;
93
94 #[inline(always)]
95 fn bitor(self, rhs: Self) -> Self::Output {
96 self.or(rhs)
97 }
98 }
99
100 impl core::ops::BitOrAssign for $ident {
101 #[inline(always)]
102 fn bitor_assign(&mut self, rhs: Self) {
103 *self = self.or(rhs);
104 }
105 }
106 };
107}
108
109flag_ty! (
110 struct FExcept(cfexcpt::Type);
116 const INVALID = cfexcpt::FE_INVALID;
117 const DENORM = cfexcpt::__FE_DENORM;
118 const DIV_BY_ZERO = cfexcpt::FE_DIVBYZERO;
119 const OVERFLOW = cfexcpt::FE_OVERFLOW;
120 const UNDERFLOW = cfexcpt::FE_UNDERFLOW;
121 const INEXACT = cfexcpt::FE_INEXACT;
122 const FE_ALL = binding::FE_ALL_EXCEPT;
123);
124
125flag_ty!(
126 struct FRound(cfround::Type);
132 const NEAREST = cfround::FE_TONEAREST;
133 const DOWNWARD = cfround::FE_DOWNWARD;
134 const UPWARD = cfround::FE_UPWARD;
135 const TOWARD_ZERO = cfround::FE_TOWARDZERO;
136);
137
138impl FExcept {
139 pub fn from_env() -> Result<Self> {
141 let mut excepts = binding::fexcept_t::default();
142 result(unsafe {
143 binding::fegetexceptflag(&mut excepts as *mut _, FExcept::FE_ALL.as_raw() as c_int)
144 })
145 .map(|_| Self(excepts as cfexcpt::Type))
146 }
147
148 #[inline(always)]
150 pub fn set(self) -> Result<()> {
151 let excepts = self.as_raw() as binding::fexcept_t;
152 result(unsafe { binding::fesetexceptflag(&excepts as *const _, self.as_raw() as c_int) })
153 }
154 #[inline(always)]
156 pub fn clear(self) -> Result<()> {
157 result(unsafe { binding::feclearexcept(self.as_raw() as c_int) })
158 }
159
160 #[inline(always)]
162 pub fn raise(self) -> Result<()> {
163 result(unsafe { binding::feraiseexcept(self.as_raw() as c_int) })
164 }
165
166 #[inline(always)]
168 pub fn test(self) -> Self {
169 Self(unsafe { binding::fetestexcept(self.as_raw() as c_int) } as cfexcpt::Type)
170 }
171}
172
173impl FRound {
174 #[inline(always)]
176 pub fn from_env() -> Self {
177 Self(unsafe { binding::fegetround() as cfround::Type })
178 }
179
180 #[inline(always)]
182 pub fn set(self) -> Result<()> {
183 result(unsafe { binding::fesetround(self.as_raw() as c_int) })
184 }
185}
186
187#[inline(always)]
189pub fn set_rounding_mode(flags: FRound) -> Result<()> {
190 flags.set()
191}
192
193#[inline(always)]
195pub fn get_rounding_mode() -> FRound {
196 FRound::from_env()
197}
198
199#[derive(Clone, Debug)]
204pub struct FEnv(binding::fenv_t);
205
206impl FEnv {
207 #[allow(missing_docs)]
208 pub fn from_env() -> Result<Self> {
209 let mut this: Self = unsafe { core::mem::zeroed() };
210 result(unsafe { binding::fegetenv(&mut this.0 as *mut _) }).map(|_| this)
211 }
212
213 #[inline(always)]
215 pub fn set(&self) -> Result<()> {
216 result(unsafe { binding::fesetenv(&self.0 as *const _) })
217 }
218
219 #[inline(always)]
221 pub fn hold(&mut self) -> Result<()> {
222 result(unsafe { binding::feholdexcept(&mut self.0 as *mut _) })
223 }
224
225 #[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}