Skip to main content

coven_format/
key.rs

1//! Canonical primary keys in SQLite numeric, binary text and blob order.
2
3use crate::error::{bound, require, Error, Rule};
4use crate::value::Value;
5use crate::wire::{Decoder, Encoder, Wire, MAX_BYTES, MAX_ITEMS};
6
7/// Encode a nonempty list of non-null key components in SQLite value order.
8/// Integers and reals share numeric order and equal numbers share bytes. Decoding
9/// chooses an integer whenever the number fits exactly in i64. Text uses BINARY
10/// collation, the only one synced key columns may declare (ยง9.2).
11/// Composite keys sort lexicographically, with a shorter prefix first.
12pub fn encode_key(values: &[Value]) -> Result<Vec<u8>, Error> {
13    require(!values.is_empty(), "row key", Rule::Required)?;
14    bound(values.len(), MAX_ITEMS, "key components")?;
15    let mut out = Encoder::new();
16    for value in values {
17        value.validate()?;
18        match value {
19            Value::Null => return Err(Error::Invalid { field: "row key", rule: Rule::NullKey }),
20            Value::Integer(0) | Value::Real(0) => 0x12u8.put(&mut out)?,
21            Value::Integer(n) => {
22                let magnitude = n.unsigned_abs();
23                let shift = magnitude.leading_zeros();
24                number(*n < 0, (63 - shift) as i32, magnitude << shift, &mut out)?;
25            }
26            Value::Real(bits) => {
27                let negative = bits >> 63 != 0;
28                let exponent = ((bits >> 52) & 0x7ff) as i32;
29                let fraction = bits & ((1u64 << 52) - 1);
30                if exponent == 0x7ff {
31                    (if negative { 0x10u8 } else { 0x14 }).put(&mut out)?;
32                } else if exponent == 0 {
33                    let shift = fraction.leading_zeros();
34                    number(negative, 63 - shift as i32 - 1074, fraction << shift, &mut out)?;
35                } else {
36                    number(negative, exponent - 1023, ((1u64 << 52) | fraction) << 11, &mut out)?;
37                }
38            }
39            Value::Text(text) => escaped(0x20, text.as_bytes(), &mut out)?,
40            Value::Blob(bytes) => escaped(0x30, bytes, &mut out)?,
41        }
42    }
43    bound(out.bytes.len(), MAX_BYTES, "key bytes")?;
44    Ok(out.bytes)
45}
46
47fn number(negative: bool, exponent: i32, mantissa: u64, out: &mut Encoder) -> Result<(), Error> {
48    let exponent = (exponent + 1074) as u16;
49    if negative {
50        0x11u8.put(out)?;
51        (!exponent).put(out)?;
52        (!mantissa).put(out)
53    } else {
54        0x13u8.put(out)?;
55        exponent.put(out)?;
56        mantissa.put(out)
57    }
58}
59
60fn escaped(tag: u8, bytes: &[u8], out: &mut Encoder) -> Result<(), Error> {
61    tag.put(out)?;
62    for byte in bytes {
63        byte.put(out)?;
64        if *byte == 0 {
65            255u8.put(out)?;
66        }
67    }
68    out.bytes(&[0, 0])
69}
70
71/// Decode and validate the sole canonical representation of a primary key.
72/// Equal integral reals and integers decode as integers; SQL values outside
73/// keys retain their original storage class in ordinary value encoding.
74pub fn decode_key(bytes: &[u8]) -> Result<Vec<Value>, Error> {
75    bound(bytes.len(), MAX_BYTES, "key bytes")?;
76    let mut input = Decoder::new(bytes)?;
77    let mut values = Vec::new();
78    while !input.is_empty() {
79        bound(values.len() + 1, MAX_ITEMS, "key components")?;
80        let tag = u8::get(&mut input)?;
81        let value = match tag {
82            0x10 => Value::Real(f64::NEG_INFINITY.to_bits()),
83            0x14 => Value::Real(f64::INFINITY.to_bits()),
84            0x12 => Value::Integer(0),
85            0x11 | 0x13 => {
86                let mut exponent = u16::get(&mut input)?;
87                let mut mantissa = u64::get(&mut input)?;
88                if tag == 0x11 {
89                    exponent = !exponent;
90                    mantissa = !mantissa;
91                }
92                decode_number(tag == 0x11, i32::from(exponent) - 1074, mantissa)?
93            }
94            0x20 | 0x30 => {
95                let mut value = Vec::new();
96                loop {
97                    let byte = u8::get(&mut input)?;
98                    if byte == 0 {
99                        match u8::get(&mut input)? {
100                            0 => break,
101                            255 => {}
102                            _ => return Err(key_error()),
103                        }
104                    }
105                    value.try_reserve(1)?;
106                    value.push(byte);
107                }
108                if tag == 0x20 {
109                    Value::Text(String::from_utf8(value).map_err(Error::from)?)
110                } else {
111                    Value::Blob(value)
112                }
113            }
114            _ => return Err(key_error()),
115        };
116        values.try_reserve(1)?;
117        values.push(value);
118    }
119    require(encode_key(&values)? == bytes, "key", Rule::KeyEncoding)?;
120    Ok(values)
121}
122
123fn key_error() -> Error {
124    Error::Invalid { field: "key", rule: Rule::KeyEncoding }
125}
126
127fn decode_number(negative: bool, exponent: i32, mantissa: u64) -> Result<Value, Error> {
128    if !(-1074..=1023).contains(&exponent) || mantissa >> 63 != 1 {
129        return Err(key_error());
130    }
131    if (0..=63).contains(&exponent) {
132        let shift = 63 - exponent as u32;
133        let magnitude = mantissa >> shift;
134        if magnitude << shift == mantissa {
135            if negative && magnitude == 1u64 << 63 {
136                return Ok(Value::Integer(i64::MIN));
137            }
138            if let Ok(n) = i64::try_from(magnitude) {
139                return Ok(Value::Integer(if negative { -n } else { n }));
140            }
141        }
142    }
143    let bits = if exponent >= -1022 {
144        if mantissa & 0x7ff != 0 {
145            return Err(key_error());
146        }
147        (((exponent + 1023) as u64) << 52) | ((mantissa >> 11) & ((1u64 << 52) - 1))
148    } else {
149        let shift = (63 - (exponent + 1074)) as u32;
150        let fraction = mantissa >> shift;
151        if fraction << shift != mantissa {
152            return Err(key_error());
153        }
154        fraction
155    };
156    Ok(Value::Real(bits | (u64::from(negative) << 63)))
157}
158
159#[cfg(test)]
160#[path = "key_tests.rs"]
161mod tests;