use super::{
err::{JsonDeserializationError, JsonDeserializationErrorContext},
SchemaType, ValueParser,
};
use crate::ast::{Context, ContextCreationError};
use crate::extensions::Extensions;
use miette::Diagnostic;
use std::collections::BTreeMap;
use thiserror::Error;
pub trait ContextSchema {
fn context_type(&self) -> SchemaType;
}
#[derive(Debug, Clone)]
pub struct NullContextSchema;
impl ContextSchema for NullContextSchema {
fn context_type(&self) -> SchemaType {
SchemaType::Record {
attrs: BTreeMap::new(),
open_attrs: false,
}
}
}
#[derive(Debug, Clone)]
pub struct ContextJsonParser<'e, 's, S = NullContextSchema> {
schema: Option<&'s S>,
extensions: &'e Extensions<'e>,
}
impl<'e, 's, S> ContextJsonParser<'e, 's, S> {
pub fn new(schema: Option<&'s S>, extensions: &'e Extensions<'e>) -> Self {
Self { schema, extensions }
}
}
impl<S: ContextSchema> ContextJsonParser<'_, '_, S> {
pub fn from_json_str(&self, json: &str) -> Result<Context, ContextJsonDeserializationError> {
let val =
serde_json::from_str(json).map_err(|e| JsonDeserializationError::Serde(e.into()))?;
self.from_json_value(val)
}
pub fn from_json_value(
&self,
json: serde_json::Value,
) -> Result<Context, ContextJsonDeserializationError> {
let vparser = ValueParser::new(self.extensions);
let expected_ty = self.schema.map(|s| s.context_type());
let rexpr = vparser.val_into_restricted_expr(json, expected_ty.as_ref(), &|| {
JsonDeserializationErrorContext::Context
})?;
Context::from_expr(rexpr.as_borrowed(), self.extensions)
.map_err(ContextJsonDeserializationError::ContextCreation)
}
pub fn from_json_file(
&self,
json: impl std::io::Read,
) -> Result<Context, ContextJsonDeserializationError> {
let val = serde_json::from_reader(json).map_err(JsonDeserializationError::from)?;
self.from_json_value(val)
}
}
#[derive(Debug, Diagnostic, Error)]
pub enum ContextJsonDeserializationError {
#[error(transparent)]
#[diagnostic(transparent)]
JsonDeserialization(#[from] JsonDeserializationError),
#[error(transparent)]
#[diagnostic(transparent)]
ContextCreation(#[from] ContextCreationError),
}