haem_frames/embedding/
codec.rs1use std::fmt;
2use std::io::{Read, Write};
3use std::marker::PhantomData;
4use std::num::NonZeroU32;
5
6use serde::{
7 Deserialize, Deserializer, Serialize,
8 de::{DeserializeOwned, MapAccess, SeqAccess, Visitor, value::MapAccessDeserializer},
9};
10
11use super::{
12 Embed, Error, FAILED_MESSAGE_CHARS, Failed, FailedCode, MINIMUM_FRAME_BYTES, Ready, Start, Tag,
13 Vectors, check_ready, check_start,
14};
15
16struct Object<T>(T);
17
18impl<'de, T: Deserialize<'de>> Deserialize<'de> for Object<T> {
19 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
20 object(deserializer).map(Self)
21 }
22}
23
24pub(super) fn object<'de, D: Deserializer<'de>, T: Deserialize<'de>>(
25 deserializer: D,
26) -> Result<T, D::Error> {
27 struct ObjectVisitor<T>(PhantomData<T>);
28 impl<'de, T: Deserialize<'de>> Visitor<'de> for ObjectVisitor<T> {
29 type Value = T;
30 fn expecting(&self, output: &mut fmt::Formatter<'_>) -> fmt::Result {
31 output.write_str("a JSON object")
32 }
33 fn visit_map<M: MapAccess<'de>>(self, map: M) -> Result<T, M::Error> {
34 T::deserialize(MapAccessDeserializer::new(map))
35 }
36 }
37 deserializer.deserialize_map(ObjectVisitor(PhantomData))
38}
39
40pub(super) fn objects<'de, D: Deserializer<'de>, T: Deserialize<'de>>(
41 deserializer: D,
42) -> Result<Vec<T>, D::Error> {
43 struct Objects<T>(PhantomData<T>);
44 impl<'de, T: Deserialize<'de>> Visitor<'de> for Objects<T> {
45 type Value = Vec<T>;
46 fn expecting(&self, output: &mut fmt::Formatter<'_>) -> fmt::Result {
47 output.write_str("an array of JSON objects")
48 }
49 fn visit_seq<S: SeqAccess<'de>>(self, mut sequence: S) -> Result<Vec<T>, S::Error> {
50 let mut items = Vec::new();
51 while let Some(Object(item)) = sequence.next_element::<Object<T>>()? {
52 items.push(item);
53 }
54 Ok(items)
55 }
56 }
57 deserializer.deserialize_seq(Objects(PhantomData))
58}
59
60#[derive(Debug)]
61pub enum Message {
62 Start(Start),
63 Ready(Ready),
64 Embed(Embed),
65 Vectors(Vectors),
66 Failed(Failed),
67}
68
69impl Message {
70 #[must_use]
71 pub const fn tag(&self) -> Tag {
72 match self {
73 Self::Start(_) => Tag::Start,
74 Self::Ready(_) => Tag::Ready,
75 Self::Embed(_) => Tag::Embed,
76 Self::Vectors(_) => Tag::Vectors,
77 Self::Failed(_) => Tag::Failed,
78 }
79 }
80}
81
82fn protocol(error: impl fmt::Display) -> Error {
83 Error::new(FailedCode::EmbedProtocol, error.to_string())
84}
85
86fn parse<T: DeserializeOwned>(payload: &[u8]) -> Result<T, Error> {
87 let mut deserializer = serde_json::Deserializer::from_slice(payload);
88 let value = object(&mut deserializer).map_err(protocol)?;
89 deserializer.end().map_err(protocol)?;
90 Ok(value)
91}
92
93fn check_failed(failed: &Failed) -> Result<(), Error> {
94 if failed.message.chars().count() > FAILED_MESSAGE_CHARS {
95 return Err(protocol("Failed message exceeds 1024 characters"));
96 }
97 Ok(())
98}
99
100pub fn decode_message(tag: u8, payload: &[u8]) -> Result<Message, Error> {
107 match Tag::try_from(tag)? {
108 Tag::Start => {
109 if payload
110 .len()
111 .checked_add(1)
112 .is_none_or(|size| size > MINIMUM_FRAME_BYTES as usize)
113 {
114 return Err(protocol("Start frame exceeds its fixed limit"));
115 }
116 let start = parse(payload)?;
117 check_start(&start)?;
118 Ok(Message::Start(start))
119 }
120 Tag::Ready => {
121 let ready = parse(payload)?;
122 check_ready(&ready)?;
123 Ok(Message::Ready(ready))
124 }
125 Tag::Embed => parse(payload).map(Message::Embed),
126 Tag::Vectors => parse(payload).map(Message::Vectors),
127 Tag::Failed => {
128 let failed = parse(payload)?;
129 check_failed(&failed)?;
130 Ok(Message::Failed(failed))
131 }
132 }
133}
134
135pub fn read_message(input: &mut impl Read, limit: NonZeroU32) -> Result<Option<Message>, Error> {
141 let Some(frame) = crate::frame::read(input, limit).map_err(protocol)? else {
142 return Ok(None);
143 };
144 let (tag, payload) = frame
145 .split_first()
146 .ok_or_else(|| protocol("frame has no tag"))?;
147 decode_message(*tag, payload).map(Some)
148}
149
150pub fn read_start(input: &mut impl Read) -> Result<Option<Start>, Error> {
156 let limit = NonZeroU32::new(MINIMUM_FRAME_BYTES)
157 .ok_or_else(|| protocol("fixed frame limit is zero"))?;
158 match read_message(input, limit)? {
159 Some(Message::Start(start)) => Ok(Some(start)),
160 None => Ok(None),
161 Some(_) => Err(protocol("first embedding frame must be Start")),
162 }
163}
164
165fn payload(value: &impl Serialize) -> Result<Vec<u8>, Error> {
166 serde_json::to_vec(value).map_err(protocol)
167}
168
169pub fn write_message(
175 output: &mut impl Write,
176 message: &Message,
177 limit: NonZeroU32,
178) -> Result<(), Error> {
179 let bytes = match message {
180 Message::Start(start) => {
181 check_start(start)?;
182 payload(start)?
183 }
184 Message::Ready(ready) => {
185 check_ready(ready)?;
186 payload(ready)?
187 }
188 Message::Embed(embed) => payload(embed)?,
189 Message::Vectors(vectors) => payload(vectors)?,
190 Message::Failed(failed) => {
191 check_failed(failed)?;
192 payload(failed)?
193 }
194 };
195 let limit = if matches!(message, Message::Start(_)) {
196 limit.min(
197 NonZeroU32::new(MINIMUM_FRAME_BYTES)
198 .ok_or_else(|| protocol("fixed frame limit is zero"))?,
199 )
200 } else {
201 limit
202 };
203 crate::frame::write(output, message.tag() as u8, &bytes, limit).map_err(protocol)
204}