1#[cfg(feature = "schemars")]
2use schemars::{JsonSchema, json_schema};
3use serde::de::{Error, MapAccess, Visitor};
4use serde::ser::SerializeMap;
5use serde::{Deserialize, Deserializer, Serialize};
6use std::hash::Hash;
7use std::marker::PhantomData;
8
9#[derive(Debug, Clone, Copy, Eq, PartialOrd, Ord, Hash)]
10pub struct SingleKVMap<Key, Value> {
11 pub key: Key,
12 pub value: Value,
13}
14
15impl<LeftKey: PartialEq<RightKey>, LeftValue: PartialEq<RightValue>, RightKey, RightValue>
16 PartialEq<SingleKVMap<RightKey, RightValue>> for SingleKVMap<LeftKey, LeftValue>
17{
18 fn eq(&self, other: &SingleKVMap<RightKey, RightValue>) -> bool {
19 self.key == other.key && self.value == other.value
20 }
21}
22
23impl<Key: Serialize, Value: Serialize> Serialize for SingleKVMap<Key, Value> {
24 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
25 where
26 S: serde::Serializer,
27 {
28 let mut map = serializer.serialize_map(Some(1))?;
29 map.serialize_entry(&self.key, &self.value)?;
30 map.end()
31 }
32}
33
34struct SingleKVMapVisitor<Key, Value>(PhantomData<(Key, Value)>);
35
36impl<Key, Value> Default for SingleKVMapVisitor<Key, Value> {
37 fn default() -> Self {
38 Self(PhantomData)
39 }
40}
41
42impl<'de, Key: Deserialize<'de>, Value: Deserialize<'de>> Visitor<'de>
43 for SingleKVMapVisitor<Key, Value>
44{
45 type Value = SingleKVMap<Key, Value>;
46
47 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
48 formatter.write_str("a map with a single key-value")
49 }
50
51 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error>
52 where
53 A::Error: Error,
54 {
55 let (key, value) = map
56 .next_entry()?
57 .ok_or(A::Error::missing_field("missing first (and only) entry"))?;
58
59 if let Some(remaining) = map.size_hint()
60 && remaining != 0
61 {
62 Err(A::Error::unknown_field(
63 &format!("Found {remaining} remaining entries, expecting 0"),
64 &[],
65 ))
66 } else {
67 Ok(SingleKVMap::new(key, value))
68 }
69 }
70}
71
72impl<'de, Key: Deserialize<'de>, Value: Deserialize<'de>> Deserialize<'de>
73 for SingleKVMap<Key, Value>
74{
75 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
76 deserializer.deserialize_map(SingleKVMapVisitor::default())
77 }
78}
79
80impl<Key, Value> SingleKVMap<Key, Value> {
81 pub fn new(key: Key, value: Value) -> Self {
82 Self { key, value }
83 }
84
85 pub fn from_entry(entry: (Key, Value)) -> Self {
86 let (key, value) = entry;
87 Self { key, value }
88 }
89
90 pub fn as_key(&self) -> &Key {
91 &self.key
92 }
93
94 pub fn as_key_mut(&mut self) -> &mut Key {
95 &mut self.key
96 }
97
98 pub fn into_key(self) -> Key {
99 self.key
100 }
101
102 pub fn set_key(&mut self, new_key: Key) -> Key {
103 std::mem::replace(&mut self.key, new_key)
104 }
105
106 pub fn as_value(&self) -> &Value {
107 &self.value
108 }
109
110 pub fn as_value_mut(&mut self) -> &mut Value {
111 &mut self.value
112 }
113
114 pub fn into_value(self) -> Value {
115 self.value
116 }
117
118 pub fn set_value(&mut self, new_value: Value) -> Value {
119 std::mem::replace(&mut self.value, new_value)
120 }
121
122 pub fn as_entry(&self) -> (&Key, &Value) {
123 (&self.key, &self.value)
124 }
125
126 pub fn as_entry_mut(&mut self) -> (&mut Key, &mut Value) {
127 (&mut self.key, &mut self.value)
128 }
129
130 pub fn into_entry(self) -> (Key, Value) {
131 (self.key, self.value)
132 }
133
134 pub fn set_entry(&mut self, new_entry: (Key, Value)) -> (Key, Value) {
135 let (new_key, new_value) = new_entry;
136 (
137 std::mem::replace(&mut self.key, new_key),
138 std::mem::replace(&mut self.value, new_value),
139 )
140 }
141}
142
143impl<Key, Value> From<(Key, Value)> for SingleKVMap<Key, Value> {
144 fn from(entry: (Key, Value)) -> Self {
145 Self::from_entry(entry)
146 }
147}
148
149impl<Key, Value> AsRef<SingleKVMap<Key, Value>> for SingleKVMap<Key, Value> {
150 fn as_ref(&self) -> &SingleKVMap<Key, Value> {
151 self
152 }
153}
154
155#[cfg(feature = "schemars")]
156impl<Key: JsonSchema, Value: JsonSchema> JsonSchema for SingleKVMap<Key, Value> {
157 fn schema_name() -> std::borrow::Cow<'static, str> {
158 format!("{}{}SingleKVMap", Key::schema_name(), Value::schema_name()).into()
159 }
160
161 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
162 let mut key_schema = generator.subschema_for::<Key>();
163 let value_schema = generator.subschema_for::<Value>();
164
165 key_schema.as_object_mut().map(|x| x.remove("type"));
166
167 json_schema!({
168 "type": "object",
169 "propertyNames": key_schema,
170 "additionalProperties": value_schema,
171 "minProperties": 1,
172 "maxProperties": 1,
173 })
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use pretty_assertions::assert_eq;
180 #[cfg(feature = "schemars")]
181 use schemars::schema_for;
182 use serde_json::json;
183
184 use super::*;
185
186 #[derive(Debug, Serialize, Deserialize, PartialEq)]
187 #[cfg_attr(feature = "schemars", derive(JsonSchema))]
188 enum MyEnum {
189 A,
190 B,
191 }
192
193 #[cfg(feature = "schemars")]
194 #[test]
195 fn derive_json_schema() {
196 assert_eq!(
197 schema_for!(SingleKVMap<i32, String>),
198 json_schema!({
199 "$schema": "https://json-schema.org/draft/2020-12/schema",
200 "title": "int32stringSingleKVMap",
201 "type": "object",
202 "additionalProperties": {
203 "type": "string"
204 },
205 "propertyNames": {
206 "format": "int32"
207 },
208 "minProperties": 1,
209 "maxProperties": 1,
210 })
211 )
212 }
213
214 #[cfg(feature = "schemars")]
215 #[test]
216 fn derive_json_schema_enum() {
217 assert_eq!(
218 schema_for!(SingleKVMap<MyEnum, MyEnum>),
219 json_schema!({
220 "$schema": "https://json-schema.org/draft/2020-12/schema",
221 "title": "MyEnumMyEnumSingleKVMap",
222 "type": "object",
223 "additionalProperties": {
224 "$ref": "#/$defs/MyEnum"
225 },
226 "propertyNames": {
227 "$ref": "#/$defs/MyEnum"
228 },
229 "minProperties": 1,
230 "maxProperties": 1,
231 "$defs": {
232 "MyEnum": {
233 "type": "string",
234 "enum": ["A", "B"]
235 }
236 }
237 })
238 )
239 }
240
241 #[test]
242 fn derive_serialize() {
243 assert_eq!(
244 serde_json::to_value(SingleKVMap::new(10, "hello")).unwrap(),
245 json! ({
246 "10": "hello"
247 })
248 )
249 }
250
251 #[test]
252 fn derive_serialize_enum() {
253 assert_eq!(
254 serde_json::to_value(SingleKVMap::new(MyEnum::A, MyEnum::B)).unwrap(),
255 json! ({
256 "A": "B"
257 })
258 )
259 }
260
261 #[test]
262 fn derive_deserialize() {
263 assert_eq!(
264 serde_json::from_value::<SingleKVMap<i32, String>>(json! ({
265 "10": "hello"
266 }))
267 .unwrap(),
268 SingleKVMap::new(10, "hello"),
269 )
270 }
271
272 #[test]
273 fn derive_deserialize_enum() {
274 assert_eq!(
275 serde_json::from_value::<SingleKVMap<MyEnum, MyEnum>>(json! ({
276 "A": "B"
277 }))
278 .unwrap(),
279 SingleKVMap::new(MyEnum::A, MyEnum::B),
280 )
281 }
282}