essential_types/solution/
decode.rs

1//! # Decoding
2//! Decoding for solution types.
3
4use crate::Word;
5
6use super::Mutation;
7
8#[cfg(test)]
9mod tests;
10
11/// Errors that can occur when decoding a predicate.
12#[derive(Debug, PartialEq)]
13pub enum MutationDecodeError {
14    /// The words are too short for the lengths of the key or value.
15    WordsTooShort,
16    /// The key length is negative.
17    NegativeKeyLength,
18    /// The value length is negative.
19    NegativeValueLength,
20}
21
22impl std::error::Error for MutationDecodeError {}
23
24/// Decode a mutation from words.
25///
26/// # Layout
27/// ```text
28/// +-----------------+-----------------+-----------------+-----------------+
29/// | key length      | key             | value length    | value           |
30/// +-----------------+-----------------+-----------------+-----------------+
31/// ```
32pub fn decode_mutation(bytes: &[Word]) -> Result<Mutation, MutationDecodeError> {
33    if bytes.len() < 2 {
34        return Err(MutationDecodeError::WordsTooShort);
35    }
36
37    if bytes[0] < 0 {
38        return Err(MutationDecodeError::NegativeKeyLength);
39    }
40
41    // Saturating cast
42    let key_len: usize = bytes[0].try_into().unwrap_or(usize::MAX);
43    let key_end = 1usize.saturating_add(key_len);
44    if bytes.len() < key_end {
45        return Err(MutationDecodeError::WordsTooShort);
46    }
47    let key = bytes[1..key_end].to_vec();
48
49    if bytes[key_end] < 0 {
50        return Err(MutationDecodeError::NegativeValueLength);
51    }
52
53    // Saturating cast
54    let value_len: usize = bytes[key_end].try_into().unwrap_or(usize::MAX);
55
56    let value_start = 2usize.saturating_add(key_len);
57    let value_end = value_start.saturating_add(value_len);
58
59    if bytes.len() < value_end {
60        return Err(MutationDecodeError::WordsTooShort);
61    }
62    let value = bytes[value_start..value_end].to_vec();
63    Ok(Mutation { key, value })
64}
65
66/// Decode a slice of mutations from words.
67///
68/// # Layout
69/// ```text
70/// +-----------------+-----------------+-----------------+-----------------+
71/// | num mutations   | mutation 1      | mutation 2      | ...             |
72/// +-----------------+-----------------+-----------------+-----------------+
73/// ```
74pub fn decode_mutations(bytes: &[Word]) -> Result<Vec<Mutation>, MutationDecodeError> {
75    if bytes.is_empty() {
76        return Err(MutationDecodeError::WordsTooShort);
77    }
78    if bytes[0] < 0 {
79        return Err(MutationDecodeError::NegativeValueLength);
80    }
81
82    // Saturating cast
83    let len: usize = bytes[0].try_into().unwrap_or(usize::MAX);
84
85    // FIXME: Do a max size check to avoid a DoS attack that allocates too much memory.
86    let mut mutations = Vec::with_capacity(len);
87    if len == 0 {
88        return Ok(mutations);
89    }
90    let mut i = 1;
91    while i < bytes.len() {
92        let Some(b) = bytes.get(i..) else {
93            return Err(MutationDecodeError::WordsTooShort);
94        };
95        let mutation = decode_mutation(b)?;
96        let size = mutation.encode_size();
97        i += size;
98        mutations.push(mutation);
99    }
100    Ok(mutations)
101}