use serde::Deserialize;
use serde_json::Value;
use crate::error::{Error, Result};
const NUMBER: u8 = 0x10;
const STRING: u8 = 0x20;
const ARRAY: u8 = 0x40;
pub fn encode_key(key: &Value) -> Option<Vec<u8>> {
let mut out = Vec::with_capacity(16);
encode_into(key, &mut out).then_some(out)
}
pub fn require_key(key: &Value) -> Result<Vec<u8>> {
encode_key(key).ok_or_else(|| Error::validation("invalid_key", format!("不是合法的键:{}", short(key))))
}
fn encode_into(key: &Value, out: &mut Vec<u8>) -> bool {
match key {
Value::Number(n) => match n.as_f64() {
Some(f) if !f.is_nan() => {
encode_number(f, out);
true
}
_ => false,
},
Value::String(s) => {
encode_string(s, out);
true
}
Value::Array(items) => {
out.push(ARRAY);
for item in items {
if !encode_into(item, out) {
return false;
}
}
out.push(0x00);
true
}
_ => false,
}
}
fn encode_number(f: f64, out: &mut Vec<u8>) {
let mut bytes = f.to_be_bytes();
if bytes[0] & 0x80 == 0 {
bytes[0] ^= 0x80;
} else {
for b in bytes.iter_mut() {
*b = !*b;
}
}
out.push(NUMBER);
out.extend_from_slice(&bytes);
}
fn encode_string(s: &str, out: &mut Vec<u8>) {
out.push(STRING);
for &b in s.as_bytes() {
match b {
0x00 => out.extend_from_slice(&[0x01, 0x01]),
0x01 => out.extend_from_slice(&[0x01, 0x02]),
_ => out.push(b),
}
}
out.push(0x00);
}
pub fn encoded_len(bytes: &[u8]) -> Option<usize> {
match *bytes.first()? {
NUMBER => (bytes.len() >= 9).then_some(9),
STRING => bytes.iter().position(|&b| b == 0x00).map(|end| end + 1),
ARRAY => {
let mut pos = 1;
loop {
match bytes.get(pos)? {
0x00 => return Some(pos + 1),
_ => pos += encoded_len(&bytes[pos..])?,
}
}
}
_ => None,
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
#[serde(untagged)]
pub enum KeyPath {
One(String),
Many(Vec<String>),
}
impl KeyPath {
pub fn paths(&self) -> Vec<&str> {
match self {
KeyPath::One(p) => vec![p.as_str()],
KeyPath::Many(ps) => ps.iter().map(String::as_str).collect(),
}
}
}
pub fn extract_key(value: &Value, key_path: &KeyPath) -> Option<Vec<u8>> {
let mut out = Vec::with_capacity(32);
match key_path {
KeyPath::One(path) => {
if !encode_into(lookup(value, path)?, &mut out) {
return None;
}
}
KeyPath::Many(paths) => {
out.push(ARRAY);
for path in paths {
if !encode_into(lookup(value, path)?, &mut out) {
return None;
}
}
out.push(0x00);
}
}
Some(out)
}
fn lookup<'a>(value: &'a Value, path: &str) -> Option<&'a Value> {
let mut current = value;
for segment in path.split('.') {
current = current.as_object()?.get(segment)?;
}
Some(current)
}
#[derive(Clone, Debug, Default, Deserialize)]
pub struct KeyRangeArg {
#[serde(default)]
pub lower: Option<Value>,
#[serde(default)]
pub upper: Option<Value>,
#[serde(default, rename = "lowerOpen", alias = "lower_open")]
pub lower_open: bool,
#[serde(default, rename = "upperOpen", alias = "upper_open")]
pub upper_open: bool,
}
#[derive(Clone, Debug, Default)]
pub struct Range {
pub lower: Option<(Vec<u8>, bool)>,
pub upper: Option<(Vec<u8>, bool)>,
}
impl KeyRangeArg {
pub fn encode(&self) -> Result<Range> {
let bound = |v: &Option<Value>, open: bool| -> Result<Option<(Vec<u8>, bool)>> {
match v {
None | Some(Value::Null) => Ok(None),
Some(key) => Ok(Some((require_key(key)?, open))),
}
};
Ok(Range { lower: bound(&self.lower, self.lower_open)?, upper: bound(&self.upper, self.upper_open)? })
}
}
fn short(value: &Value) -> String {
let text = value.to_string();
match text.char_indices().nth(40) {
Some((i, _)) => format!("{}…", &text[..i]),
None => text,
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn hex(v: Value) -> String {
hex::encode(encode_key(&v).unwrap())
}
#[test]
fn layout() {
assert_eq!(hex(json!(0)), "108000000000000000");
assert_eq!(hex(json!(1)), "10bff0000000000000");
assert_eq!(hex(json!(-1)), "10400fffffffffffff");
assert_eq!(hex(json!("")), "2000");
assert_eq!(hex(json!("a\u{0}\u{1}")), "20610101010200");
assert_eq!(hex(json!([])), "4000");
assert_eq!(hex(json!([[]])), "40400000");
assert!(encode_key(&json!(null)).is_none());
assert!(encode_key(&json!(true)).is_none());
assert!(encode_key(&json!({ "a": 1 })).is_none());
assert!(encode_key(&json!([1, null])).is_none());
}
#[test]
fn length_of_encoded_keys() {
for key in [json!(5), json!("a\u{0}b"), json!([1, ["x", []], "y"]), json!([[]])] {
let mut bytes = encode_key(&key).unwrap();
let n = bytes.len();
bytes.extend_from_slice(&encode_key(&json!("tail")).unwrap());
assert_eq!(encoded_len(&bytes), Some(n), "{key}");
}
assert_eq!(encoded_len(&[0x10, 1, 2]), None);
assert_eq!(encoded_len(&[0x40, 0x10]), None);
assert_eq!(encoded_len(&[0x33]), None);
}
#[test]
fn extract() {
let v = json!({ "conversation_id": "c1", "seq": 5, "_local": { "created_ms": 7, "flag": true }, "list": [1] });
let path = |s: &str| KeyPath::One(s.into());
assert_eq!(extract_key(&v, &path("seq")), encode_key(&json!(5)));
assert_eq!(extract_key(&v, &path("_local.created_ms")), encode_key(&json!(7)));
assert_eq!(extract_key(&v, &KeyPath::Many(vec!["conversation_id".into(), "seq".into()])), encode_key(&json!(["c1", 5])));
assert_eq!(extract_key(&v, &path("_local.flag")), None);
assert_eq!(extract_key(&v, &path("missing")), None);
assert_eq!(extract_key(&v, &path("list.0")), None);
assert_eq!(extract_key(&v, &path("list")), encode_key(&json!([1])));
assert_eq!(extract_key(&v, &KeyPath::Many(vec!["conversation_id".into(), "nope".into()])), None);
}
}