mmdb_writer/value.rs
1//! The [`Value`] data model — one MMDB data-section value.
2//!
3//! Every piece of data an MMDB file stores (a record payload, a map key, an array element,
4//! the metadata itself) reduces to a `Value`. Construct them directly with [`Value::map`],
5//! [`Value::array`], and the many [`From`] conversions, or — with the `serde` feature — let
6//! [`Writer::insert`] build them from any `serde::Serialize` type.
7//!
8//! [`Writer::insert`]: crate::Writer::insert
9
10use std::collections::BTreeMap;
11
12/// One MMDB data-section value.
13///
14/// The variants correspond one-to-one with the data types defined by the [MMDB format].
15/// There is deliberately no null/unit variant — MMDB has no null type; absence is modeled
16/// by omitting a map entry.
17///
18/// # Equality and hashing
19///
20/// Floating-point variants ([`Value::Float`], [`Value::Double`]) compare and hash by their
21/// raw bit pattern, so bit-identical values (including matching `NaN` payloads) are treated
22/// as equal. This is what lets the writer deduplicate repeated values in the data section.
23///
24/// # Construction
25///
26/// ```
27/// use mmdb_writer::Value;
28///
29/// let scalar = Value::from(42_u32);
30/// let list = Value::array([Value::from("a"), Value::from("b")]);
31/// let map = Value::map([
32/// ("count", Value::from(2_u32)),
33/// ("items", list),
34/// ]);
35/// assert!(matches!(map, Value::Map(_)));
36/// ```
37///
38/// [MMDB format]: https://maxmind.github.io/MaxMind-DB/
39#[derive(Debug, Clone)]
40#[non_exhaustive]
41pub enum Value {
42 /// UTF-8 string (type 2).
43 String(String),
44 /// IEEE 754 binary64 (type 3).
45 Double(f64),
46 /// Arbitrary byte blob (type 4).
47 Bytes(Vec<u8>),
48 /// Unsigned 16-bit integer (type 5).
49 U16(u16),
50 /// Unsigned 32-bit integer (type 6).
51 U32(u32),
52 /// String-keyed map (type 7). Backed by a [`BTreeMap`] so the encoded byte order — and
53 /// therefore the output — is deterministic.
54 Map(BTreeMap<String, Value>),
55 /// Signed 32-bit integer (extended type 8).
56 I32(i32),
57 /// Unsigned 64-bit integer (extended type 9).
58 U64(u64),
59 /// Unsigned 128-bit integer (extended type 10).
60 U128(u128),
61 /// Ordered array (extended type 11).
62 Array(Vec<Value>),
63 /// Boolean (extended type 14).
64 Bool(bool),
65 /// IEEE 754 binary32 (extended type 15).
66 Float(f32),
67}
68
69impl Value {
70 /// Build a [`Value::Map`] from key/value pairs.
71 ///
72 /// Keys convert via [`Into<String>`] and values via [`Into<Value>`], so string literals
73 /// and scalars can be passed directly.
74 ///
75 /// ```
76 /// use mmdb_writer::Value;
77 ///
78 /// let v = Value::map([
79 /// ("asn", Value::from(64_512_u32)),
80 /// ("org", Value::from("Example, Inc.")),
81 /// ]);
82 /// ```
83 pub fn map<K, V, I>(entries: I) -> Self
84 where
85 K: Into<String>,
86 V: Into<Value>,
87 I: IntoIterator<Item = (K, V)>,
88 {
89 Self::Map(
90 entries
91 .into_iter()
92 .map(|(k, v)| (k.into(), v.into()))
93 .collect(),
94 )
95 }
96
97 /// Build a [`Value::Array`] from a sequence of values.
98 ///
99 /// Elements convert via [`Into<Value>`].
100 ///
101 /// ```
102 /// use mmdb_writer::Value;
103 ///
104 /// let v = Value::array([Value::from(1_u32), Value::from(2_u32)]);
105 /// ```
106 pub fn array<V, I>(items: I) -> Self
107 where
108 V: Into<Value>,
109 I: IntoIterator<Item = V>,
110 {
111 Self::Array(items.into_iter().map(Into::into).collect())
112 }
113
114 /// Merge `new` onto `existing`, combining only the top level of two maps.
115 ///
116 /// If both are [`Value::Map`], the result contains every key from both; on a key present
117 /// in both, `new`'s value wins (no recursion into nested maps). If either side is not a
118 /// map, `new` is returned unchanged. This is the equivalent of the Go writer's
119 /// `TopLevelMergeWith` inserter.
120 #[must_use]
121 pub fn merge_top_level(existing: &Value, new: &Value) -> Value {
122 match (existing, new) {
123 (Value::Map(old), Value::Map(new_map)) => {
124 let mut merged = old.clone();
125 for (k, v) in new_map {
126 merged.insert(k.clone(), v.clone());
127 }
128 Value::Map(merged)
129 }
130 _ => new.clone(),
131 }
132 }
133
134 /// Merge `new` onto `existing`, recursing into nested maps and concatenating arrays.
135 ///
136 /// - Two maps merge key by key, recursing on keys present in both.
137 /// - Two arrays concatenate (`existing` elements followed by `new` elements).
138 /// - Any other combination yields `new`.
139 ///
140 /// This is the equivalent of the Go writer's `DeepMergeWith` inserter.
141 #[must_use]
142 pub fn merge_deep(existing: &Value, new: &Value) -> Value {
143 match (existing, new) {
144 (Value::Map(old), Value::Map(new_map)) => {
145 let mut merged = old.clone();
146 for (k, v) in new_map {
147 let combined = match merged.get(k) {
148 Some(prev) => Value::merge_deep(prev, v),
149 None => v.clone(),
150 };
151 merged.insert(k.clone(), combined);
152 }
153 Value::Map(merged)
154 }
155 (Value::Array(old), Value::Array(new_arr)) => {
156 let mut merged = old.clone();
157 merged.extend(new_arr.iter().cloned());
158 Value::Array(merged)
159 }
160 _ => new.clone(),
161 }
162 }
163}
164
165impl PartialEq for Value {
166 fn eq(&self, other: &Self) -> bool {
167 match (self, other) {
168 (Self::String(a), Self::String(b)) => a == b,
169 (Self::Double(a), Self::Double(b)) => a.to_bits() == b.to_bits(),
170 (Self::Bytes(a), Self::Bytes(b)) => a == b,
171 (Self::U16(a), Self::U16(b)) => a == b,
172 (Self::U32(a), Self::U32(b)) => a == b,
173 (Self::Map(a), Self::Map(b)) => a == b,
174 (Self::I32(a), Self::I32(b)) => a == b,
175 (Self::U64(a), Self::U64(b)) => a == b,
176 (Self::U128(a), Self::U128(b)) => a == b,
177 (Self::Array(a), Self::Array(b)) => a == b,
178 (Self::Bool(a), Self::Bool(b)) => a == b,
179 (Self::Float(a), Self::Float(b)) => a.to_bits() == b.to_bits(),
180 _ => false,
181 }
182 }
183}
184
185impl Eq for Value {}
186
187impl std::hash::Hash for Value {
188 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
189 std::mem::discriminant(self).hash(state);
190 match self {
191 Self::String(v) => v.hash(state),
192 Self::Double(v) => v.to_bits().hash(state),
193 Self::Bytes(v) => v.hash(state),
194 Self::U16(v) => v.hash(state),
195 Self::U32(v) => v.hash(state),
196 Self::Map(v) => v.hash(state),
197 Self::I32(v) => v.hash(state),
198 Self::U64(v) => v.hash(state),
199 Self::U128(v) => v.hash(state),
200 Self::Array(v) => v.hash(state),
201 Self::Bool(v) => v.hash(state),
202 Self::Float(v) => v.to_bits().hash(state),
203 }
204 }
205}
206
207// --- From conversions -------------------------------------------------------------------
208
209impl From<&str> for Value {
210 fn from(v: &str) -> Self {
211 Self::String(v.to_owned())
212 }
213}
214
215impl From<String> for Value {
216 fn from(v: String) -> Self {
217 Self::String(v)
218 }
219}
220
221impl From<bool> for Value {
222 fn from(v: bool) -> Self {
223 Self::Bool(v)
224 }
225}
226
227impl From<f32> for Value {
228 fn from(v: f32) -> Self {
229 Self::Float(v)
230 }
231}
232
233impl From<f64> for Value {
234 fn from(v: f64) -> Self {
235 Self::Double(v)
236 }
237}
238
239// Unsigned integers map to the narrowest MMDB type that holds them; `u8`/`u16` share the
240// 16-bit type, matching how the serde serializer widens them.
241impl From<u8> for Value {
242 fn from(v: u8) -> Self {
243 Self::U16(u16::from(v))
244 }
245}
246
247impl From<u16> for Value {
248 fn from(v: u16) -> Self {
249 Self::U16(v)
250 }
251}
252
253impl From<u32> for Value {
254 fn from(v: u32) -> Self {
255 Self::U32(v)
256 }
257}
258
259impl From<u64> for Value {
260 fn from(v: u64) -> Self {
261 Self::U64(v)
262 }
263}
264
265impl From<u128> for Value {
266 fn from(v: u128) -> Self {
267 Self::U128(v)
268 }
269}
270
271// Signed integers narrower than 64-bit share the single MMDB signed type (int32).
272impl From<i8> for Value {
273 fn from(v: i8) -> Self {
274 Self::I32(i32::from(v))
275 }
276}
277
278impl From<i16> for Value {
279 fn from(v: i16) -> Self {
280 Self::I32(i32::from(v))
281 }
282}
283
284impl From<i32> for Value {
285 fn from(v: i32) -> Self {
286 Self::I32(v)
287 }
288}
289
290impl From<Vec<u8>> for Value {
291 fn from(v: Vec<u8>) -> Self {
292 Self::Bytes(v)
293 }
294}
295
296impl From<Vec<Value>> for Value {
297 fn from(v: Vec<Value>) -> Self {
298 Self::Array(v)
299 }
300}
301
302impl From<BTreeMap<String, Value>> for Value {
303 fn from(v: BTreeMap<String, Value>) -> Self {
304 Self::Map(v)
305 }
306}
307
308impl FromIterator<Value> for Value {
309 fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
310 Self::Array(iter.into_iter().collect())
311 }
312}
313
314impl FromIterator<(String, Value)> for Value {
315 fn from_iter<I: IntoIterator<Item = (String, Value)>>(iter: I) -> Self {
316 Self::Map(iter.into_iter().collect())
317 }
318}
319
320#[cfg(feature = "serde")]
321mod serde_impls;