1use std::any::{Any, TypeId};
5use std::collections::HashMap;
6use std::default::Default;
7use std::fmt;
8
9use crate::ast::{BuiltinType, Literal, SpannedNode, Value};
10use crate::errors::{DecodeError, ExpectedType};
11use crate::traits::{Decode, ErrorSpan};
12
13#[derive(Debug, Default)]
18pub struct Context<S: ErrorSpan> {
19 errors: Vec<DecodeError<S>>,
20 extensions: HashMap<TypeId, Box<dyn Any>>,
21}
22
23#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
27pub enum Kind {
28 Int,
32 Decimal,
36 String,
38 Bool,
40 #[default]
42 Null,
43 Nan,
45 Inf,
47 NegInf,
49}
50
51pub fn bytes<S: ErrorSpan>(value: &Value<S>, ctx: &mut Context<S>) -> Vec<u8> {
56 if let Some(typ) = &value.type_name {
57 match typ.as_builtin() {
58 Some(&BuiltinType::Base64) => {
59 #[cfg(feature = "base64")]
60 {
61 use base64::{engine::general_purpose::STANDARD, Engine};
62 match &*value.literal {
63 Literal::String(s) => match STANDARD.decode(s.as_bytes()) {
64 Ok(vec) => vec,
65 Err(e) => {
66 ctx.emit_error(DecodeError::conversion(&value.literal, e));
67 Default::default()
68 }
69 },
70 _ => {
71 ctx.emit_error(DecodeError::scalar_kind(Kind::String, &value.literal));
72 Default::default()
73 }
74 }
75 }
76 #[cfg(not(feature = "base64"))]
77 {
78 ctx.emit_error(DecodeError::unsupported(
79 &value.literal,
80 "base64 support is not compiled in",
81 ));
82 Default::default()
83 }
84 }
85 _ => {
86 ctx.emit_error(DecodeError::TypeName {
87 span: typ.span().clone(),
88 found: Some(typ.value.clone()),
89 expected: ExpectedType::optional(BuiltinType::Base64),
90 rust_type: "bytes",
91 });
92 Default::default()
93 }
94 }
95 } else {
96 match &*value.literal {
97 Literal::String(s) => s.as_bytes().to_vec(),
98 _ => {
99 ctx.emit_error(DecodeError::scalar_kind(Kind::String, &value.literal));
100 Default::default()
101 }
102 }
103 }
104}
105
106pub fn check_flag_node<S: ErrorSpan>(node: &SpannedNode<S>, ctx: &mut Context<S>) {
113 for arg in &node.arguments {
114 ctx.emit_error(DecodeError::unexpected(
115 &arg.literal,
116 "argument",
117 "unexpected argument",
118 ));
119 }
120 for name in node.properties.keys() {
121 ctx.emit_error(DecodeError::unexpected(
122 name,
123 "property",
124 format!("unexpected property `{}`", name.escape_default()),
125 ));
126 }
127 if let Some(children) = &node.children {
128 for child in children.iter() {
129 ctx.emit_error(DecodeError::unexpected(
130 child,
131 "node",
132 format!("unexpected node `{}`", child.node_name.escape_default()),
133 ));
134 }
135 }
136}
137
138pub fn node<T, S>(ast: &SpannedNode<S>) -> Result<T, Vec<DecodeError<S>>>
140where
141 T: Decode<S>,
142 S: ErrorSpan,
143{
144 let mut ctx = Context::new();
145 match Decode::decode_node(ast, &mut ctx) {
146 Ok(_) if ctx.has_errors() => Err(ctx.into_errors()),
147 Err(e) => {
148 ctx.emit_error(e);
149 Err(ctx.into_errors())
150 }
151 Ok(v) => Ok(v),
152 }
153}
154
155impl<S: ErrorSpan> Context<S> {
156 pub(crate) fn new() -> Context<S> {
157 Context {
158 errors: Vec::new(),
159 extensions: HashMap::new(),
160 }
161 }
162 pub fn emit_error(&mut self, err: impl Into<DecodeError<S>>) {
168 self.errors.push(err.into());
169 }
170 pub fn has_errors(&self) -> bool {
172 !self.errors.is_empty()
173 }
174 pub(crate) fn into_errors(self) -> Vec<DecodeError<S>> {
175 self.errors
176 }
177 pub fn set<T: 'static>(&mut self, value: T) {
189 self.extensions.insert(TypeId::of::<T>(), Box::new(value));
190 }
191 pub fn get<T: 'static>(&self) -> Option<&T> {
195 self.extensions
196 .get(&TypeId::of::<T>())
197 .and_then(|b| b.downcast_ref())
198 }
199}
200
201impl fmt::Display for Kind {
202 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203 f.write_str(self.as_str())
204 }
205}
206
207impl From<&'_ Literal> for Kind {
208 fn from(lit: &Literal) -> Kind {
209 use Kind as K;
210 use Literal as L;
211 match lit {
212 L::Int(_) => K::Int,
213 L::Decimal(_) => K::Decimal,
214 L::String(_) => K::String,
215 L::Bool(_) => K::Bool,
216 L::Null => K::Null,
217 L::Nan => K::Nan,
218 L::Inf => K::Inf,
219 L::NegInf => K::NegInf,
220 }
221 }
222}
223
224impl Kind {
225 pub const fn as_str(&self) -> &'static str {
229 use Kind::*;
230 match self {
231 Int => "integer",
232 Decimal => "decimal",
233 String => "string",
234 Bool => "boolean",
235 Null => "null",
236 Nan => "nan",
237 Inf => "inf",
238 NegInf => "-inf",
239 }
240 }
241}