#![cfg(feature = "f16")]
#![cfg_attr(feature = "f16", feature(f16))]
use zerocbor::{FromCbor, ToCbor, Value, from_cbor, to_cbor_vec};
mod on_the_wire {
use super::*;
#[test]
fn every_bit_pattern_goes_out_as_the_half_it_came_from() {
for bits in 0..=u16::MAX {
let is_nan = (bits & 0x7c00) == 0x7c00 && (bits & 0x03ff) != 0;
let encoded = to_cbor_vec(&f16::from_bits(bits)).unwrap();
assert_eq!(encoded[0], 0xf9, "{bits:#06x} did not go out as a half");
if is_nan {
assert_eq!(encoded, [0xf9, 0x7e, 0x00], "bits {bits:#06x}");
let decoded: f16 = from_cbor(&encoded).unwrap();
assert!(decoded.is_nan(), "bits {bits:#06x} stopped being a NaN");
continue;
}
let decoded: f16 = from_cbor(&encoded).unwrap();
assert_eq!(decoded.to_bits(), bits, "bits {bits:#06x} did not survive");
}
let smallest = f16::from_bits(0x0001);
assert_eq!(smallest as f32, 2.0f32.powi(-24));
assert!(smallest as f32 > 0.0);
assert_eq!((-0.0f32 as f16).to_bits(), 0x8000);
assert!((f16::from_bits(0x8000) as f32).is_sign_negative());
}
#[test]
fn the_wire_form_is_the_one_rfc_8949_defines() {
for (bits, expected) in [
(0x0000u16, [0xf9, 0x00, 0x00]), (0x8000, [0xf9, 0x80, 0x00]), (0x3c00, [0xf9, 0x3c, 0x00]), (0x7bff, [0xf9, 0x7b, 0xff]), (0x0400, [0xf9, 0x04, 0x00]), (0x0001, [0xf9, 0x00, 0x01]), (0x7c00, [0xf9, 0x7c, 0x00]), (0xfc00, [0xf9, 0xfc, 0x00]), ] {
assert_eq!(to_cbor_vec(&f16::from_bits(bits)).unwrap(), expected);
assert_eq!(from_cbor::<f16>(&expected).unwrap().to_bits(), bits);
}
let payload = f16::from_bits(0x7e01);
assert!(payload.is_nan());
assert!((payload as f32).is_nan(), "the conversion dropped the NaN");
let encoded = to_cbor_vec(&payload).unwrap();
assert_eq!(
encoded,
[0xf9, 0x7e, 0x00],
"a NaN payload reached the wire"
);
assert!(from_cbor::<f16>(&encoded).unwrap().is_nan());
}
#[test]
fn every_width_is_accepted_on_the_way_in() {
for bytes in [
&[0xf9, 0x3c, 0x00][..], &[0xfa, 0x3f, 0x80, 0x00, 0x00][..], &[0xfb, 0x3f, 0xf0, 0, 0, 0, 0, 0, 0][..], ] {
let value: f16 = from_cbor(bytes).unwrap();
assert_eq!(value, 1.0f16, "for {bytes:02x?}");
assert_eq!(to_cbor_vec(&value).unwrap(), [0xf9, 0x3c, 0x00]);
}
let value: f16 = from_cbor(&[0xfb, 0x7e, 0x37, 0xe4, 0, 0, 0, 0, 0]).unwrap();
assert_eq!(value, f16::INFINITY);
}
#[test]
fn the_width_survives_a_wider_type_and_a_value() {
assert_eq!(
to_cbor_vec(&from_cbor::<f32>(&[0xf9, 0x3c, 0x00]).unwrap()).unwrap(),
[0xf9, 0x3c, 0x00]
);
let value: Value = from_cbor(&[0xf9, 0x3c, 0x00]).unwrap();
assert_eq!(to_cbor_vec(&value).unwrap(), [0xf9, 0x3c, 0x00]);
let value: Value =
from_cbor(&[0xa2, 0xf9, 0x00, 0x00, 0x00, 0xf9, 0x3c, 0x00, 0x01]).unwrap();
assert_eq!(
to_cbor_vec(&value).unwrap(),
[0xa2, 0xf9, 0x00, 0x00, 0x00, 0xf9, 0x3c, 0x00, 0x01]
);
}
}
mod in_a_derived_type {
use super::*;
#[derive(Debug, PartialEq, ToCbor, FromCbor)]
#[cbor(map)]
struct Reading {
value: f16,
unit: String,
}
#[test]
fn a_field_keeps_its_width_through_a_struct() {
let reading = Reading {
value: 1.5,
unit: "V".into(),
};
let encoded = to_cbor_vec(&reading).unwrap();
assert_eq!(
encoded,
[
0xa2, 0x64, b'u', b'n', b'i', b't', 0x61, b'V', 0x65, b'v', b'a', b'l', b'u', b'e',
0xf9, 0x3e, 0x00,
]
);
assert_eq!(from_cbor::<Reading>(&encoded).unwrap(), reading);
}
}
mod size_hints {
use super::*;
#[test]
fn a_buffer_sized_from_the_hint_is_never_short() {
assert_eq!(1.0f16.size_hint().map(|h| h.upper_bound()), Some(3));
assert_eq!(
<f16 as ToCbor>::max_size().map(|h| h.upper_bound()),
Some(3)
);
let values = [1.0f16, 2.0, 3.0];
let mut buf = [0u8; 10];
let written = zerocbor::to_cbor(&&values[..], &mut buf).unwrap();
assert_eq!(written, 10);
assert_eq!(
buf,
[0x83, 0xf9, 0x3c, 0x00, 0xf9, 0x40, 0x00, 0xf9, 0x42, 0x00]
);
}
}