compress_json_rs/
memory.rs

1use std::collections::HashMap;
2use serde_json::Value;
3use crate::config::CONFIG;
4use crate::debug::throw_unsupported_data;
5use crate::encode::{encode_bool, encode_num, encode_str};
6use crate::number::int_to_s;
7
8/// Key type for compressed references
9pub type Key = String;
10
11/// In-memory structure holding store and caches for compression
12pub struct Memory {
13    store: Vec<String>,
14    value_cache: HashMap<String, String>,
15    schema_cache: HashMap<String, String>,
16    key_count: usize,
17}
18
19/// Convert internal store to values array
20pub fn mem_to_values(mem: &Memory) -> Vec<String> {
21    mem.store.clone()
22}
23
24/// Create a new in-memory Memory instance
25pub fn make_memory() -> Memory {
26    Memory {
27        store: Vec::new(),
28        value_cache: HashMap::new(),
29        schema_cache: HashMap::new(),
30        key_count: 0,
31    }
32}
33
34/// Get or insert a value in the store, returning its key
35fn get_value_key(mem: &mut Memory, value: &str) -> String {
36    if let Some(key) = mem.value_cache.get(value) {
37        return key.clone();
38    }
39    let id = mem.key_count;
40    let key = int_to_s(id);
41    mem.key_count += 1;
42    mem.store.push(value.to_string());
43    mem.value_cache.insert(value.to_string(), key.clone());
44    key
45}
46
47/// Get or insert a schema (object keys), returning its key
48fn get_schema(mem: &mut Memory, keys: &[String]) -> String {
49    let mut schema_keys = keys.to_vec();
50    if CONFIG.sort_key {
51        schema_keys.sort();
52    }
53    let schema = schema_keys.join(",");
54    if let Some(key) = mem.schema_cache.get(&schema) {
55        return key.clone();
56    }
57    // Represent schema as an array of strings
58    let arr = Value::Array(
59        schema_keys
60            .iter()
61            .map(|k| Value::String(k.clone()))
62            .collect(),
63    );
64    let key_id = add_value(mem, &arr);
65    mem.schema_cache.insert(schema, key_id.clone());
66    key_id
67}
68
69/// Recursively add a JSON value to memory, returning its key
70pub fn add_value(mem: &mut Memory, o: &Value) -> Key {
71    match o {
72        Value::Null => "".to_string(),
73        Value::Bool(b) => get_value_key(mem, &encode_bool(*b)),
74        Value::Number(n) => {
75            // Convert number to f64
76            let f = n.as_f64().unwrap_or_else(|| {
77                // integer fallback
78                n.as_i64()
79                    .map(|i| i as f64)
80                    .or_else(|| n.as_u64().map(|u| u as f64))
81                    .unwrap_or(0.0)
82            });
83            if f.is_nan() {
84                if CONFIG.error_on_nan {
85                    throw_unsupported_data("[number NaN]");
86                }
87                return "".to_string();
88            }
89            if f.is_infinite() {
90                if CONFIG.error_on_infinite {
91                    throw_unsupported_data("[number Infinity]");
92                }
93                return "".to_string();
94            }
95            get_value_key(mem, &encode_num(f))
96        }
97        Value::String(s) => get_value_key(mem, &encode_str(s)),
98        Value::Array(arr) => {
99            let mut acc = String::from("a");
100            for v in arr.iter() {
101                let key = if v.is_null() {
102                    "_".to_string()
103                } else {
104                    add_value(mem, v)
105                };
106                acc.push('|');
107                acc.push_str(&key);
108            }
109            if acc == "a" {
110                acc = "a|".to_string();
111            }
112            get_value_key(mem, &acc)
113        }
114        Value::Object(map) => {
115            let keys: Vec<String> = map.keys().cloned().collect();
116            if keys.is_empty() {
117                return get_value_key(mem, "o|");
118            }
119            let key_id = get_schema(mem, &keys);
120            let mut acc = String::from("o|");
121            acc.push_str(&key_id);
122            for key in keys.iter() {
123                let v = &map[key];
124                let val_key = add_value(mem, v);
125                acc.push('|');
126                acc.push_str(&val_key);
127            }
128            get_value_key(mem, &acc)
129        }
130        _ => panic!("unsupported data type"),
131    }
132}