1import_stdlib!();
2
3use half::f16;
4
5use super::varint::{EncodeVarInt, MajorType};
6use crate::{CBOR, CBORCase, Error, ExactFrom, Result, Simple, int::From64};
7
8static CBOR_NAN: [u8; 3] = [0xf9, 0x7e, 0x00];
50
51impl From<f64> for CBOR {
52 fn from(value: f64) -> Self {
53 let n = value;
54 if n < 0.0f64
55 && let Some(n) = i128::exact_from_f64(n)
56 && let Some(i) = u64::exact_from_i128(-1 - n)
57 {
58 return CBORCase::Negative(i).into();
59 }
60 if let Some(i) = u64::exact_from_f64(n) {
61 return i.into();
62 }
63 CBORCase::Simple(Simple::Float(n)).into()
64 }
65}
66
67pub(crate) fn f64_cbor_data(value: f64) -> Vec<u8> {
68 let n = value;
69 let f = n as f32;
70 if (f as f64) == n {
71 return f32_cbor_data(f);
72 }
73 if n < 0.0f64
74 && let Some(n) = i128::exact_from_f64(n)
75 && let Some(i) = u64::exact_from_i128(-1 - n)
76 {
77 let cbor: CBOR = CBORCase::Negative(i).into();
78 return cbor.to_cbor_data();
79 }
80 if let Some(i) = u64::exact_from_f64(n) {
81 return i.cbor_data();
82 }
83 if value.is_nan() {
84 return CBOR_NAN.to_vec();
85 }
86 n.to_bits().encode_int(MajorType::Simple)
87}
88
89pub(crate) fn validate_canonical_f64(n: f64) -> Result<()> {
90 if n == (n as f32 as f64) || n == (n as i64 as f64) || n.is_nan() {
91 return Err(Error::NonCanonicalNumeric);
92 }
93 Ok(())
94}
95
96impl TryFrom<CBOR> for f64 {
97 type Error = Error;
98
99 fn try_from(cbor: CBOR) -> Result<Self> {
100 match cbor.into_case() {
101 CBORCase::Unsigned(n) => {
102 if let Some(f) = f64::exact_from_u64(n) {
103 Ok(f)
104 } else {
105 Err(Error::OutOfRange)
106 }
107 }
108 CBORCase::Negative(n) => {
109 if let Some(f) = f64::exact_from_u64(n) {
110 Ok(-1f64 - f)
111 } else {
112 Err(Error::OutOfRange)
113 }
114 }
115 CBORCase::Simple(Simple::Float(n)) => Ok(n),
116 _ => Err(Error::WrongType),
117 }
118 }
119}
120
121impl From<f32> for CBOR {
122 fn from(value: f32) -> Self {
123 let n = value;
124 if n < 0.0f32
125 && let Some(i) = u64::exact_from_f32(-1f32 - n)
126 {
127 return CBORCase::Negative(i).into();
128 }
129 if let Some(i) = u32::exact_from_f32(n) {
130 return i.into();
131 }
132 CBORCase::Simple(Simple::Float(n as f64)).into()
133 }
134}
135
136pub(crate) fn f32_cbor_data(value: f32) -> Vec<u8> {
137 let n = value;
138 let f = f16::from_f32(n);
139 if f.to_f32() == n {
140 return f16_cbor_data(f);
141 }
142 if n < 0.0f32
143 && let Some(i) = u64::exact_from_f32(-1f32 - n)
144 {
145 let cbor: CBOR = CBORCase::Negative(i).into();
146 return cbor.to_cbor_data();
147 }
148 if let Some(i) = u32::exact_from_f32(n) {
149 return i.cbor_data();
150 }
151 if value.is_nan() {
152 return CBOR_NAN.to_vec();
153 }
154 n.to_bits().encode_int(MajorType::Simple)
155}
156
157pub(crate) fn validate_canonical_f32(n: f32) -> Result<()> {
158 if n == f16::from_f32(n).to_f32() || n == (n as i32 as f32) || n.is_nan() {
159 return Err(Error::NonCanonicalNumeric);
160 }
161 Ok(())
162}
163
164impl TryFrom<CBOR> for f32 {
165 type Error = Error;
166
167 fn try_from(cbor: CBOR) -> Result<Self> {
168 match cbor.into_case() {
169 CBORCase::Unsigned(n) => {
170 if let Some(f) = f32::exact_from_u64(n) {
171 Ok(f)
172 } else {
173 Err(Error::OutOfRange)
174 }
175 }
176 CBORCase::Negative(n) => {
177 if let Some(f) = f32::exact_from_u64(n) {
178 Ok(f)
179 } else {
180 Err(Error::OutOfRange)
181 }
182 }
183 CBORCase::Simple(Simple::Float(n)) => {
184 if let Some(f) = f32::exact_from_f64(n) {
185 Ok(f)
186 } else {
187 Err(Error::OutOfRange)
188 }
189 }
190 _ => Err(Error::WrongType),
191 }
192 }
193}
194
195impl From<f16> for CBOR {
196 fn from(value: f16) -> Self {
197 let n = value.to_f64();
198 if n < 0.0
199 && let Some(i) = u64::exact_from_f64(-1f64 - n)
200 {
201 return CBORCase::Negative(i).into();
202 }
203 if let Some(i) = u16::exact_from_f64(n) {
204 return i.into();
205 }
206 CBORCase::Simple(Simple::Float(n)).into()
207 }
208}
209
210pub(crate) fn f16_cbor_data(value: f16) -> Vec<u8> {
211 let n = value.to_f64();
212 if n < 0.0
213 && let Some(i) = u64::exact_from_f64(-1f64 - n)
214 {
215 let cbor: CBOR = CBORCase::Negative(i).into();
216 return cbor.to_cbor_data();
217 }
218 if let Some(i) = u16::exact_from_f64(n) {
219 return i.cbor_data();
220 }
221 if value.is_nan() {
222 return CBOR_NAN.to_vec();
223 }
224 value.to_bits().encode_int(MajorType::Simple)
225}
226
227impl TryFrom<CBOR> for f16 {
228 type Error = Error;
229
230 fn try_from(cbor: CBOR) -> Result<Self> {
231 match cbor.into_case() {
232 CBORCase::Unsigned(n) => {
233 if let Some(f) = f16::exact_from_u64(n) {
234 Ok(f)
235 } else {
236 Err(Error::OutOfRange)
237 }
238 }
239 CBORCase::Negative(n) => {
240 if let Some(f) = f64::exact_from_u64(n) {
241 if let Some(b) = f16::exact_from_f64(-1f64 - f) {
242 Ok(b)
243 } else {
244 Err(Error::OutOfRange)
245 }
246 } else {
247 Err(Error::OutOfRange)
248 }
249 }
250 CBORCase::Simple(Simple::Float(n)) => {
251 if let Some(f) = f16::exact_from_f64(n) {
252 Ok(f)
253 } else {
254 Err(Error::OutOfRange)
255 }
256 }
257 _ => Err(Error::WrongType),
258 }
259 }
260}
261
262pub(crate) fn validate_canonical_f16(n: f16) -> Result<()> {
263 let f = n.to_f64();
264 if f == (f as i64 as f64) || (n.is_nan() && n.to_bits() != 0x7e00) {
265 return Err(Error::NonCanonicalNumeric);
266 }
267 Ok(())
268}