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