1use std::collections::BTreeMap;
20use std::marker::PhantomData;
21
22use crate::schema::{Kinds, Reader, Schema, Shape, Text, is_metadata_key, read_ref};
23use crate::value::{Map, Ref, Seg, Value};
24
25pub trait With<F> {
27 fn shape() -> Shape;
28 fn read(v: &Value, cx: &mut Reader) -> Option<F>;
29 fn write(f: &F) -> Value;
30 fn absent() -> Option<F> {
32 None
33 }
34 fn skip(_f: &F) -> bool {
36 false
37 }
38}
39
40pub struct RefTo<K>(PhantomData<K>);
42
43impl<K: Kinds> With<String> for RefTo<K> {
44 fn shape() -> Shape {
45 Shape::Ref(K::NAMES)
46 }
47 fn read(v: &Value, cx: &mut Reader) -> Option<String> {
48 let r = read_ref(v, cx, K::NAMES)?;
49 cx.resolve_ref(&r)
50 }
51 fn write(f: &String) -> Value {
52 Value::Ref(Ref::new(
53 K::NAMES.first().copied().unwrap_or("item"),
54 f.clone(),
55 ))
56 }
57}
58
59pub struct TextOf;
61
62impl With<String> for TextOf {
63 fn shape() -> Shape {
64 Shape::Text
65 }
66 fn read(v: &Value, cx: &mut Reader) -> Option<String> {
67 let t = Text::read(v, cx)?;
68 cx.resolve_text(&t)
69 }
70 fn write(f: &String) -> Value {
71 Value::Text(f.clone())
72 }
73}
74
75pub struct Opt<W>(PhantomData<W>);
77
78impl<F, W: With<F>> With<Option<F>> for Opt<W> {
79 fn shape() -> Shape {
80 Shape::Optional(W::shape)
81 }
82 fn read(v: &Value, cx: &mut Reader) -> Option<Option<F>> {
83 if v.is_null() {
84 Some(None)
85 } else {
86 W::read(v, cx).map(Some)
87 }
88 }
89 fn write(f: &Option<F>) -> Value {
90 f.as_ref().map_or(Value::Null, W::write)
91 }
92 fn absent() -> Option<Option<F>> {
93 Some(None)
94 }
95 fn skip(f: &Option<F>) -> bool {
96 f.is_none()
97 }
98}
99
100pub struct List<W>(PhantomData<W>);
102
103impl<F, W: With<F>> With<Vec<F>> for List<W> {
104 fn shape() -> Shape {
105 Shape::List(W::shape)
106 }
107 fn read(v: &Value, cx: &mut Reader) -> Option<Vec<F>> {
108 let Value::List(items) = v else {
109 cx.expected("a list", v);
110 return None;
111 };
112 let mut out = Vec::with_capacity(items.len());
113 let mut ok = true;
114 for (i, item) in items.iter().enumerate() {
115 match cx.at(Seg::Index(i), |cx| W::read(item, cx)) {
116 Some(x) => out.push(x),
117 None => ok = false,
118 }
119 }
120 ok.then_some(out)
121 }
122 fn write(f: &Vec<F>) -> Value {
123 Value::List(f.iter().map(W::write).collect())
124 }
125}
126
127pub struct Values<W>(PhantomData<W>);
129
130impl<F, W: With<F>> With<BTreeMap<String, F>> for Values<W> {
131 fn shape() -> Shape {
132 Shape::Map(W::shape)
133 }
134 fn read(v: &Value, cx: &mut Reader) -> Option<BTreeMap<String, F>> {
135 let map = cx.map(v)?;
136 let mut out = BTreeMap::new();
137 let mut ok = true;
138 for (k, item) in map.iter().filter(|(k, _)| !is_metadata_key(k)) {
139 match cx.at(Seg::Key(k.to_string()), |cx| W::read(item, cx)) {
140 Some(x) => {
141 out.insert(k.to_string(), x);
142 }
143 None => ok = false,
144 }
145 }
146 ok.then_some(out)
147 }
148 fn write(f: &BTreeMap<String, F>) -> Value {
149 Value::Map(
150 f.iter()
151 .map(|(k, v)| (k.clone(), W::write(v)))
152 .collect::<Map>(),
153 )
154 }
155}
156
157pub struct Plain;
159
160impl<F: Schema> With<F> for Plain {
161 fn shape() -> Shape {
162 F::shape()
163 }
164 fn read(v: &Value, cx: &mut Reader) -> Option<F> {
165 F::read(v, cx)
166 }
167 fn write(f: &F) -> Value {
168 f.write()
169 }
170 fn absent() -> Option<F> {
171 F::absent()
172 }
173 fn skip(f: &F) -> bool {
174 f.skip()
175 }
176}