1pub const TAG_CATALOG: u8 = 0x00;
10pub const TAG_NODE: u8 = 0x01;
11pub const TAG_EDGE: u8 = 0x03;
12pub const TAG_REDGE: u8 = 0x04;
13pub const TAG_VEC: u8 = 0x05;
18pub const TAG_LABEL: u8 = 0x02;
19pub const TAG_EXT: u8 = 0x06;
20pub const TAG_CEDGE: u8 = 0x08;
26pub const TAG_CREDGE: u8 = 0x09;
27pub const TAG_PROP: u8 = 0x0A;
32pub const TAG_VCODE: u8 = 0x0B;
38pub const TAG_TEXT: u8 = 0x0C;
49pub const TAG_TEXTNORM: u8 = 0x0D;
52pub const TAG_TEXTMETA: u8 = 0x0E;
55pub const TAG_SPAT: u8 = 0x0F;
60pub const TAG_GEOM: u8 = 0x10;
64pub const TAG_NAV: u8 = 0x11;
71pub const TAG_SQLMETA: u8 = 0x12;
75pub const TAG_FIELDIDX: u8 = 0x13;
79pub const TAG_SEARCHSLOT: u8 = 0x14;
83
84pub const CAT_KEY_ORDER: u64 = 4;
92pub const CAT_FIELD_AGGREGATE: u64 = 5;
95
96pub fn field_aggregate_key(coll: u64, field: u64) -> Vec<u8> {
97 k(TAG_CATALOG, &[CAT_FIELD_AGGREGATE, coll, field])
98}
99
100pub fn is_field_aggregate_key(key: &[u8]) -> bool {
101 key.len() == 25 && key[0] == TAG_CATALOG
102 && key[1..9] == CAT_FIELD_AGGREGATE.to_be_bytes()
103}
104
105fn k(tag: u8, parts: &[u64]) -> Vec<u8> {
106 let mut v = Vec::with_capacity(1 + parts.len() * 8);
107 v.push(tag);
108 for p in parts { v.extend_from_slice(&p.to_be_bytes()); }
109 v
110}
111
112pub fn node(id: u64) -> Vec<u8> { k(TAG_NODE, &[id]) }
113pub fn edge(ctx: u64, src: u64, ty: u64, dst: u64) -> Vec<u8> {
117 if ctx == 0 { k(TAG_EDGE, &[src, ty, dst]) } else { k(TAG_CEDGE, &[ctx, src, ty, dst]) }
118}
119pub fn redge(ctx: u64, dst: u64, ty: u64, src: u64) -> Vec<u8> {
120 if ctx == 0 { k(TAG_REDGE, &[dst, ty, src]) } else { k(TAG_CREDGE, &[ctx, dst, ty, src]) }
121}
122pub fn edge_prefix(ctx: u64, src: u64) -> Vec<u8> {
123 if ctx == 0 { k(TAG_EDGE, &[src]) } else { k(TAG_CEDGE, &[ctx, src]) }
124}
125pub fn ctx_prefix(ctx: u64) -> Vec<u8> {
126 if ctx == 0 { vec![TAG_EDGE] } else { k(TAG_CEDGE, &[ctx]) }
127}
128pub fn vec_key(field: u64, id: u64) -> Vec<u8> { k(TAG_VEC, &[field, id]) }
129pub fn vec_prefix(field: u64) -> Vec<u8> { k(TAG_VEC, &[field]) }
130pub fn vcode_key(field: u64, id: u64) -> Vec<u8> { k(TAG_VCODE, &[field, id]) }
131pub fn vcode_prefix(field: u64) -> Vec<u8> { k(TAG_VCODE, &[field]) }
132pub fn nav_prefix(field: u64) -> Vec<u8> { k(TAG_NAV, &[field]) }
133
134pub fn text_head_key(field: u64, term: &[u8], docid: u64) -> Vec<u8> {
135 let mut v = Vec::with_capacity(1 + 8 + 4 + term.len() + 1 + 8);
136 v.push(TAG_TEXT);
137 v.extend_from_slice(&field.to_be_bytes());
138 v.extend_from_slice(&0u32.to_be_bytes());
139 v.extend_from_slice(term);
140 v.push(0x00);
141 v.extend_from_slice(&docid.to_be_bytes());
142 v
143}
144pub fn text_head_doc_key(field: u64, docid: u64) -> Vec<u8> {
148 text_head_key(field, b"", docid)
149}
150pub fn text_seg_key(field: u64, seg: u32, term: &[u8]) -> Vec<u8> {
151 let mut v = Vec::with_capacity(1 + 8 + 4 + term.len());
152 v.push(TAG_TEXT);
153 v.extend_from_slice(&field.to_be_bytes());
154 v.extend_from_slice(&seg.to_be_bytes());
155 v.extend_from_slice(term);
156 v
157}
158pub fn text_seg_block_prefix(field: u64, seg: u32, term: &[u8]) -> Vec<u8> {
161 let mut v = text_seg_key(field, seg, term);
162 v.push(0);
163 v
164}
165pub fn text_seg_block_key(field: u64, seg: u32, term: &[u8], first_doc: u64) -> Vec<u8> {
166 let mut v = text_seg_block_prefix(field, seg, term);
167 v.extend_from_slice(&first_doc.to_be_bytes());
168 v
169}
170pub fn text_seg_doc_prefix(field: u64, seg: u32) -> Vec<u8> {
173 let mut v = text_meta_key(field, seg);
174 v.push(0);
175 v
176}
177pub fn text_seg_doc_key(field: u64, seg: u32, docid: u64) -> Vec<u8> {
178 let mut v = text_seg_doc_prefix(field, seg);
179 v.extend_from_slice(&docid.to_be_bytes());
180 v
181}
182pub fn text_norm_key(field: u64, docid: u64) -> Vec<u8> { k(TAG_TEXTNORM, &[field, docid]) }
183pub fn text_prefix(field: u64) -> Vec<u8> { k(TAG_TEXT, &[field]) }
184pub fn text_norm_prefix(field: u64) -> Vec<u8> { k(TAG_TEXTNORM, &[field]) }
185pub fn text_meta_prefix(field: u64) -> Vec<u8> { k(TAG_TEXTMETA, &[field]) }
186pub fn spat_key(field: u64, level: u8, cell: u64, id: u64) -> Vec<u8> {
187 let mut v = Vec::with_capacity(1 + 8 + 1 + 8 + 8);
188 v.push(TAG_SPAT);
189 v.extend_from_slice(&field.to_be_bytes());
190 v.push(level);
191 v.extend_from_slice(&cell.to_be_bytes());
192 v.extend_from_slice(&id.to_be_bytes());
193 v
194}
195pub fn geom_key(field: u64, id: u64) -> Vec<u8> { k(TAG_GEOM, &[field, id]) }
196pub fn geom_prefix(field: u64) -> Vec<u8> { k(TAG_GEOM, &[field]) }
197pub fn nav_key(field: u64, id: u64) -> Vec<u8> { k(TAG_NAV, &[field, id]) }
198pub fn fieldidx_key(coll: u64, field: u64, value: &[u8], id: u64) -> Vec<u8> {
204 let mut v = Vec::with_capacity(17 + value.len() + 8);
205 v.push(TAG_FIELDIDX);
206 v.extend_from_slice(&coll.to_be_bytes());
207 v.extend_from_slice(&field.to_be_bytes());
208 v.extend_from_slice(value);
209 v.extend_from_slice(&id.to_be_bytes());
210 v
211}
212pub fn fieldidx_prefix(coll: u64, field: u64) -> Vec<u8> {
213 let mut v = Vec::with_capacity(17);
214 v.push(TAG_FIELDIDX);
215 v.extend_from_slice(&coll.to_be_bytes());
216 v.extend_from_slice(&field.to_be_bytes());
217 v
218}
219
220pub fn searchslot_key(idx: u64, kind: u8, id: u64) -> Vec<u8> {
221 let mut v = Vec::with_capacity(18);
222 v.push(TAG_SEARCHSLOT);
223 v.extend_from_slice(&idx.to_be_bytes());
224 v.push(kind);
225 v.extend_from_slice(&id.to_be_bytes());
226 v
227}
228
229pub fn searchslot_prefix(idx: u64) -> Vec<u8> {
230 let mut v = Vec::with_capacity(9);
231 v.push(TAG_SEARCHSLOT);
232 v.extend_from_slice(&idx.to_be_bytes());
233 v
234}
235
236pub fn sqlmeta_key(kind: u8, hash: u64) -> Vec<u8> {
237 let mut v = Vec::with_capacity(10);
238 v.push(TAG_SQLMETA); v.push(kind); v.extend_from_slice(&hash.to_be_bytes()); v
239}
240pub fn spat_prefix(field: u64, level: u8) -> Vec<u8> {
241 let mut v = Vec::with_capacity(1 + 8 + 1);
242 v.push(TAG_SPAT);
243 v.extend_from_slice(&field.to_be_bytes());
244 v.push(level);
245 v
246}
247
248pub fn text_meta_key(field: u64, seg: u32) -> Vec<u8> {
249 let mut v = Vec::with_capacity(1 + 8 + 4);
250 v.push(TAG_TEXTMETA);
251 v.extend_from_slice(&field.to_be_bytes());
252 v.extend_from_slice(&seg.to_be_bytes());
253 v
254}
255pub const TEXT_TERM_STATS_SEG: u32 = u32::MAX - 1;
259pub const TEXT_FIELD_META_SEG: u32 = u32::MAX;
260pub fn text_field_meta_key(field: u64) -> Vec<u8> {
261 text_meta_key(field, TEXT_FIELD_META_SEG)
262}
263pub fn text_term_id_key(field: u64, term_id: u64) -> Vec<u8> {
264 let mut v = text_meta_key(field, TEXT_TERM_STATS_SEG);
265 v.push(0);
266 v.extend_from_slice(&term_id.to_be_bytes());
267 v
268}
269pub fn text_term_lex_prefix(field: u64) -> Vec<u8> {
273 let mut v = text_meta_key(field, TEXT_TERM_STATS_SEG);
274 v.push(1);
275 v
276}
277pub fn text_term_lex_key(field: u64, term: &[u8]) -> Vec<u8> {
278 let mut v = text_term_lex_prefix(field);
279 v.extend_from_slice(term);
280 v
281}
282pub fn label(l: u64, id: u64) -> Vec<u8> { k(TAG_LABEL, &[l, id]) }
283pub fn label_prefix(l: u64) -> Vec<u8> { k(TAG_LABEL, &[l]) }
284pub fn edge_type_prefix(ctx: u64, src: u64, ty: u64) -> Vec<u8> {
285 if ctx == 0 { k(TAG_EDGE, &[src, ty]) } else { k(TAG_CEDGE, &[ctx, src, ty]) }
286}
287pub fn redge_prefix(ctx: u64, dst: u64) -> Vec<u8> {
288 if ctx == 0 { k(TAG_REDGE, &[dst]) } else { k(TAG_CREDGE, &[ctx, dst]) }
289}
290pub fn redge_type_prefix(ctx: u64, dst: u64, ty: u64) -> Vec<u8> {
291 if ctx == 0 { k(TAG_REDGE, &[dst, ty]) } else { k(TAG_CREDGE, &[ctx, dst, ty]) }
292}
293pub fn extkey(h: u64) -> Vec<u8> { k(TAG_EXT, &[h]) }
294pub fn catalog(field: u64) -> Vec<u8> { k(TAG_CATALOG, &[field]) }
295pub fn catalog_field(slot: u64, field: u64) -> Vec<u8> { k(TAG_CATALOG, &[slot, field]) }
310pub fn catalog_field_prefix(slot: u64) -> Vec<u8> { k(TAG_CATALOG, &[slot]) }
311pub fn catalog_field_item(slot: u64, field: u64, item: u64) -> Vec<u8> {
315 k(TAG_CATALOG, &[slot, field, item])
316}
317
318pub fn key_order_prefix(collection: u64, field: u64) -> Vec<u8> {
320 k(TAG_CATALOG, &[CAT_KEY_ORDER, collection, field])
321}
322
323pub fn key_order_key(collection: u64, field: u64, key: &[u8], id: u64) -> Vec<u8> {
329 let mut out = key_order_prefix(collection, field);
330 for &byte in key {
331 if byte == 0 { out.extend_from_slice(&[0, u8::MAX]); }
332 else { out.push(byte); }
333 }
334 out.extend_from_slice(&[0, 0]);
335 out.extend_from_slice(&id.to_be_bytes());
336 out
337}
338
339pub fn ext_hash(b: &[u8]) -> u64 {
343 let mut h: u64 = 0xcbf2_9ce4_8422_2325;
344 for x in b { h ^= *x as u64; h = h.wrapping_mul(0x1000_0000_01b3); }
345 h
346}
347
348pub fn prop(prop_id: u64, value: u64, id: u64) -> Vec<u8> { k(TAG_PROP, &[prop_id, value, id]) }
349pub fn prop_prefix(prop_id: u64) -> Vec<u8> { k(TAG_PROP, &[prop_id]) }
350pub fn prop_value_prefix(prop_id: u64, value: u64) -> Vec<u8> { k(TAG_PROP, &[prop_id, value]) }
351
352pub fn enc_i64(v: i64) -> u64 { (v as u64) ^ (1 << 63) }
358pub fn enc_f64(v: f64) -> u64 {
359 let b = v.to_bits();
360 if b >> 63 == 1 { !b } else { b ^ (1 << 63) }
361}
362pub fn enc_f64_desc(v: f64) -> u64 { !enc_f64(v) }
365pub fn enc_i64_desc(v: i64) -> u64 { !enc_i64(v) }
366
367pub fn u64_at(k: &[u8], off: usize) -> u64 {
369 let mut w = [0u8; 8]; w.copy_from_slice(&k[off..off+8]); u64::from_be_bytes(w)
370}
371
372#[cfg(test)]
373mod tests {
374 use super::*;
375 #[test]
376 fn byte_order_is_numeric_order_and_tags_never_interleave() {
377 let mut ks: Vec<Vec<u8>> = (0..64u64).map(|i| edge(0, i * 7919, 1, i)).collect();
378 let want = ks.clone();
379 ks.sort();
380 assert_eq!(ks, want, "big-endian keys must already be sorted");
381 assert!(node(u64::MAX) < edge(0, 0, 0, 0), "node space must sort before edge space");
382 assert!(edge(0, u64::MAX, u64::MAX, u64::MAX) < redge(0, 0, 0, 0));
383 assert!(redge(0, u64::MAX, 0, 0) < edge(1, 0, 0, 0), "ctx spaces sort after base");
384 assert!(edge(1, u64::MAX, 0, 0) < redge(1, 0, 0, 0));
385 }
386 #[test]
387 fn adjacency_is_a_contiguous_prefix() {
388 let pre = edge_prefix(0, 42);
389 for d in 0..16u64 {
390 assert!(edge(0, 42, 7, d).starts_with(&pre));
391 assert!(!edge(0, 43, 7, d).starts_with(&pre));
392 assert!(!edge(1, 42, 7, d).starts_with(&pre), "another ctx leaked in");
393 }
394 let kg = ctx_prefix(5);
396 assert!(edge(5, 0, 0, 0).starts_with(&kg) && edge(5, u64::MAX, 1, 1).starts_with(&kg));
397 assert!(!edge(6, 0, 0, 0).starts_with(&kg));
398 }
399}