1use half::f16;
2
3use crate::{Error, Float, Result, Value, ValueKey, float::Inner};
4
5impl Float {
6 pub const fn to_f16(self) -> Result<f16> {
12 match self.0 {
13 Inner::F16(bits) => Ok(f16::from_bits(bits)),
14 Inner::F32(_) => Err(Error::Precision),
15 Inner::F64(_) => Err(Error::Precision),
16 }
17 }
18}
19
20impl From<f16> for Float {
21 fn from(value: f16) -> Self {
22 Self(Inner::F16(value.to_bits()))
23 }
24}
25
26impl<'a> Value<'a> {
27 pub fn to_f16(&self) -> Result<f16> {
34 match self {
35 Self::Float(float) => float.to_f16(),
36 Self::Tag(_number, content) => content.untagged().to_f16(),
37 _ => Err(Error::IncompatibleType(self.data_type())),
38 }
39 }
40}
41
42impl<'a> From<f16> for Value<'a> {
43 fn from(value: f16) -> Self {
44 Self::Float(value.into())
45 }
46}
47
48impl<'a> TryFrom<Value<'a>> for f16 {
49 type Error = Error;
50 fn try_from(value: Value<'a>) -> Result<Self> {
51 value.to_f16()
52 }
53}
54
55impl<'a> From<f16> for ValueKey<'a> {
56 fn from(value: f16) -> Self {
57 Value::from(value).into()
58 }
59}
60
61#[cfg(test)]
66mod tests {
67 use half::f16;
68
69 use crate::{DataType, Error, Float, Value, float::Inner};
70
71 #[test]
76 fn float_to_f16_from_f16_storage() {
77 let f: Float = f16::from_f32(1.0).into();
78 assert_eq!(f.to_f16(), Ok(f16::from_f32(1.0)));
79 }
80
81 #[test]
82 fn float_to_f16_rejects_f32() {
83 let f: Float = 1e10_f32.into();
85 assert!(matches!(f.0, Inner::F32(_)));
86 assert_eq!(f.to_f16(), Err(Error::Precision));
87 }
88
89 #[test]
90 fn float_to_f16_rejects_f64() {
91 let f: Float = 1e100_f64.into();
93 assert!(matches!(f.0, Inner::F64(_)));
94 assert_eq!(f.to_f16(), Err(Error::Precision));
95 }
96
97 #[test]
98 fn float_to_f16_zero() {
99 let f: Float = f16::ZERO.into();
100 assert_eq!(f.to_f16().unwrap().to_bits(), f16::ZERO.to_bits());
101 assert_eq!(f.to_f32().unwrap().to_bits(), 0.0_f32.to_bits());
102 assert_eq!(f.to_f64().to_bits(), 0.0_f64.to_bits());
103 }
104
105 #[test]
106 fn float_to_f16_neg_zero() {
107 let f: Float = f16::NEG_ZERO.into();
108 assert_eq!(f.to_f16().unwrap().to_bits(), f16::NEG_ZERO.to_bits());
109 assert_eq!(f.to_f32().unwrap().to_bits(), (-0.0_f32).to_bits());
110 assert_eq!(f.to_f64().to_bits(), (-0.0_f64).to_bits());
111 }
112
113 #[test]
114 fn float_to_f16_infinity() {
115 let f: Float = f16::INFINITY.into();
116 assert_eq!(f.to_f16().unwrap(), f16::INFINITY);
117 assert_eq!(f.to_f32().unwrap(), f32::INFINITY);
118 assert_eq!(f.to_f64(), f64::INFINITY);
119 }
120
121 #[test]
122 fn float_to_f16_nan() {
123 let f: Float = f16::NAN.into();
124 assert!(f.to_f16().unwrap().is_nan());
125 assert!(f.to_f32().unwrap().is_nan());
126 assert!(f.to_f64().is_nan());
127 }
128
129 #[test]
134 fn from_f16_stores_as_f16_bits() {
135 let v = f16::from_f32(42.0);
136 let f: Float = v.into();
137 assert!(matches!(f.0, Inner::F16(_)));
138 }
139
140 #[test]
141 fn from_f16_roundtrips() {
142 for bits in 0_u16..=0x7fff {
143 let v = f16::from_bits(bits);
144 if v.is_nan() {
145 continue;
146 }
147 let f: Float = v.into();
148 assert_eq!(
149 f.to_f16().unwrap().to_bits(),
150 bits,
151 "roundtrip failed for bits 0x{bits:04x}"
152 );
153 }
154 }
155
156 #[test]
161 fn value_to_f16_from_float_value() {
162 let val: Value = f16::from_f32(1.5).into();
163 assert_eq!(val.to_f16(), Ok(f16::from_f32(1.5)));
164 }
165
166 #[test]
167 fn value_to_f16_incompatible_type() {
168 let val = Value::Unsigned(42);
169 assert_eq!(val.to_f16(), Err(Error::IncompatibleType(DataType::Int)));
170 }
171
172 #[test]
173 fn value_to_f16_string_is_incompatible() {
174 let val = Value::from("hello");
175 assert_eq!(val.to_f16(), Err(Error::IncompatibleType(DataType::Text)));
176 }
177
178 #[test]
179 fn value_to_f16_f32_precision_error() {
180 let val: Value = 1e10_f32.into();
181 assert_eq!(val.to_f16(), Err(Error::Precision));
182 }
183
184 #[test]
189 fn value_from_f16_is_float_variant() {
190 let val: Value = f16::from_f32(2.0).into();
191 assert!(matches!(val, Value::Float(_)));
192 }
193
194 #[test]
199 fn try_from_value_for_f16_ok() {
200 let val: Value = f16::from_f32(3.41).into();
201 let result = f16::try_from(val).unwrap();
202 assert_eq!(result, f16::from_f32(3.41));
203 }
204
205 #[test]
206 fn try_from_value_for_f16_err() {
207 let val = Value::Unsigned(1);
208 assert_eq!(f16::try_from(val), Err(Error::IncompatibleType(DataType::Int)));
209 }
210}