haem_frames/embedding/
vector.rs1use super::{Error, FailedCode};
2
3const DIGITS: &[u8; 16] = b"0123456789abcdef";
4
5pub fn encode_vector(vector: &[f32]) -> Result<String, Error> {
6 let capacity = vector
7 .len()
8 .checked_mul(8)
9 .ok_or_else(|| Error::new(FailedCode::EmbedLimits, "vector text length overflows"))?;
10 let mut text = String::with_capacity(capacity);
11 for member in vector {
12 if !member.is_finite() {
13 return Err(Error::new(
14 FailedCode::EmbedOutputInvalid,
15 "vector member is not finite",
16 ));
17 }
18 for byte in member.to_le_bytes() {
19 text.push(char::from(DIGITS[usize::from(byte >> 4)]));
20 text.push(char::from(DIGITS[usize::from(byte & 15)]));
21 }
22 }
23 Ok(text)
24}
25
26fn nibble(byte: u8) -> Result<u8, Error> {
27 match byte {
28 b'0'..=b'9' => Ok(byte - b'0'),
29 b'a'..=b'f' => Ok(byte - b'a' + 10),
30 _ => Err(Error::new(
31 FailedCode::EmbedProtocol,
32 "vector text must contain only lowercase hexadecimal",
33 )),
34 }
35}
36
37pub fn decode_vector(text: &str) -> Result<Vec<f32>, Error> {
38 let mut words = text.as_bytes().chunks_exact(8);
39 if !words.remainder().is_empty() {
40 return Err(Error::new(
41 FailedCode::EmbedProtocol,
42 "vector text length must be a multiple of eight",
43 ));
44 }
45 words
46 .by_ref()
47 .map(|word| {
48 let mut bytes = [0; 4];
49 for (byte, pair) in bytes.iter_mut().zip(word.chunks_exact(2)) {
50 *byte = (nibble(pair[0])? << 4) | nibble(pair[1])?;
51 }
52 let member = f32::from_le_bytes(bytes);
53 if !member.is_finite() {
54 return Err(Error::new(
55 FailedCode::EmbedOutputInvalid,
56 "vector member is not finite",
57 ));
58 }
59 Ok(member)
60 })
61 .collect()
62}