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