1mod fields;
8mod one_or_list;
9mod plain;
10mod reader;
11mod shape;
12mod typed_values;
13
14pub use fields::{Fields, field_name};
15pub use one_or_list::OneOrList;
16pub use plain::*;
17pub use reader::*;
18pub use shape::*;
19pub use typed_values::*;
20
21use std::collections::{BTreeMap, HashMap};
22use std::fmt;
23use std::marker::PhantomData;
24
25use crate::binary::{Decoder, Writer};
26use crate::borrowed::{MapRef, ValueRef};
27use crate::diagnostic::{Diagnostic, Errors};
28use crate::frame::{Packer, Unpacker};
29use crate::text::{self, Doc, LineCol};
30use crate::typed;
31use crate::value::{Map, Path, Ref, Res, Seg, Value};
32
33pub trait Schema: Sized {
35 fn shape() -> Shape;
37
38 fn read(v: &ValueRef<'_>, cx: &mut Reader) -> Option<Self>;
41
42 fn write(&self) -> Value;
44
45 fn absent() -> Option<Self> {
47 None
48 }
49
50 fn skip(&self) -> bool {
52 false
53 }
54
55 fn encode(&self, w: &mut Writer) {
58 w.value(&self.write());
59 }
60
61 fn decode(d: &mut Decoder<'_>) -> Option<Self> {
66 let arena = bumpalo::Bump::new();
67 let v = d.value_ref(&arena).ok()?;
68 read_ref_value(&v).ok()
69 }
70
71 fn pack(&self, p: &mut Packer) {
74 p.put_tagged(self);
75 }
76
77 fn unpack(u: &mut Unpacker<'_>) -> Option<Self> {
80 u.get_tagged()
81 }
82
83 fn pack_list(items: &[Self], p: &mut Packer) {
85 let at = p.begin_list(items.len());
86 for item in items {
87 item.pack(p);
88 }
89 p.end(at);
90 }
91
92 fn unpack_list(u: &mut Unpacker<'_>) -> Option<Vec<Self>> {
94 let (n, end) = u.list()?;
95 let mut out = Vec::with_capacity(n);
96 for _ in 0..n {
97 out.push(Self::unpack(u)?);
98 }
99 u.skip_to(end)?;
100 Some(out)
101 }
102
103 fn encode_list(items: &[Self], w: &mut Writer) {
105 w.list(items.len());
106 for item in items {
107 item.encode(w);
108 }
109 }
110
111 fn decode_list(d: &mut Decoder<'_>) -> Option<Vec<Self>> {
113 let n = d.list()?;
114 let mut out = Vec::with_capacity(n);
115 for _ in 0..n {
116 out.push(Self::decode(d)?);
117 }
118 d.leave();
119 Some(out)
120 }
121}
122
123pub const WRAPPED: &str = yog_ids::word::VALUE;
127
128#[doc(hidden)]
131pub fn flattens<T: Schema>() -> bool {
132 matches!(T::shape(), Shape::Struct(_))
133}
134
135pub fn to_bytes<T: Schema>(v: &T) -> Vec<u8> {
137 let mut w = Writer::new();
138 v.encode(&mut w);
139 w.finish()
140}
141
142pub fn field_names(shape: &Shape) -> Vec<&'static str> {
144 match shape {
145 Shape::Struct(s) => s.fields.iter().map(|f| f.name).collect(),
146 _ => Vec::new(),
147 }
148}
149
150pub fn read_both<A: Schema, B: Schema>(
153 v: &ValueRef,
154 cx: &mut Reader,
155 also: &[&'static str],
156) -> Option<(A, B)> {
157 let (an, bn) = (field_names(&A::shape()), field_names(&B::shape()));
158 let mut b_keys = bn.clone();
159 b_keys.extend_from_slice(also);
160 let mut a_keys = an;
161 a_keys.extend_from_slice(also);
162 let a = cx.with_allowed_all(&b_keys, |cx| A::read(v, cx));
163 let b = cx.with_allowed_all(&a_keys, |cx| B::read(v, cx));
164 Some((a?, b?))
165}
166
167pub fn from_value<T: Schema>(v: &Value) -> Result<Read<T>, Vec<Diagnostic>> {
169 let arena = bumpalo::Bump::new();
170 read_with(&v.borrow(&arena), Reader::new())
171}
172
173pub fn read_value<T: Schema>(v: &Value) -> Result<T, Vec<Diagnostic>> {
176 let arena = bumpalo::Bump::new();
177 read_ref_value(&v.borrow(&arena))
178}
179
180pub fn read_ref_value<T: Schema>(v: &ValueRef) -> Result<T, Vec<Diagnostic>> {
182 let reader = Reader {
183 value_only: true,
184 ..Reader::new()
185 };
186 read_with(v, reader).map(|r| r.value)
187}
188
189pub fn read_bytes<T: Schema>(bytes: &[u8]) -> Result<T, Vec<Diagnostic>> {
192 if let Ok(mut d) = Decoder::open(bytes)
194 && let Some(v) = T::decode(&mut d)
195 && d.at_end()
196 {
197 return Ok(v);
198 }
199 let arena = bumpalo::Bump::new();
200 let v = crate::binary::decode_ref(bytes, &arena)
201 .map_err(|e| vec![Diagnostic::error(yog_ids::data_problem::BAD_BINARY, e)])?;
202 read_ref_value(&v)
203}
204
205pub fn from_value_with<T: Schema>(
207 v: &Value,
208 resolver: &mut dyn Resolve,
209) -> Result<Read<T>, Vec<Diagnostic>> {
210 let arena = bumpalo::Bump::new();
211 read_with(&v.borrow(&arena), Reader::with_resolver(resolver))
212}
213
214fn read_with<T: Schema>(v: &ValueRef, mut cx: Reader<'_>) -> Result<Read<T>, Vec<Diagnostic>> {
215 let value = T::read(v, &mut cx);
216 match value {
217 Some(value) if cx.problems.is_empty() => Ok(Read {
218 value,
219 refs: cx.refs,
220 tags: cx.tags,
221 resources: cx.resources,
222 }),
223 _ => Err(cx.problems),
224 }
225}
226
227pub fn built_in<T: Schema + Default>(what: &str, text: &str) -> T {
231 match from_text::<T>(text) {
232 Ok(read) => read.value,
233 Err(e) => {
234 yog_logging::error!("{what} won't read: {e}");
235 T::default()
236 }
237 }
238}
239
240pub fn from_text<T: Schema>(text: &str) -> Result<Read<T>, Errors> {
242 let doc = text::parse(text)?;
243 from_doc(text, &doc)
244}
245
246#[cfg(feature = "toml")]
248pub fn from_toml<T: Schema>(text: &str) -> Result<Read<T>, Errors> {
249 let doc = crate::toml::parse(text)?;
250 from_doc(text, &doc)
251}
252
253pub fn from_doc<T: Schema>(text: &str, doc: &Doc) -> Result<Read<T>, Errors> {
255 locate(text, doc, from_value(&doc.value))
256}
257
258pub fn from_doc_with<T: Schema>(
260 text: &str,
261 doc: &Doc,
262 resolver: &mut dyn Resolve,
263) -> Result<Read<T>, Errors> {
264 locate(text, doc, from_value_with(&doc.value, resolver))
265}
266
267fn locate<T>(
268 text: &str,
269 doc: &Doc,
270 read: Result<Read<T>, Vec<Diagnostic>>,
271) -> Result<Read<T>, Errors> {
272 read.map_err(|problems| {
273 let mut located: Vec<Diagnostic> =
274 problems.into_iter().map(|p| placed(text, doc, p)).collect();
275 located.sort_by_key(|d| (d.line, d.col));
277 Errors(located)
278 })
279}
280
281pub fn placed(text: &str, doc: &Doc, d: Diagnostic) -> Diagnostic {
284 let spans = doc.spans_at(&d.path);
285 let span = match (d.on_key, spans.key) {
286 (true, Some(key)) => key,
287 _ => spans.span,
288 };
289 let at = LineCol::of(text, span.start as usize);
290 d.at(at)
291}
292
293pub fn to_text<T: Schema>(value: &T) -> String {
295 text::to_string_pretty(&value.write())
296}