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