1use std::convert::TryFrom;
17use std::ffi::{CStr, CString};
18use std::fmt;
19use std::marker::PhantomData;
20use std::mem::MaybeUninit;
21use std::str::FromStr;
22
23use libc::c_char;
24
25use crate::context::Context;
26use crate::decimal::Decimal;
27use crate::decimal64::Decimal64;
28use crate::error::ParseDecimalError;
29
30#[repr(transparent)]
32#[derive(Clone, Copy)]
33pub struct Decimal32 {
34 pub(crate) inner: decnumber_sys::decSingle,
35}
36
37impl Decimal32 {
38 pub const NAN: Decimal32 = Decimal32::from_ne_bytes(if cfg!(target_endian = "little") {
40 [0x0, 0x0, 0x0, 0x7c]
41 } else {
42 [0x7c, 0x0, 0x0, 0x0]
43 });
44
45 pub const ZERO: Decimal32 = Decimal32::from_ne_bytes(if cfg!(target_endian = "little") {
47 [0x0, 0x0, 0x50, 0x22]
48 } else {
49 [0x22, 0x50, 0x0, 0x0]
50 });
51
52 pub const ONE: Decimal32 = Decimal32::from_ne_bytes(if cfg!(target_endian = "little") {
54 [0x1, 0x0, 0x50, 0x22]
55 } else {
56 [0x22, 0x50, 0x0, 0x1]
57 });
58
59 pub fn from_le_bytes(mut bytes: [u8; 4]) -> Decimal32 {
61 if cfg!(target_endian = "big") {
62 bytes.reverse();
63 }
64 Decimal32::from_ne_bytes(bytes)
65 }
66
67 pub fn from_be_bytes(mut bytes: [u8; 4]) -> Decimal32 {
69 if cfg!(target_endian = "little") {
70 bytes.reverse();
71 }
72 Decimal32::from_ne_bytes(bytes)
73 }
74
75 pub const fn from_ne_bytes(bytes: [u8; 4]) -> Decimal32 {
78 Decimal32 {
79 inner: decnumber_sys::decSingle { bytes },
80 }
81 }
82
83 pub fn to_le_bytes(&self) -> [u8; 4] {
86 let mut bytes = self.to_ne_bytes();
87 if cfg!(target_endian = "big") {
88 bytes.reverse();
89 }
90 bytes
91 }
92
93 pub fn to_be_bytes(&self) -> [u8; 4] {
96 let mut bytes = self.to_ne_bytes();
97 if cfg!(target_endian = "little") {
98 bytes.reverse();
99 }
100 bytes
101 }
102
103 pub fn to_ne_bytes(&self) -> [u8; 4] {
106 self.inner.bytes
107 }
108
109 pub fn coefficient(&self) -> i32 {
113 let mut dpd = if cfg!(target_endian = "big") {
114 u32::from_be_bytes(self.inner.bytes)
115 } else {
116 u32::from_le_bytes(self.inner.bytes)
117 };
118
119 if dpd == 0 {
120 return 0;
121 }
122
123 let is_neg = dpd >= 2_147_483_648;
126
127 let dpd_mask = 0b11_1111_1111;
129
130 let mut r =
132 i32::try_from(unsafe { decnumber_sys::DPD2BIN[dpd as usize & dpd_mask] }).unwrap();
133 dpd >>= 10;
134 r += i32::try_from(unsafe { decnumber_sys::DPD2BINK[dpd as usize & dpd_mask] }).unwrap();
135
136 let h = i32::try_from(unsafe { decnumber_sys::DECCOMBMSD[(dpd >> 16) as usize] }).unwrap();
138
139 if h > 0 {
140 r += h * 1_000_000;
141 }
142
143 if is_neg {
144 r *= -1;
145 }
146
147 r
148 }
149
150 pub fn exponent(&self) -> i32 {
152 unsafe { decnumber_sys::decSingleGetExponent(&self.inner) }
153 }
154}
155
156impl Default for Decimal32 {
157 fn default() -> Decimal32 {
158 Decimal32::ZERO
159 }
160}
161
162impl fmt::Debug for Decimal32 {
163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164 fmt::Display::fmt(self, f)
165 }
166}
167
168impl fmt::Display for Decimal32 {
169 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
170 let mut buf = ['\0'; decnumber_sys::DECDOUBLE_String];
171 let c_str = unsafe {
172 if f.alternate() {
173 decnumber_sys::decSingleToEngString(&self.inner, buf.as_mut_ptr() as *mut c_char);
174 } else {
175 decnumber_sys::decSingleToString(&self.inner, buf.as_mut_ptr() as *mut c_char);
176 }
177 CStr::from_ptr(buf.as_ptr() as *const c_char)
178 };
179 f.write_str(
180 c_str
181 .to_str()
182 .expect("decSingleToString yields valid UTF-8"),
183 )
184 }
185}
186
187impl FromStr for Decimal32 {
188 type Err = ParseDecimalError;
189
190 fn from_str(s: &str) -> Result<Decimal32, ParseDecimalError> {
191 Context::<Decimal32>::default().parse(s)
192 }
193}
194
195impl Default for Context<Decimal32> {
196 fn default() -> Context<Decimal32> {
197 let mut ctx = MaybeUninit::<decnumber_sys::decContext>::uninit();
198 let ctx = unsafe {
199 decnumber_sys::decContextDefault(ctx.as_mut_ptr(), decnumber_sys::DEC_INIT_DECDOUBLE);
200 ctx.assume_init()
201 };
202 Context {
203 inner: ctx,
204 _phantom: PhantomData,
205 }
206 }
207}
208
209impl Context<Decimal32> {
210 pub fn parse<S>(&mut self, s: S) -> Result<Decimal32, ParseDecimalError>
212 where
213 S: Into<Vec<u8>>,
214 {
215 let c_string = CString::new(s).map_err(|_| ParseDecimalError)?;
216 let mut d = Decimal32::ZERO;
217 unsafe {
218 decnumber_sys::decSingleFromString(&mut d.inner, c_string.as_ptr(), &mut self.inner);
219 }
220 if (self.inner.status & decnumber_sys::DEC_Conversion_syntax) != 0 {
221 Err(ParseDecimalError)
222 } else {
223 Ok(d)
224 }
225 }
226
227 pub fn from_decimal64(&mut self, d64: Decimal64) -> Decimal32 {
232 let mut d32 = Decimal32::ZERO;
233 unsafe {
234 decnumber_sys::decSingleFromWider(&mut d32.inner, &d64.inner, &mut self.inner);
235 }
236 d32
237 }
238
239 pub fn from_decimal<const N: usize>(&mut self, d: &Decimal<N>) -> Decimal32 {
244 let mut d32 = Decimal32::ZERO;
245 unsafe {
246 decnumber_sys::decimal32FromNumber(&mut d32.inner, d.as_ptr(), &mut self.inner);
247 }
248 d32
249 }
250}