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