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, Dependency, Export, Expr, Lib, LibManifest, LibTarget, Linker, LocatedExpr,
14 LocatedExprTree, Result, Symbol, Version, WriteCx,
15};
16
17use crate::reader::FrameReader;
18use crate::types::{FLAG_DENSE, FLAG_NONE, FLAG_ORIGIN, FLAG_TREE_ORIGIN};
19use crate::writer::FrameWriter;
20use crate::{BitwiseFrame, DecodeLimits, FrameTables};
21
22pub struct BitwiseCodec;
33
34impl Decoder for BitwiseCodec {
35 fn decode(&self, cx: &mut ReadCx<'_>, input: Input) -> Result<Expr> {
36 let bytes = input_bytes(input);
37 decode_located_tree_frame_with_limits(cx.codec, &bytes, DecodeLimits::from(cx.limits))
38 .map(|(_, tree)| tree.located().expr)
39 }
40}
41
42impl Encoder for BitwiseCodec {
43 fn encode(&self, _cx: &mut WriteCx<'_>, expr: &Expr) -> Result<Output> {
44 Ok(Output::Bytes(encode_frame(expr)?.0))
45 }
46}
47
48impl LocatedDecoder for BitwiseCodec {
49 fn decode_located(
50 &self,
51 cx: &mut ReadCx<'_>,
52 input: Input,
53 _source_id: String,
54 ) -> Result<LocatedExpr> {
55 let bytes = input_bytes(input);
56 decode_located_tree_frame_with_limits(cx.codec, &bytes, DecodeLimits::from(cx.limits))
57 .map(|(_, tree)| tree.located())
58 }
59}
60
61impl LocatedEncoder for BitwiseCodec {
62 fn encode_located(&self, cx: &mut WriteCx<'_>, expr: &LocatedExpr) -> Result<Output> {
63 Ok(Output::Bytes(
64 encode_located_frame(expr, cx.options.lossless_origin)?.0,
65 ))
66 }
67}
68
69impl TreeDecoder for BitwiseCodec {
70 fn decode_tree(
71 &self,
72 cx: &mut ReadCx<'_>,
73 input: Input,
74 _source_id: String,
75 ) -> Result<LocatedExprTree> {
76 let bytes = input_bytes(input);
77 decode_located_tree_frame_with_limits(cx.codec, &bytes, DecodeLimits::from(cx.limits))
78 .map(|(_, tree)| tree)
79 }
80}
81
82impl TreeEncoder for BitwiseCodec {
83 fn encode_tree(&self, cx: &mut WriteCx<'_>, expr: &LocatedExprTree) -> Result<Output> {
84 validate_expr_tree(cx.codec, expr)?;
85 Ok(Output::Bytes(
86 encode_located_tree_frame(expr, cx.options.lossless_origin)?.0,
87 ))
88 }
89}
90
91fn input_bytes(input: Input) -> Vec<u8> {
92 match input {
93 Input::Text(text) => text.into_bytes(),
94 Input::Bytes(bytes) => bytes,
95 }
96}
97
98pub fn encode_frame(expr: &Expr) -> Result<BitwiseFrame> {
103 encode_located_frame(
104 &LocatedExpr {
105 expr: expr.clone(),
106 origin: None,
107 },
108 false,
109 )
110}
111
112pub fn encode_dense(expr: &Expr) -> Result<BitwiseFrame> {
121 let tables = FrameTables::collect(expr);
122 let mut writer = FrameWriter::new(tables);
123 writer.flags = FLAG_DENSE;
124 writer.set_dense(true);
125 writer.write_header()?;
126 writer.write_expr(expr)?;
127 Ok(BitwiseFrame(writer.finish()))
128}
129
130pub fn encode_located_frame(located: &LocatedExpr, include_origin: bool) -> Result<BitwiseFrame> {
135 let tables = FrameTables::collect(&located.expr);
136 let mut writer = FrameWriter::new(tables);
137 writer.flags = if include_origin && located.origin.is_some() {
138 FLAG_ORIGIN
139 } else {
140 FLAG_NONE
141 };
142 writer.write_header()?;
143 writer.write_expr(&located.expr)?;
144 if writer.flags & FLAG_ORIGIN != 0 {
145 writer.write_origin(
146 located
147 .origin
148 .as_ref()
149 .expect("origin flag requires origin payload"),
150 )?;
151 }
152 Ok(BitwiseFrame(writer.finish()))
153}
154
155pub fn encode_located_tree_frame(
161 tree: &LocatedExprTree,
162 include_origin: bool,
163) -> Result<BitwiseFrame> {
164 validate_expr_tree(sim_kernel::CodecId(0), tree)?;
165 let tables = FrameTables::collect(&tree.expr);
166 let mut writer = FrameWriter::new(tables);
167 writer.flags = if include_origin {
168 FLAG_TREE_ORIGIN
169 } else {
170 FLAG_NONE
171 };
172 writer.write_header()?;
173 writer.write_expr(&tree.expr)?;
174 if writer.flags & FLAG_TREE_ORIGIN != 0 {
175 writer.write_origin_tree(tree)?;
176 }
177 Ok(BitwiseFrame(writer.finish()))
178}
179
180pub fn decode_frame(codec: sim_kernel::CodecId, bytes: &[u8]) -> Result<(FrameTables, Expr)> {
185 let (tables, tree) = decode_located_tree_frame(codec, bytes)?;
186 Ok((tables, tree.located().expr))
187}
188
189pub fn decode_located_frame(
194 codec: sim_kernel::CodecId,
195 bytes: &[u8],
196) -> Result<(FrameTables, LocatedExpr)> {
197 let (tables, tree) = decode_located_tree_frame(codec, bytes)?;
198 Ok((tables, tree.located()))
199}
200
201pub fn decode_located_tree_frame(
204 codec: sim_kernel::CodecId,
205 bytes: &[u8],
206) -> Result<(FrameTables, LocatedExprTree)> {
207 decode_located_tree_frame_with_limits(codec, bytes, DecodeLimits::default())
208}
209
210pub fn decode_located_tree_frame_with_limits(
218 codec: sim_kernel::CodecId,
219 bytes: &[u8],
220 limits: DecodeLimits,
221) -> Result<(FrameTables, LocatedExprTree)> {
222 let mut reader = FrameReader::new(codec, bytes, limits)?;
223 let tables = reader.read_header()?;
224 let expr = reader.read_expr()?;
225 let mut tree = if reader.flags & FLAG_TREE_ORIGIN != 0 {
226 reader.read_origin_tree(expr)?
227 } else {
228 LocatedExprTree::from_expr_recursive(expr)
229 };
230 if reader.flags & FLAG_ORIGIN != 0 {
231 tree.origin = Some(reader.read_origin()?);
232 }
233 reader.require_zero_padding()?;
234 Ok((tables, tree))
235}
236
237pub struct BitwiseCodecLib {
243 symbol: Symbol,
244 codec_id: sim_kernel::CodecId,
245}
246
247impl BitwiseCodecLib {
248 pub fn new(id: sim_kernel::CodecId) -> Self {
251 Self {
252 symbol: Symbol::qualified("codec", "bitwise"),
253 codec_id: id,
254 }
255 }
256}
257
258impl Lib for BitwiseCodecLib {
259 fn manifest(&self) -> LibManifest {
260 LibManifest {
261 id: self.symbol.clone(),
262 version: Version(env!("CARGO_PKG_VERSION").to_owned()),
263 abi: AbiVersion { major: 0, minor: 1 },
264 target: LibTarget::HostRegistered,
265 requires: Vec::<Dependency>::new(),
266 capabilities: Vec::new(),
267 exports: vec![Export::Codec {
268 symbol: self.symbol.clone(),
269 codec_id: Some(self.codec_id),
270 }],
271 }
272 }
273
274 fn load(&self, _cx: &mut sim_kernel::LoadCx, linker: &mut Linker) -> Result<()> {
275 let expr_shape =
276 sim_codec::resolve_expr_shape(linker, &Symbol::qualified("codec", "BitwiseFrame"))?;
277 let options_shape = sim_codec::resolve_options_shape(linker)?;
278
279 linker.codec_value(
280 self.symbol.clone(),
281 codec_value(CodecRuntime {
282 id: self.codec_id,
283 symbol: self.symbol.clone(),
284 decoder: Some(Arc::new(BitwiseCodec)),
285 located_decoder: Some(Arc::new(BitwiseCodec)),
286 tree_decoder: Some(Arc::new(BitwiseCodec)),
287 encoder: Some(Arc::new(BitwiseCodec)),
288 located_encoder: Some(Arc::new(BitwiseCodec)),
289 tree_encoder: Some(Arc::new(BitwiseCodec)),
290 expr_shape,
291 options_shape,
292 default_decode: CodecDefaultDecode::Datum,
293 }),
294 )?;
295 Ok(())
296 }
297}