1use num_bigint::BigInt;
2use num_rational::BigRational;
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use std::fmt;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum Value {
13 Int(BigInt),
15 Rational(BigRational),
17 Unit { number: Box<Value>, unit: UnitId },
19}
20
21pub use crate::unit::UnitId;
23
24impl Serialize for Value {
25 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
26 where
27 S: Serializer,
28 {
29 use serde::ser::SerializeMap;
30 match self {
31 Value::Int(n) => {
32 let mut map = serializer.serialize_map(Some(2))?;
33 map.serialize_entry("kind", "int")?;
34 map.serialize_entry("value", &n.to_string())?;
35 map.end()
36 }
37 Value::Rational(r) => {
38 let mut map = serializer.serialize_map(Some(3))?;
39 map.serialize_entry("kind", "rational")?;
40 map.serialize_entry("numerator", &r.numer().to_string())?;
41 map.serialize_entry("denominator", &r.denom().to_string())?;
42 map.end()
43 }
44 Value::Unit { number, unit } => {
45 let (number_kind, numerator, denominator) = match number.as_ref() {
46 Value::Int(n) => ("int", n.to_string(), "1".to_string()),
47 Value::Rational(r) => {
48 ("rational", r.numer().to_string(), r.denom().to_string())
49 }
50 Value::Unit { .. } => {
51 return Err(serde::ser::Error::custom("unit may not wrap another unit"));
52 }
53 };
54 let mut map = serializer.serialize_map(Some(5))?;
55 map.serialize_entry("kind", "unit")?;
56 map.serialize_entry("number_kind", number_kind)?;
57 map.serialize_entry("numerator", &numerator)?;
58 map.serialize_entry("denominator", &denominator)?;
59 map.serialize_entry("unit", &unit.to_string())?;
60 map.end()
61 }
62 }
63 }
64}
65
66impl<'de> Deserialize<'de> for Value {
67 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
68 where
69 D: Deserializer<'de>,
70 {
71 #[derive(Deserialize)]
72 struct Raw {
73 kind: String,
74 value: Option<String>,
75 numerator: Option<String>,
76 denominator: Option<String>,
77 number_kind: Option<String>,
78 unit: Option<String>,
79 }
80
81 let raw = Raw::deserialize(deserializer)?;
82 match raw.kind.as_str() {
83 "int" => {
84 let value = raw
85 .value
86 .ok_or_else(|| serde::de::Error::missing_field("value"))?;
87 let n: BigInt = value
88 .parse()
89 .map_err(|_| serde::de::Error::custom("invalid integer"))?;
90 Ok(Value::Int(n))
91 }
92 "rational" => {
93 let num_str = raw
94 .numerator
95 .ok_or_else(|| serde::de::Error::missing_field("numerator"))?;
96 let den_str = raw
97 .denominator
98 .ok_or_else(|| serde::de::Error::missing_field("denominator"))?;
99 let n: BigInt = num_str
100 .parse()
101 .map_err(|_| serde::de::Error::custom("invalid numerator"))?;
102 let d: BigInt = den_str
103 .parse()
104 .map_err(|_| serde::de::Error::custom("invalid denominator"))?;
105 if d == BigInt::from(0) {
106 return Err(serde::de::Error::custom("zero denominator"));
107 }
108 Ok(Value::Rational(BigRational::new(n, d)))
109 }
110 "unit" => {
111 let number_kind = raw
112 .number_kind
113 .ok_or_else(|| serde::de::Error::missing_field("number_kind"))?;
114 let num_str = raw
115 .numerator
116 .ok_or_else(|| serde::de::Error::missing_field("numerator"))?;
117 let den_str = raw
118 .denominator
119 .ok_or_else(|| serde::de::Error::missing_field("denominator"))?;
120 let unit_str = raw
121 .unit
122 .ok_or_else(|| serde::de::Error::missing_field("unit"))?;
123
124 let number = match number_kind.as_str() {
125 "int" => {
126 let n: BigInt = num_str
127 .parse()
128 .map_err(|_| serde::de::Error::custom("invalid integer"))?;
129 Value::Int(n)
130 }
131 "rational" => {
132 let n: BigInt = num_str
133 .parse()
134 .map_err(|_| serde::de::Error::custom("invalid numerator"))?;
135 let d: BigInt = den_str
136 .parse()
137 .map_err(|_| serde::de::Error::custom("invalid denominator"))?;
138 if d == BigInt::from(0) {
139 return Err(serde::de::Error::custom("zero denominator"));
140 }
141 Value::Rational(BigRational::new(n, d))
142 }
143 _ => return Err(serde::de::Error::custom("unknown number_kind")),
144 };
145 let unit = UnitId::from_symbol(&unit_str)
146 .unwrap_or_else(|| UnitId::Unknown(unit_str.clone()));
147 Ok(Value::Unit {
148 number: Box::new(number),
149 unit,
150 })
151 }
152 other => Err(serde::de::Error::custom(format!("unknown kind: {}", other))),
153 }
154 }
155}
156
157impl fmt::Display for Value {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 match self {
160 Value::Int(n) => write!(f, "{}", n),
161 Value::Rational(r) => {
162 if r.denom() == &BigInt::from(1) {
163 write!(f, "{}", r.numer())
164 } else {
165 write!(f, "{}/{}", r.numer(), r.denom())
166 }
167 }
168 Value::Unit { number, unit } => write!(f, "{} {}", number, unit),
169 }
170 }
171}