1use std::sync::Arc;
7
8use sim_codec::{
9 CodecDefaultDecode, CodecRuntime, Decoder, Encoder, Input, LocatedDecoder, LocatedEncoder,
10 Output, ReadCx, TreeDecoder, TreeEncoder, codec_value, validate_expr_tree,
11};
12use sim_kernel::{
13 AbiVersion, DefaultFactory, Dependency, Error, Export, Expr, Lib, LibManifest, LibTarget,
14 Linker, LocatedExpr, LocatedExprTree, Result, Symbol, Version, WriteCx,
15};
16
17use crate::reader::BinaryReader;
18use crate::writer::BinaryWriter;
19use crate::{BinaryFrame, DecodeLimits, FLAG_NONE, FLAG_ORIGIN, FLAG_TREE_ORIGIN, FrameTables};
20
21pub struct BinaryCodec;
31
32impl Decoder for BinaryCodec {
33 fn decode(&self, cx: &mut ReadCx<'_>, input: Input) -> Result<Expr> {
34 let bytes = match input {
35 Input::Text(text) => text.into_bytes(),
36 Input::Bytes(bytes) => bytes,
37 };
38 decode_located_tree_frame_with_limits(cx.codec, &bytes, DecodeLimits::from(cx.limits))
39 .map(|(_, tree)| tree.located().expr)
40 }
41}
42
43impl Encoder for BinaryCodec {
44 fn encode(&self, _cx: &mut WriteCx<'_>, expr: &Expr) -> Result<Output> {
45 Ok(Output::Bytes(encode_frame(expr)?.0))
46 }
47}
48
49impl LocatedDecoder for BinaryCodec {
50 fn decode_located(
51 &self,
52 cx: &mut ReadCx<'_>,
53 input: Input,
54 _source_id: String,
55 ) -> Result<LocatedExpr> {
56 let bytes = match input {
57 Input::Text(text) => text.into_bytes(),
58 Input::Bytes(bytes) => bytes,
59 };
60 decode_located_tree_frame_with_limits(cx.codec, &bytes, DecodeLimits::from(cx.limits))
61 .map(|(_, tree)| tree.located())
62 }
63}
64
65impl LocatedEncoder for BinaryCodec {
66 fn encode_located(&self, cx: &mut WriteCx<'_>, expr: &LocatedExpr) -> Result<Output> {
67 Ok(Output::Bytes(
68 encode_located_frame(expr, cx.options.lossless_origin)?.0,
69 ))
70 }
71}
72
73impl TreeDecoder for BinaryCodec {
74 fn decode_tree(
75 &self,
76 cx: &mut ReadCx<'_>,
77 input: Input,
78 _source_id: String,
79 ) -> Result<LocatedExprTree> {
80 let bytes = match input {
81 Input::Text(text) => text.into_bytes(),
82 Input::Bytes(bytes) => bytes,
83 };
84 decode_located_tree_frame_with_limits(cx.codec, &bytes, DecodeLimits::from(cx.limits))
85 .map(|(_, tree)| tree)
86 }
87}
88
89impl TreeEncoder for BinaryCodec {
90 fn encode_tree(&self, cx: &mut WriteCx<'_>, expr: &LocatedExprTree) -> Result<Output> {
91 validate_expr_tree(cx.codec, expr)?;
92 Ok(Output::Bytes(
93 encode_located_tree_frame(expr, cx.options.lossless_origin)?.0,
94 ))
95 }
96}
97
98pub fn encode_frame(expr: &Expr) -> Result<BinaryFrame> {
100 encode_located_frame(
101 &LocatedExpr {
102 expr: expr.clone(),
103 origin: None,
104 },
105 false,
106 )
107}
108
109pub fn encode_located_frame(located: &LocatedExpr, include_origin: bool) -> Result<BinaryFrame> {
114 let tables = FrameTables::collect(&located.expr);
115 let mut writer = BinaryWriter::new(tables)?;
116 writer.flags = if include_origin && located.origin.is_some() {
117 FLAG_ORIGIN
118 } else {
119 FLAG_NONE
120 };
121 writer.write_header()?;
122 writer.write_expr(&located.expr)?;
123 if writer.flags & FLAG_ORIGIN != 0 {
124 writer.write_origin(
125 located
126 .origin
127 .as_ref()
128 .expect("origin flag requires origin payload"),
129 )?;
130 }
131 Ok(BinaryFrame(writer.bytes))
132}
133
134pub fn encode_located_tree_frame(
140 tree: &LocatedExprTree,
141 include_origin: bool,
142) -> Result<BinaryFrame> {
143 validate_expr_tree(sim_kernel::CodecId(0), tree)?;
144 let tables = FrameTables::collect(&tree.expr);
145 let mut writer = BinaryWriter::new(tables)?;
146 writer.flags = if include_origin {
147 FLAG_TREE_ORIGIN
148 } else {
149 FLAG_NONE
150 };
151 writer.write_header()?;
152 writer.write_expr(&tree.expr)?;
153 if writer.flags & FLAG_TREE_ORIGIN != 0 {
154 writer.write_origin_tree(tree)?;
155 }
156 Ok(BinaryFrame(writer.bytes))
157}
158
159pub fn decode_frame(codec: sim_kernel::CodecId, bytes: &[u8]) -> Result<(FrameTables, Expr)> {
164 let located = decode_located_frame(codec, bytes)?;
165 Ok((located.0, located.1.expr))
166}
167
168pub fn decode_located_frame(
173 codec: sim_kernel::CodecId,
174 bytes: &[u8],
175) -> Result<(FrameTables, LocatedExpr)> {
176 let (tables, tree) = decode_located_tree_frame(codec, bytes)?;
177 Ok((tables, tree.located()))
178}
179
180pub fn decode_located_tree_frame(
187 codec: sim_kernel::CodecId,
188 bytes: &[u8],
189) -> Result<(FrameTables, LocatedExprTree)> {
190 decode_located_tree_frame_with_limits(codec, bytes, DecodeLimits::default())
191}
192
193pub fn decode_located_tree_frame_with_limits(
200 codec: sim_kernel::CodecId,
201 bytes: &[u8],
202 limits: DecodeLimits,
203) -> Result<(FrameTables, LocatedExprTree)> {
204 let mut reader = BinaryReader::new(codec, bytes, limits)?;
205 let tables = reader.read_header()?;
206 let expr = reader.read_expr()?;
207 let mut tree = if reader.flags & FLAG_TREE_ORIGIN != 0 {
208 reader.read_origin_tree(expr)?
209 } else {
210 LocatedExprTree::from_expr_recursive(expr)
211 };
212 if reader.flags & FLAG_ORIGIN != 0 {
213 tree.origin = Some(reader.read_origin()?);
214 }
215 if !reader.is_empty() {
216 return Err(Error::CodecError {
217 codec,
218 message: "trailing bytes after binary payload".to_owned(),
219 });
220 }
221 Ok((tables, tree))
222}
223
224pub struct BinaryCodecLib {
230 symbol: Symbol,
231 codec_id: sim_kernel::CodecId,
232}
233
234impl BinaryCodecLib {
235 pub fn new(id: sim_kernel::CodecId) -> Self {
238 Self {
239 symbol: Symbol::qualified("codec", "binary"),
240 codec_id: id,
241 }
242 }
243}
244
245impl Lib for BinaryCodecLib {
246 fn manifest(&self) -> LibManifest {
247 LibManifest {
248 id: self.symbol.clone(),
249 version: Version(env!("CARGO_PKG_VERSION").to_owned()),
250 abi: AbiVersion { major: 0, minor: 1 },
251 target: LibTarget::HostRegistered,
252 requires: Vec::<Dependency>::new(),
253 capabilities: Vec::new(),
254 exports: vec![Export::Codec {
255 symbol: self.symbol.clone(),
256 codec_id: Some(self.codec_id),
257 }],
258 }
259 }
260
261 fn load(&self, _cx: &mut sim_kernel::LoadCx, linker: &mut Linker) -> Result<()> {
262 let _factory = DefaultFactory;
263 let expr_shape =
264 sim_codec::resolve_expr_shape(linker, &Symbol::qualified("codec", "BinaryFrame"))?;
265 let options_shape = sim_codec::resolve_options_shape(linker)?;
266
267 linker.codec_value(
268 self.symbol.clone(),
269 codec_value(CodecRuntime {
270 id: self.codec_id,
271 symbol: self.symbol.clone(),
272 decoder: Some(Arc::new(BinaryCodec)),
273 located_decoder: Some(Arc::new(BinaryCodec)),
274 tree_decoder: Some(Arc::new(BinaryCodec)),
275 encoder: Some(Arc::new(BinaryCodec)),
276 located_encoder: Some(Arc::new(BinaryCodec)),
277 tree_encoder: Some(Arc::new(BinaryCodec)),
278 expr_shape,
279 options_shape,
280 default_decode: CodecDefaultDecode::Datum,
281 }),
282 )?;
283 Ok(())
284 }
285}