use std::sync::Arc;
use serde_json::Value as JsonValue;
use sim_codec::{
CodecDefaultDecode, CodecRuntime, DecodeBudget, Decoder, Encoder, Input, LocatedDecoder,
LocatedEncoder, Output, ReadCx, TreeDecoder, TreeEncoder, codec_value, validate_expr_tree,
};
use sim_kernel::{
AbiVersion, DefaultFactory, Dependency, Error, Export, Expr, Lib, LibManifest, LibTarget,
Linker, LocatedExpr, LocatedExprTree, Result, Symbol, Version, WriteCx,
};
use crate::{
expr_to_json, json_to_expr, json_to_located_expr, json_to_tree, located_expr_to_json,
tree_to_json,
};
pub struct JsonCodec;
impl Decoder for JsonCodec {
fn decode(&self, cx: &mut ReadCx<'_>, input: Input) -> Result<Expr> {
let source = input.into_string()?;
let mut budget = DecodeBudget::new(cx.limits);
budget.check_input_bytes(cx.codec, source.len())?;
let value =
serde_json::from_str::<JsonValue>(&source).map_err(|err| Error::CodecError {
codec: cx.codec,
message: err.to_string(),
})?;
json_to_expr(cx.codec, &value, &mut budget, 0)
}
}
impl Encoder for JsonCodec {
fn encode(&self, cx: &mut WriteCx<'_>, expr: &Expr) -> Result<Output> {
let value = expr_to_json(expr);
let text = serde_json::to_string(&value).map_err(|err| Error::CodecError {
codec: cx.codec,
message: err.to_string(),
})?;
Ok(Output::Text(text))
}
}
impl LocatedDecoder for JsonCodec {
fn decode_located(
&self,
cx: &mut ReadCx<'_>,
input: Input,
_source_id: String,
) -> Result<LocatedExpr> {
let source = input.into_string()?;
let mut budget = DecodeBudget::new(cx.limits);
budget.check_input_bytes(cx.codec, source.len())?;
let value =
serde_json::from_str::<JsonValue>(&source).map_err(|err| Error::CodecError {
codec: cx.codec,
message: err.to_string(),
})?;
json_to_located_expr(cx.codec, &value, &mut budget, 0)
}
}
impl LocatedEncoder for JsonCodec {
fn encode_located(&self, cx: &mut WriteCx<'_>, expr: &LocatedExpr) -> Result<Output> {
let value = located_expr_to_json(expr, cx.options.lossless_origin);
let text = serde_json::to_string(&value).map_err(|err| Error::CodecError {
codec: cx.codec,
message: err.to_string(),
})?;
Ok(Output::Text(text))
}
}
impl TreeDecoder for JsonCodec {
fn decode_tree(
&self,
cx: &mut ReadCx<'_>,
input: Input,
_source_id: String,
) -> Result<LocatedExprTree> {
let source = input.into_string()?;
let mut budget = DecodeBudget::new(cx.limits);
budget.check_input_bytes(cx.codec, source.len())?;
let value =
serde_json::from_str::<JsonValue>(&source).map_err(|err| Error::CodecError {
codec: cx.codec,
message: err.to_string(),
})?;
json_to_tree(cx.codec, &value, &mut budget, 0)
}
}
impl TreeEncoder for JsonCodec {
fn encode_tree(&self, cx: &mut WriteCx<'_>, expr: &LocatedExprTree) -> Result<Output> {
validate_expr_tree(cx.codec, expr)?;
let value = tree_to_json(expr, cx.options.lossless_origin);
let text = serde_json::to_string(&value).map_err(|err| Error::CodecError {
codec: cx.codec,
message: err.to_string(),
})?;
Ok(Output::Text(text))
}
}
pub struct JsonCodecLib {
symbol: Symbol,
codec_id: sim_kernel::CodecId,
}
impl JsonCodecLib {
pub fn new(id: sim_kernel::CodecId) -> Self {
Self {
symbol: Symbol::qualified("codec", "json"),
codec_id: id,
}
}
}
impl Lib for JsonCodecLib {
fn manifest(&self) -> LibManifest {
LibManifest {
id: self.symbol.clone(),
version: Version(env!("CARGO_PKG_VERSION").to_owned()),
abi: AbiVersion { major: 0, minor: 1 },
target: LibTarget::HostRegistered,
requires: Vec::<Dependency>::new(),
capabilities: Vec::new(),
exports: vec![Export::Codec {
symbol: self.symbol.clone(),
codec_id: Some(self.codec_id),
}],
}
}
fn load(&self, _cx: &mut sim_kernel::LoadCx, linker: &mut Linker) -> Result<()> {
let _factory = DefaultFactory;
let expr_shape =
sim_codec::resolve_expr_shape(linker, &Symbol::qualified("codec", "JsonTaggedExpr"))?;
let options_shape = sim_codec::resolve_options_shape(linker)?;
linker.codec_value(
self.symbol.clone(),
codec_value(CodecRuntime {
id: self.codec_id,
symbol: self.symbol.clone(),
decoder: Some(Arc::new(JsonCodec)),
located_decoder: Some(Arc::new(JsonCodec)),
tree_decoder: Some(Arc::new(JsonCodec)),
encoder: Some(Arc::new(JsonCodec)),
located_encoder: Some(Arc::new(JsonCodec)),
tree_encoder: Some(Arc::new(JsonCodec)),
expr_shape,
options_shape,
default_decode: CodecDefaultDecode::Datum,
}),
)?;
Ok(())
}
}