1use std::collections::BTreeMap;
8use std::path::PathBuf;
9
10use rkyv::{
11 Archive, Archived, Place, Resolver,
12 rancor::{Fallible, Source},
13 ser::{Allocator, Writer},
14 with::{ArchiveWith, DeserializeWith, SerializeWith},
15};
16
17pub struct AsPath;
29
30impl ArchiveWith<PathBuf> for AsPath {
31 type Archived = Archived<String>;
32 type Resolver = Resolver<String>;
33
34 fn resolve_with(field: &PathBuf, resolver: Self::Resolver, out: Place<Self::Archived>) {
35 let s = field.to_string_lossy().into_owned();
36 Archive::resolve(&s, resolver, out);
37 }
38}
39
40impl<S: Fallible + Writer + Allocator + ?Sized> SerializeWith<PathBuf, S> for AsPath
41where
42 S::Error: Source,
43{
44 fn serialize_with(field: &PathBuf, s: &mut S) -> Result<Self::Resolver, S::Error> {
45 let path_str = field.to_string_lossy().into_owned();
46 rkyv::Serialize::serialize(&path_str, s)
47 }
48}
49
50impl<D: Fallible + ?Sized> DeserializeWith<Archived<String>, PathBuf, D> for AsPath {
51 fn deserialize_with(field: &Archived<String>, _d: &mut D) -> Result<PathBuf, D::Error> {
52 Ok(PathBuf::from(field.as_str()))
53 }
54}
55
56pub struct AsJson;
78
79impl ArchiveWith<serde_json::Value> for AsJson {
82 type Archived = Archived<String>;
83 type Resolver = Resolver<String>;
84
85 fn resolve_with(
86 field: &serde_json::Value,
87 resolver: Self::Resolver,
88 out: Place<Self::Archived>,
89 ) {
90 let s = serde_json::to_string(field).unwrap_or_default();
91 Archive::resolve(&s, resolver, out);
92 }
93}
94
95impl<S: Fallible + Writer + Allocator + ?Sized> SerializeWith<serde_json::Value, S> for AsJson
96where
97 S::Error: Source,
98{
99 fn serialize_with(field: &serde_json::Value, s: &mut S) -> Result<Self::Resolver, S::Error> {
100 let json = serde_json::to_string(field).unwrap_or_default();
101 rkyv::Serialize::serialize(&json, s)
102 }
103}
104
105impl<D: Fallible + ?Sized> DeserializeWith<Archived<String>, serde_json::Value, D> for AsJson {
106 fn deserialize_with(
107 field: &Archived<String>,
108 _d: &mut D,
109 ) -> Result<serde_json::Value, D::Error> {
110 Ok(serde_json::from_str(field.as_str()).unwrap_or(serde_json::Value::Null))
111 }
112}
113
114impl ArchiveWith<BTreeMap<String, serde_json::Value>> for AsJson {
117 type Archived = Archived<String>;
118 type Resolver = Resolver<String>;
119
120 fn resolve_with(
121 field: &BTreeMap<String, serde_json::Value>,
122 resolver: Self::Resolver,
123 out: Place<Self::Archived>,
124 ) {
125 let s = serde_json::to_string(field).unwrap_or_default();
126 Archive::resolve(&s, resolver, out);
127 }
128}
129
130impl<S: Fallible + Writer + Allocator + ?Sized>
131 SerializeWith<BTreeMap<String, serde_json::Value>, S> for AsJson
132where
133 S::Error: Source,
134{
135 fn serialize_with(
136 field: &BTreeMap<String, serde_json::Value>,
137 s: &mut S,
138 ) -> Result<Self::Resolver, S::Error> {
139 let json = serde_json::to_string(field).unwrap_or_default();
140 rkyv::Serialize::serialize(&json, s)
141 }
142}
143
144impl<D: Fallible + ?Sized> DeserializeWith<Archived<String>, BTreeMap<String, serde_json::Value>, D>
145 for AsJson
146{
147 fn deserialize_with(
148 field: &Archived<String>,
149 _d: &mut D,
150 ) -> Result<BTreeMap<String, serde_json::Value>, D::Error> {
151 Ok(serde_json::from_str(field.as_str()).unwrap_or_default())
152 }
153}
154
155impl ArchiveWith<Vec<serde_json::Value>> for AsJson {
158 type Archived = Archived<String>;
159 type Resolver = Resolver<String>;
160
161 fn resolve_with(
162 field: &Vec<serde_json::Value>,
163 resolver: Self::Resolver,
164 out: Place<Self::Archived>,
165 ) {
166 let s = serde_json::to_string(field).unwrap_or_default();
167 Archive::resolve(&s, resolver, out);
168 }
169}
170
171impl<S: Fallible + Writer + Allocator + ?Sized> SerializeWith<Vec<serde_json::Value>, S> for AsJson
172where
173 S::Error: Source,
174{
175 fn serialize_with(
176 field: &Vec<serde_json::Value>,
177 s: &mut S,
178 ) -> Result<Self::Resolver, S::Error> {
179 let json = serde_json::to_string(field).unwrap_or_default();
180 rkyv::Serialize::serialize(&json, s)
181 }
182}
183
184impl<D: Fallible + ?Sized> DeserializeWith<Archived<String>, Vec<serde_json::Value>, D> for AsJson {
185 fn deserialize_with(
186 field: &Archived<String>,
187 _d: &mut D,
188 ) -> Result<Vec<serde_json::Value>, D::Error> {
189 Ok(serde_json::from_str(field.as_str()).unwrap_or_default())
190 }
191}
192
193impl ArchiveWith<Option<serde_json::Value>> for AsJson {
196 type Archived = Archived<Option<String>>;
197 type Resolver = Resolver<Option<String>>;
198
199 fn resolve_with(
200 field: &Option<serde_json::Value>,
201 resolver: Self::Resolver,
202 out: Place<Self::Archived>,
203 ) {
204 let s: Option<String> = field
205 .as_ref()
206 .map(|v| serde_json::to_string(v).unwrap_or_default());
207 Archive::resolve(&s, resolver, out);
208 }
209}
210
211impl<S: Fallible + Writer + Allocator + ?Sized> SerializeWith<Option<serde_json::Value>, S>
212 for AsJson
213where
214 S::Error: Source,
215{
216 fn serialize_with(
217 field: &Option<serde_json::Value>,
218 s: &mut S,
219 ) -> Result<Self::Resolver, S::Error> {
220 let opt: Option<String> = field
221 .as_ref()
222 .map(|v| serde_json::to_string(v).unwrap_or_default());
223 rkyv::Serialize::serialize(&opt, s)
224 }
225}
226
227impl<D: Fallible + ?Sized> DeserializeWith<Archived<Option<String>>, Option<serde_json::Value>, D>
228 for AsJson
229{
230 fn deserialize_with(
231 field: &Archived<Option<String>>,
232 _d: &mut D,
233 ) -> Result<Option<serde_json::Value>, D::Error> {
234 match field.as_ref() {
235 None => Ok(None),
236 Some(s) => Ok(Some(
237 serde_json::from_str(s.as_str()).unwrap_or(serde_json::Value::Null),
238 )),
239 }
240 }
241}
242
243impl ArchiveWith<Option<BTreeMap<String, serde_json::Value>>> for AsJson {
246 type Archived = Archived<Option<String>>;
247 type Resolver = Resolver<Option<String>>;
248
249 fn resolve_with(
250 field: &Option<BTreeMap<String, serde_json::Value>>,
251 resolver: Self::Resolver,
252 out: Place<Self::Archived>,
253 ) {
254 let s: Option<String> = field
255 .as_ref()
256 .map(|m| serde_json::to_string(m).unwrap_or_default());
257 Archive::resolve(&s, resolver, out);
258 }
259}
260
261impl<S: Fallible + Writer + Allocator + ?Sized>
262 SerializeWith<Option<BTreeMap<String, serde_json::Value>>, S> for AsJson
263where
264 S::Error: Source,
265{
266 fn serialize_with(
267 field: &Option<BTreeMap<String, serde_json::Value>>,
268 s: &mut S,
269 ) -> Result<Self::Resolver, S::Error> {
270 let opt: Option<String> = field
271 .as_ref()
272 .map(|m| serde_json::to_string(m).unwrap_or_default());
273 rkyv::Serialize::serialize(&opt, s)
274 }
275}
276
277impl<D: Fallible + ?Sized>
278 DeserializeWith<Archived<Option<String>>, Option<BTreeMap<String, serde_json::Value>>, D>
279 for AsJson
280{
281 fn deserialize_with(
282 field: &Archived<Option<String>>,
283 _d: &mut D,
284 ) -> Result<Option<BTreeMap<String, serde_json::Value>>, D::Error> {
285 match field.as_ref() {
286 None => Ok(None),
287 Some(s) => Ok(Some(serde_json::from_str(s.as_str()).unwrap_or_default())),
288 }
289 }
290}
291
292impl ArchiveWith<Option<Vec<serde_json::Value>>> for AsJson {
295 type Archived = Archived<Option<String>>;
296 type Resolver = Resolver<Option<String>>;
297
298 fn resolve_with(
299 field: &Option<Vec<serde_json::Value>>,
300 resolver: Self::Resolver,
301 out: Place<Self::Archived>,
302 ) {
303 let s: Option<String> = field
304 .as_ref()
305 .map(|v| serde_json::to_string(v).unwrap_or_default());
306 Archive::resolve(&s, resolver, out);
307 }
308}
309
310impl<S: Fallible + Writer + Allocator + ?Sized> SerializeWith<Option<Vec<serde_json::Value>>, S>
311 for AsJson
312where
313 S::Error: Source,
314{
315 fn serialize_with(
316 field: &Option<Vec<serde_json::Value>>,
317 s: &mut S,
318 ) -> Result<Self::Resolver, S::Error> {
319 let opt: Option<String> = field
320 .as_ref()
321 .map(|v| serde_json::to_string(v).unwrap_or_default());
322 rkyv::Serialize::serialize(&opt, s)
323 }
324}
325
326impl<D: Fallible + ?Sized>
327 DeserializeWith<Archived<Option<String>>, Option<Vec<serde_json::Value>>, D> for AsJson
328{
329 fn deserialize_with(
330 field: &Archived<Option<String>>,
331 _d: &mut D,
332 ) -> Result<Option<Vec<serde_json::Value>>, D::Error> {
333 match field.as_ref() {
334 None => Ok(None),
335 Some(s) => Ok(Some(serde_json::from_str(s.as_str()).unwrap_or_default())),
336 }
337 }
338}
339
340impl ArchiveWith<Vec<(PathBuf, u64)>> for AsJson {
346 type Archived = Archived<String>;
347 type Resolver = Resolver<String>;
348
349 fn resolve_with(
350 field: &Vec<(PathBuf, u64)>,
351 resolver: Self::Resolver,
352 out: Place<Self::Archived>,
353 ) {
354 let pairs: Vec<(String, u64)> = field
355 .iter()
356 .map(|(p, t)| (p.to_string_lossy().into_owned(), *t))
357 .collect();
358 let s = serde_json::to_string(&pairs).unwrap_or_default();
359 Archive::resolve(&s, resolver, out);
360 }
361}
362
363impl<S: Fallible + Writer + Allocator + ?Sized> SerializeWith<Vec<(PathBuf, u64)>, S> for AsJson
364where
365 S::Error: Source,
366{
367 fn serialize_with(field: &Vec<(PathBuf, u64)>, s: &mut S) -> Result<Self::Resolver, S::Error> {
368 let pairs: Vec<(String, u64)> = field
369 .iter()
370 .map(|(p, t)| (p.to_string_lossy().into_owned(), *t))
371 .collect();
372 let json = serde_json::to_string(&pairs).unwrap_or_default();
373 rkyv::Serialize::serialize(&json, s)
374 }
375}
376
377impl<D: Fallible + ?Sized> DeserializeWith<Archived<String>, Vec<(PathBuf, u64)>, D> for AsJson {
378 fn deserialize_with(
379 field: &Archived<String>,
380 _d: &mut D,
381 ) -> Result<Vec<(PathBuf, u64)>, D::Error> {
382 let pairs: Vec<(String, u64)> = serde_json::from_str(field.as_str()).unwrap_or_default();
383 Ok(pairs
384 .into_iter()
385 .map(|(s, t)| (PathBuf::from(s), t))
386 .collect())
387 }
388}
389
390#[cfg(test)]
391mod tests {
392 use std::collections::BTreeMap;
393 use std::path::PathBuf;
394
395 use rkyv::rancor::Error as RkyvError;
396 use serde_json::{Value, json};
397
398 use super::*;
399
400 macro_rules! roundtrip {
402 ($wrapper:ty, $field_ty:ty, $value:expr) => {{
403 #[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
404 struct Wrapper {
405 #[rkyv(with = $wrapper)]
406 field: $field_ty,
407 }
408 let original = Wrapper { field: $value };
409 let bytes = rkyv::to_bytes::<RkyvError>(&original).expect("serialize");
410 let decoded: Wrapper =
411 rkyv::from_bytes::<Wrapper, RkyvError>(&bytes).expect("deserialize");
412 decoded.field
413 }};
414 }
415
416 #[test]
417 fn as_path_roundtrips_utf8_path() {
418 let path = PathBuf::from("/home/user/templates/github.hcl");
419 let decoded = roundtrip!(AsPath, PathBuf, path.clone());
420 assert_eq!(decoded, path);
421 }
422
423 #[test]
424 fn as_json_value_roundtrips_object() {
425 let v: Value = json!({"key": "value", "num": 42});
426 let decoded = roundtrip!(AsJson, Value, v.clone());
427 assert_eq!(decoded, v);
428 }
429
430 #[test]
431 fn as_json_value_roundtrips_null() {
432 let decoded = roundtrip!(AsJson, Value, Value::Null);
433 assert_eq!(decoded, Value::Null);
434 }
435
436 #[test]
437 fn as_json_btreemap_roundtrips() {
438 let mut m = BTreeMap::new();
439 m.insert("x".to_string(), json!(1));
440 m.insert("y".to_string(), json!("hello"));
441 let decoded = roundtrip!(AsJson, BTreeMap<String, Value>, m.clone());
442 assert_eq!(decoded, m);
443 }
444
445 #[test]
446 fn as_json_vec_value_roundtrips() {
447 let v = vec![json!(1), json!("two"), json!(null)];
448 let decoded = roundtrip!(AsJson, Vec<Value>, v.clone());
449 assert_eq!(decoded, v);
450 }
451
452 #[test]
453 fn as_json_option_value_some_roundtrips() {
454 let v: Option<Value> = Some(json!({"a": true}));
455 let decoded = roundtrip!(AsJson, Option<Value>, v.clone());
456 assert_eq!(decoded, v);
457 }
458
459 #[test]
460 fn as_json_option_value_none_roundtrips() {
461 let v: Option<Value> = None;
462 let decoded = roundtrip!(AsJson, Option<Value>, v);
463 assert_eq!(decoded, None);
464 }
465
466 #[test]
467 fn as_json_option_btreemap_some_roundtrips() {
468 let mut m = BTreeMap::new();
469 m.insert("k".to_string(), json!(99));
470 let v: Option<BTreeMap<String, Value>> = Some(m.clone());
471 let decoded = roundtrip!(AsJson, Option<BTreeMap<String, Value>>, v);
472 assert_eq!(decoded, Some(m));
473 }
474
475 #[test]
476 fn as_json_option_btreemap_none_roundtrips() {
477 let v: Option<BTreeMap<String, Value>> = None;
478 let decoded = roundtrip!(AsJson, Option<BTreeMap<String, Value>>, v);
479 assert_eq!(decoded, None);
480 }
481
482 #[test]
483 fn as_json_option_vec_value_some_roundtrips() {
484 let v: Option<Vec<Value>> = Some(vec![json!(1), json!(2)]);
485 let decoded = roundtrip!(AsJson, Option<Vec<Value>>, v.clone());
486 assert_eq!(decoded, v);
487 }
488
489 #[test]
490 fn as_json_option_vec_value_none_roundtrips() {
491 let v: Option<Vec<Value>> = None;
492 let decoded = roundtrip!(AsJson, Option<Vec<Value>>, v);
493 assert_eq!(decoded, None);
494 }
495
496 #[test]
497 fn as_json_fingerprint_roundtrips() {
498 let fp = vec![
499 (PathBuf::from("/tmp/a.hcl"), 1_700_000_000u64),
500 (PathBuf::from("/home/user/b.hcl"), 999u64),
501 ];
502 let decoded = roundtrip!(AsJson, Vec<(PathBuf, u64)>, fp.clone());
503 assert_eq!(decoded, fp);
504 }
505}