substrate_data/schema/convert/
read.rs1use crate::binary::Decoder;
4use crate::diagnostic::{Diagnostic, Errors, Problem};
5use crate::model::borrowed::ValueRef;
6use crate::model::value::Value;
7use crate::schema::{Read, Reader, Resolve, Schema, Shape};
8use crate::text::{self, Doc, LineCol};
9
10#[must_use]
12pub fn field_names(shape: &Shape) -> Vec<&'static str> {
13 match shape {
14 Shape::Struct(s) => s.fields.iter().map(|f| f.name).collect(),
15 _ => Vec::new(),
16 }
17}
18
19pub fn read_both<A: Schema, B: Schema>(
22 v: &ValueRef<'_>,
23 cx: &mut Reader<'_>,
24 also: &[&'static str],
25) -> Option<(A, B)> {
26 let (an, bn) = (field_names(&A::shape()), field_names(&B::shape()));
27 let mut b_keys = bn.clone();
28 b_keys.extend_from_slice(also);
29 let mut a_keys = an;
30 a_keys.extend_from_slice(also);
31 let a = cx.with_allowed_all(&b_keys, |cx| A::read(v, cx));
32 let b = cx.with_allowed_all(&a_keys, |cx| B::read(v, cx));
33 Some((a?, b?))
34}
35
36pub fn from_value<T: Schema>(v: &Value) -> Result<Read<T>, Vec<Diagnostic>> {
42 let arena = bumpalo::Bump::new();
43 read_with(&v.borrow(&arena), Reader::new())
44}
45
46pub fn read_value<T: Schema>(v: &Value) -> Result<T, Vec<Diagnostic>> {
53 let arena = bumpalo::Bump::new();
54 read_ref_value(&v.borrow(&arena))
55}
56
57pub fn read_ref_value<T: Schema>(v: &ValueRef<'_>) -> Result<T, Vec<Diagnostic>> {
63 let reader = Reader {
64 value_only: true,
65 ..Reader::new()
66 };
67 read_with(v, reader).map(|r| r.value)
68}
69
70pub fn read_bytes<T: Schema>(bytes: &[u8]) -> Result<T, Vec<Diagnostic>> {
77 if let Ok(mut d) = Decoder::open(bytes)
79 && let Some(v) = T::decode(&mut d)
80 && d.at_end()
81 {
82 return Ok(v);
83 }
84 let arena = bumpalo::Bump::new();
85 let v = crate::binary::decode_ref(bytes, &arena)
86 .map_err(|e| vec![Diagnostic::error(Problem::BadBinary, e)])?;
87 read_ref_value(&v)
88}
89
90pub fn from_bytes_with<T: Schema>(
99 bytes: &[u8],
100 resolver: &mut dyn Resolve,
101) -> Result<Read<T>, Vec<Diagnostic>> {
102 let arena = bumpalo::Bump::new();
103 let v = crate::binary::decode_ref(bytes, &arena)
104 .map_err(|e| vec![Diagnostic::error(Problem::BadBinary, e)])?;
105 read_with(&v, Reader::with_resolver(resolver))
106}
107
108pub fn from_value_with<T: Schema>(
114 v: &Value,
115 resolver: &mut dyn Resolve,
116) -> Result<Read<T>, Vec<Diagnostic>> {
117 let arena = bumpalo::Bump::new();
118 read_with(&v.borrow(&arena), Reader::with_resolver(resolver))
119}
120
121fn read_with<T: Schema>(v: &ValueRef<'_>, mut cx: Reader<'_>) -> Result<Read<T>, Vec<Diagnostic>> {
122 let value = T::read(v, &mut cx);
123 match value {
124 Some(value) if cx.problems.is_empty() => Ok(Read {
125 value,
126 refs: cx.refs,
127 }),
128 _ => Err(cx.problems),
129 }
130}
131
132pub fn from_text<T: Schema>(text: &str) -> Result<Read<T>, Errors> {
138 let arena = bumpalo::Bump::new();
142 let v = text::parse_ref(text, &arena)?;
143 if let Ok(read) = read_with(&v, Reader::new()) {
144 return Ok(read);
145 }
146 let doc = text::parse(text)?;
147 from_doc(text, &doc)
148}
149
150#[cfg(feature = "toml")]
156pub fn from_toml<T: Schema>(text: &str) -> Result<Read<T>, Errors> {
157 let doc = crate::toml::parse(text)?;
158 from_doc(text, &doc)
159}
160
161pub fn from_doc<T: Schema>(text: &str, doc: &Doc) -> Result<Read<T>, Errors> {
167 locate(text, doc, from_value(&doc.value))
168}
169
170pub fn from_doc_with<T: Schema>(
176 text: &str,
177 doc: &Doc,
178 resolver: &mut dyn Resolve,
179) -> Result<Read<T>, Errors> {
180 locate(text, doc, from_value_with(&doc.value, resolver))
181}
182
183fn locate<T>(
184 text: &str,
185 doc: &Doc,
186 read: Result<Read<T>, Vec<Diagnostic>>,
187) -> Result<Read<T>, Errors> {
188 read.map_err(|problems| {
189 let mut located: Vec<Diagnostic> =
190 problems.into_iter().map(|p| placed(text, doc, p)).collect();
191 located.sort_by_key(|d| (d.line, d.col));
193 Errors(located)
194 })
195}
196
197pub fn placed(text: &str, doc: &Doc, d: Diagnostic) -> Diagnostic {
200 let spans = doc.spans_at(&d.path);
201 let span = match (d.on_key, spans.key) {
202 (true, Some(key)) => key,
203 _ => spans.span,
204 };
205 let at = LineCol::of(text, span.start as usize);
206 d.at(at)
207}