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 #[inline(always)]
62 pub fn has(self, other: Self) -> bool {
63 self.0 & other.0 != 0
64 }
65
66 #[inline(always)]
68 pub fn or(self, other: Self) -> Self {
69 Self(self.0 | other.0)
70 }
71
72 #[inline(always)]
74 pub fn not(self, other: Self) -> Self {
75 Self(self.0 & !other.0)
76 }
77
78 #[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 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 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 #[inline(always)]
135 pub fn clear(self) -> Result<()> {
136 result(unsafe { binding::feclearexcept(self.as_raw() as c_int) })
137 }
138
139 #[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 #[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 #[inline(always)]
156 pub fn raise(self) -> Result<()> {
157 result(unsafe { binding::feraiseexcept(self.as_raw() as c_int) })
158 }
159
160 #[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 #[inline(always)]
170 pub fn getround() -> Self {
171 Self(unsafe { binding::fegetround() as cfround::Type })
172 }
173
174 #[inline(always)]
176 pub fn setround(self) -> Result<()> {
177 result(unsafe { binding::fesetround(self.as_raw() as c_int) })
178 }
179}
180
181#[inline(always)]
183pub fn set_rounding_mode(flags: FRound) -> Result<()> {
184 flags.setround()
185}
186
187#[inline(always)]
189pub fn get_rounding_mode() -> FRound {
190 FRound::getround()
191}
192
193#[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 #[inline(always)]
209 pub fn hold(&mut self) -> Result<()> {
210 result(unsafe { binding::feholdexcept(&mut self.0 as *mut _) })
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 get(&mut self) -> Result<()> {
222 result(unsafe { binding::fegetenv(&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}