sim_codec_chat/
canonical.rs1use std::sync::Arc;
6
7use sim_codec::{
8 DecodeBudget, Decoder, DomainCodecLib, Encoder, Input, Output, ReadCx, domain_input_text,
9};
10use sim_kernel::{CodecId, Export, Lib, LibManifest, Linker, LoadCx, Result, Symbol, WriteCx};
11
12use crate::cookbook::{
13 ChatProviderProfilesReport, ChatTranscriptRoundtripReport, provider_profiles_symbol,
14 transcript_roundtrip_symbol,
15};
16use crate::{
17 expr::{decode_chat_text, encode_chat_text},
18 validate_chat_transcript,
19};
20
21pub struct ChatCodec;
23
24impl Decoder for ChatCodec {
25 fn decode(&self, cx: &mut ReadCx<'_>, input: Input) -> Result<sim_kernel::Expr> {
26 let source = domain_input_text(cx.codec, input)?;
27 let mut budget = DecodeBudget::new(cx.limits);
28 budget.check_input_bytes(cx.codec, source.len())?;
29 let expr = decode_chat_text(cx.codec, &source, &mut budget)?;
30 validate_chat_transcript(&expr)?;
31 Ok(expr)
32 }
33}
34
35impl Encoder for ChatCodec {
36 fn encode(&self, _cx: &mut WriteCx<'_>, expr: &sim_kernel::Expr) -> Result<Output> {
37 validate_chat_transcript(expr)?;
38 Ok(Output::Text(encode_chat_text(expr)))
39 }
40}
41
42pub struct ChatCodecLib {
45 symbol: Symbol,
46 codec_id: CodecId,
47}
48
49impl ChatCodecLib {
50 pub fn new(id: CodecId) -> Self {
52 Self {
53 symbol: Symbol::qualified("codec", "chat"),
54 codec_id: id,
55 }
56 }
57
58 fn domain_lib(&self) -> DomainCodecLib {
59 DomainCodecLib::new(
60 self.symbol.clone(),
61 self.codec_id,
62 Arc::new(ChatCodec),
63 Arc::new(ChatCodec),
64 Symbol::qualified("codec", "ChatTranscript"),
65 )
66 }
67}
68
69impl Lib for ChatCodecLib {
70 fn manifest(&self) -> LibManifest {
71 let mut manifest = self.domain_lib().manifest();
72 manifest.exports.extend([
73 Export::Function {
74 symbol: transcript_roundtrip_symbol(),
75 function_id: None,
76 },
77 Export::Function {
78 symbol: provider_profiles_symbol(),
79 function_id: None,
80 },
81 ]);
82 manifest
83 }
84
85 fn load(&self, cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
86 self.domain_lib().load(cx, linker)?;
87 linker.function_value(
88 transcript_roundtrip_symbol(),
89 cx.factory()
90 .opaque(Arc::new(ChatTranscriptRoundtripReport))?,
91 )?;
92 linker.function_value(
93 provider_profiles_symbol(),
94 cx.factory().opaque(Arc::new(ChatProviderProfilesReport))?,
95 )?;
96 Ok(())
97 }
98}