Skip to main content

state_engine/core/
codec.rs

1use super::fixed_bits;
2
3pub const ROOT_NAMES: &[(&str, u64)] = &[
4    ("_load",  fixed_bits::ROOT_LOAD),
5    ("_store", fixed_bits::ROOT_STORE),
6    ("_state", fixed_bits::ROOT_STATE),
7];
8
9pub fn root_encode(s: &str) -> u64 {
10    ROOT_NAMES.iter()
11        .find(|(name, _)| *name == s)
12        .map(|(_, v)| *v)
13        .unwrap_or(fixed_bits::ROOT_NULL)
14}
15
16pub fn root_decode(v: u64) -> Option<&'static str> {
17    ROOT_NAMES.iter()
18        .find(|(_, val)| *val == v)
19        .map(|(name, _)| *name)
20}
21
22pub const CLIENT_NAMES: &[(&str, u64)] = &[
23    ("State",    fixed_bits::CLIENT_STATE),
24    ("InMemory", fixed_bits::CLIENT_IN_MEMORY),
25    ("Env",      fixed_bits::CLIENT_ENV),
26    ("KVS",      fixed_bits::CLIENT_KVS),
27    ("Db",       fixed_bits::CLIENT_DB),
28    ("HTTP",     fixed_bits::CLIENT_HTTP),
29    ("File",     fixed_bits::CLIENT_FILE),
30];
31
32pub fn client_encode(s: &str) -> u64 {
33    CLIENT_NAMES.iter()
34        .find(|(name, _)| *name == s)
35        .map(|(_, v)| *v)
36        .unwrap_or(fixed_bits::CLIENT_NULL)
37}
38
39pub fn client_decode(v: u64) -> Option<&'static str> {
40    CLIENT_NAMES.iter()
41        .find(|(_, val)| *val == v)
42        .map(|(name, _)| *name)
43}
44
45pub const PROP_NAMES: &[(&str, u64)] = &[
46    ("type",       fixed_bits::PROP_TYPE),
47    ("key",        fixed_bits::PROP_KEY),
48    ("connection", fixed_bits::PROP_CONNECTION),
49    ("map",        fixed_bits::PROP_MAP),
50    ("ttl",        fixed_bits::PROP_TTL),
51    ("table",      fixed_bits::PROP_TABLE),
52    ("where",      fixed_bits::PROP_WHERE),
53    ("url",        fixed_bits::PROP_URL),
54    ("headers",    fixed_bits::PROP_HEADERS),
55];
56
57pub fn prop_encode(s: &str) -> u64 {
58    PROP_NAMES.iter()
59        .find(|(name, _)| *name == s)
60        .map(|(_, v)| *v)
61        .unwrap_or(fixed_bits::PROP_NULL)
62}
63
64pub fn prop_decode(v: u64) -> Option<&'static str> {
65    PROP_NAMES.iter()
66        .find(|(_, val)| *val == v)
67        .map(|(name, _)| *name)
68}
69
70/// Per-client required/optional prop indices.
71/// State layer uses this to mechanically build call arguments from manifest records.
72///
73/// Layout per entry: (client, &[props])
74/// - InMemory : key
75/// - KVS      : key, ttl
76/// - Env      : map
77/// - Db       : connection, table, map, where
78/// - HTTP     : url, headers, map
79/// - File     : key, map
80/// - State    : key
81pub const CLIENT_PROPS: &[(u64, &[u64])] = &[
82    (fixed_bits::CLIENT_STATE,     &[fixed_bits::PROP_KEY]),
83    (fixed_bits::CLIENT_IN_MEMORY, &[fixed_bits::PROP_KEY]),
84    (fixed_bits::CLIENT_ENV,       &[fixed_bits::PROP_MAP]),
85    (fixed_bits::CLIENT_KVS,       &[fixed_bits::PROP_KEY, fixed_bits::PROP_TTL]),
86    (fixed_bits::CLIENT_DB,        &[fixed_bits::PROP_CONNECTION, fixed_bits::PROP_TABLE, fixed_bits::PROP_MAP, fixed_bits::PROP_WHERE]),
87    (fixed_bits::CLIENT_HTTP,      &[fixed_bits::PROP_URL, fixed_bits::PROP_HEADERS, fixed_bits::PROP_MAP]),
88    (fixed_bits::CLIENT_FILE,      &[fixed_bits::PROP_KEY, fixed_bits::PROP_MAP]),
89];
90
91pub fn client_props(client: u64) -> &'static [u64] {
92    CLIENT_PROPS.iter()
93        .find(|(c, _)| *c == client)
94        .map(|(_, props)| *props)
95        .unwrap_or(&[])
96}
97
98pub const TYPE_NAMES: &[(&str, u64)] = &[
99    ("integer",  fixed_bits::TYPE_I64),
100    ("string",   fixed_bits::TYPE_UTF8),
101    ("float",    fixed_bits::TYPE_F64),
102    ("boolean",  fixed_bits::TYPE_BOOLEAN),
103    ("datetime", fixed_bits::TYPE_DATETIME),
104];
105
106pub fn type_encode(s: &str) -> u64 {
107    TYPE_NAMES.iter()
108        .find(|(name, _)| *name == s)
109        .map(|(_, v)| *v)
110        .unwrap_or(fixed_bits::TYPE_NULL)
111}
112
113pub fn type_decode(v: u64) -> Option<&'static str> {
114    TYPE_NAMES.iter()
115        .find(|(_, val)| *val == v)
116        .map(|(name, _)| *name)
117}
118
119#[cfg(test)]
120mod tests {
121    use super::*;
122
123    #[test]
124    fn test_client_codec() {
125        for &(name, val) in CLIENT_NAMES {
126            assert_eq!(client_encode(name), val);
127            assert_eq!(client_decode(val), Some(name));
128        }
129    }
130
131    #[test]
132    fn test_client_props() {
133        for &(client, props) in CLIENT_PROPS {
134            assert_eq!(client_props(client), props);
135        }
136        assert!(client_props(fixed_bits::CLIENT_NULL).is_empty());
137    }
138
139    #[test]
140    fn test_root_codec() {
141        for &(name, val) in ROOT_NAMES {
142            assert_eq!(root_encode(name), val);
143            assert_eq!(root_decode(val), Some(name));
144        }
145    }
146
147    #[test]
148    fn test_prop_codec() {
149        for &(name, val) in PROP_NAMES {
150            assert_eq!(prop_encode(name), val);
151            assert_eq!(prop_decode(val), Some(name));
152        }
153    }
154
155    #[test]
156    fn test_type_codec() {
157        for &(name, val) in TYPE_NAMES {
158            assert_eq!(type_encode(name), val);
159            assert_eq!(type_decode(val), Some(name));
160        }
161    }
162
163    #[test]
164    fn test_unknown_encode() {
165        assert_eq!(client_encode("Unknown"), fixed_bits::CLIENT_NULL);
166        assert_eq!(root_encode("_unknown"), fixed_bits::ROOT_NULL);
167        assert_eq!(prop_encode("unknown"), fixed_bits::PROP_NULL);
168        assert_eq!(type_encode("unknown"), fixed_bits::TYPE_NULL);
169    }
170
171    #[test]
172    fn test_null_decode() {
173        assert_eq!(client_decode(fixed_bits::CLIENT_NULL), None);
174        assert_eq!(root_decode(fixed_bits::ROOT_NULL), None);
175        assert_eq!(prop_decode(fixed_bits::PROP_NULL), None);
176        assert_eq!(type_decode(fixed_bits::TYPE_NULL), None);
177    }
178}