lilliput_core/value/
map.rs1#[cfg(any(test, feature = "testing"))]
2use proptest::{prelude::*, sample::SizeRange};
3#[cfg(any(test, feature = "testing"))]
4use proptest_derive::Arbitrary;
5
6use super::Value;
7
8#[cfg(feature = "preserve_order")]
10pub type Map = ordermap::OrderMap<Value, Value>;
11
12#[cfg(not(feature = "preserve_order"))]
14pub type Map = std::collections::BTreeMap<Value, Value>;
15
16#[cfg(any(test, feature = "testing"))]
17pub(crate) fn arbitrary_map() -> impl Strategy<Value = Map> {
18 arbitrary_map_with(Value::arbitrary(), Value::arbitrary(), 0..10)
19}
20
21#[cfg(any(test, feature = "testing"))]
22pub(crate) fn arbitrary_map_with(
23 key: impl Strategy<Value = Value>,
24 value: impl Strategy<Value = Value>,
25 size: impl Into<SizeRange>,
26) -> impl Strategy<Value = Map> {
27 proptest::collection::hash_map(key, value, size.into()).prop_map(Map::from_iter)
28}
29
30#[cfg_attr(any(test, feature = "testing"), derive(Arbitrary))]
32#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
33pub struct MapValue(
34 #[cfg_attr(any(test, feature = "testing"), proptest(strategy = "arbitrary_map()"))] pub Map,
35);
36
37impl MapValue {
38 pub fn as_map_ref(&self) -> &Map {
40 &self.0
41 }
42
43 pub fn into_map(self) -> Map {
45 self.0
46 }
47
48 pub fn len(&self) -> usize {
50 self.0.len()
51 }
52
53 pub fn is_empty(&self) -> bool {
55 self.0.is_empty()
56 }
57}
58
59impl From<Map> for MapValue {
60 fn from(value: Map) -> Self {
61 Self(value)
62 }
63}
64
65impl<'a> From<&'a MapValue> for &'a Map {
66 fn from(value: &'a MapValue) -> Self {
67 &value.0
68 }
69}
70
71impl From<MapValue> for Map {
72 fn from(value: MapValue) -> Self {
73 value.0
74 }
75}
76
77impl std::fmt::Debug for MapValue {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 f.debug_map().entries(self.0.iter()).finish()
80 }
81}
82
83#[cfg(feature = "serde")]
84impl serde::Serialize for MapValue {
85 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
86 where
87 S: serde::Serializer,
88 {
89 self.0.serialize(serializer)
90 }
91}
92
93#[cfg(feature = "serde")]
94impl<'de> serde::Deserialize<'de> for MapValue {
95 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
96 where
97 D: serde::Deserializer<'de>,
98 {
99 Ok(Self(Map::deserialize(deserializer)?))
100 }
101}
102
103#[cfg(feature = "serde")]
104pub(crate) struct MapKeyClassifier;
105
106#[cfg(feature = "serde")]
107pub(crate) enum MapKeyClass {
108 Map(Value),
109}
110
111#[cfg(feature = "serde")]
112impl<'de> serde::de::DeserializeSeed<'de> for MapKeyClassifier {
113 type Value = MapKeyClass;
114
115 fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
116 where
117 D: serde::Deserializer<'de>,
118 {
119 use serde::Deserialize as _;
120
121 Ok(MapKeyClass::Map(Value::deserialize(deserializer)?))
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use proptest::prelude::*;
128 use test_log::test;
129
130 use crate::{
131 config::EncoderConfig,
132 decoder::Decoder,
133 encoder::Encoder,
134 io::{SliceReader, VecWriter},
135 value::{NullValue, Value},
136 };
137
138 use super::*;
139
140 #[test]
141 fn debug() {
142 let mut map = Map::default();
143 map.insert(Value::Null(NullValue), Value::Null(NullValue));
144 let value = MapValue::from(map);
145
146 assert_eq!(format!("{value:?}"), "{null: null}");
147 assert_eq!(
148 format!("{value:#?}"),
149 "{\n Null(\n null,\n ): Null(\n null,\n ),\n}"
150 );
151 }
152
153 proptest! {
154 #[test]
155 fn encode_decode_roundtrip(value in MapValue::arbitrary(), config in EncoderConfig::arbitrary()) {
156 let mut encoded: Vec<u8> = Vec::new();
157 let writer = VecWriter::new(&mut encoded);
158 let mut encoder = Encoder::new(writer, config);
159 encoder.encode_map(&value.0).unwrap();
160
161 let reader = SliceReader::new(&encoded);
165 let mut decoder = Decoder::from_reader(reader);
166 let decoded = decoder.decode_map().unwrap();
167 prop_assert_eq!(&decoded, &value.0);
168
169 let reader = SliceReader::new(&encoded);
170 let mut decoder = Decoder::from_reader(reader);
171 let decoded = decoder.decode_value().unwrap();
172 let Value::Map(decoded) = decoded else {
173 panic!("expected map value");
174 };
175 prop_assert_eq!(&decoded, &value);
176 }
177 }
178}