1mod succinctarchiveconstraint;
2mod universe;
3
4use crate::blob::Blob;
5use crate::blob::BlobSchema;
6use crate::blob::ToBlob;
7use crate::blob::TryFromBlob;
8use crate::id::id_from_value;
9use crate::id::id_into_value;
10use crate::id::ExclusiveId;
11use crate::id::Id;
12use crate::id_hex;
13use crate::macros::entity;
14use crate::metadata;
15use crate::metadata::ConstMetadata;
16use crate::query::TriblePattern;
17use crate::repo::BlobStore;
18use crate::trible::Trible;
19use crate::trible::TribleSet;
20use crate::value::schemas::genid::GenId;
21use crate::value::schemas::hash::Blake3;
22use crate::value::schemas::UnknownValue;
23use crate::value::RawValue;
24use crate::value::Value;
25use crate::value::ValueSchema;
26use succinctarchiveconstraint::*;
27
28pub use universe::*;
29
30use std::convert::TryInto;
31use std::iter;
32
33use itertools::Itertools;
34
35use anybytes::area::{ByteArea, SectionWriter};
36use anybytes::Bytes;
37use jerky::bit_vector::rank9sel::Rank9SelIndex;
38use jerky::bit_vector::BitVector;
39use jerky::bit_vector::BitVectorBuilder;
40use jerky::bit_vector::BitVectorDataMeta;
41use jerky::bit_vector::NumBits;
42use jerky::bit_vector::Rank;
43use jerky::bit_vector::Select;
44use jerky::char_sequences::wavelet_matrix::WaveletMatrixMeta;
45use jerky::char_sequences::{WaveletMatrix, WaveletMatrixBuilder};
46use jerky::serialization::{Metadata, Serializable};
47
48pub struct SuccinctArchiveBlob;
49
50impl BlobSchema for SuccinctArchiveBlob {}
51
52impl ConstMetadata for SuccinctArchiveBlob {
53 fn id() -> Id {
54 id_hex!("8FAD1D4C7F884B51BAA5D6C56B873E41")
55 }
56
57 fn describe<B>(blobs: &mut B) -> Result<TribleSet, B::PutError>
58 where
59 B: BlobStore<Blake3>,
60 {
61 let id = Self::id();
62 let description = blobs.put(
63 "Succinct archive index for fast offline trible queries. The bytes store a compressed, query-friendly layout derived from a canonical trible set.\n\nUse for large, read-heavy, mostly immutable datasets where fast scans or joins matter more than incremental updates. Build it from a TribleSet or SimpleArchive, and keep a canonical source if you need to regenerate or validate the index.",
64 )?;
65 Ok(entity! {
66 ExclusiveId::force_ref(&id) @
67 metadata::name: blobs.put("succinctarchive".to_string())?,
68 metadata::description: description,
69 metadata::tag: metadata::KIND_BLOB_SCHEMA,
70 })
71 }
72}
73
74#[derive(Debug, Clone, Copy, zerocopy::FromBytes, zerocopy::KnownLayout, zerocopy::Immutable)]
75#[repr(C)]
76pub struct SuccinctArchiveMeta<D: Metadata> {
77 pub entity_count: usize,
78 pub attribute_count: usize,
79 pub value_count: usize,
80 pub domain: D,
81 pub e_a: BitVectorDataMeta,
82 pub a_a: BitVectorDataMeta,
83 pub v_a: BitVectorDataMeta,
84 pub changed_e_a: BitVectorDataMeta,
85 pub changed_e_v: BitVectorDataMeta,
86 pub changed_a_e: BitVectorDataMeta,
87 pub changed_a_v: BitVectorDataMeta,
88 pub changed_v_e: BitVectorDataMeta,
89 pub changed_v_a: BitVectorDataMeta,
90 pub eav_c: WaveletMatrixMeta,
91 pub vea_c: WaveletMatrixMeta,
92 pub ave_c: WaveletMatrixMeta,
93 pub vae_c: WaveletMatrixMeta,
94 pub eva_c: WaveletMatrixMeta,
95 pub aev_c: WaveletMatrixMeta,
96}
97
98fn build_prefix_bv<I>(
99 domain_len: usize,
100 triple_count: usize,
101 iter: I,
102 writer: &mut SectionWriter,
103) -> BitVector<Rank9SelIndex>
104where
105 I: IntoIterator<Item = (usize, usize)>,
106{
107 let mut builder =
108 BitVectorBuilder::from_bit(false, triple_count + domain_len + 1, writer).unwrap();
109
110 let mut seen = 0usize;
111 let mut last = 0usize;
112 for (val, count) in iter {
113 for c in last..=val {
114 builder.set_bit(seen + c, true).unwrap();
115 }
116 seen += count;
117 last = val + 1;
118 }
119 for c in last..=domain_len {
120 builder.set_bit(seen + c, true).unwrap();
121 }
122 builder.freeze::<Rank9SelIndex>()
123}
124
125#[derive(Debug, Clone)]
126pub struct SuccinctArchive<U> {
127 pub bytes: Bytes,
128 pub domain: U,
129
130 pub entity_count: usize,
131 pub attribute_count: usize,
132 pub value_count: usize,
133
134 pub e_a: BitVector<Rank9SelIndex>,
135 pub a_a: BitVector<Rank9SelIndex>,
136 pub v_a: BitVector<Rank9SelIndex>,
137
138 pub changed_e_a: BitVector<Rank9SelIndex>,
141 pub changed_e_v: BitVector<Rank9SelIndex>,
144 pub changed_a_e: BitVector<Rank9SelIndex>,
147 pub changed_a_v: BitVector<Rank9SelIndex>,
150 pub changed_v_e: BitVector<Rank9SelIndex>,
153 pub changed_v_a: BitVector<Rank9SelIndex>,
156
157 pub eav_c: WaveletMatrix<Rank9SelIndex>,
158 pub vea_c: WaveletMatrix<Rank9SelIndex>,
159 pub ave_c: WaveletMatrix<Rank9SelIndex>,
160 pub vae_c: WaveletMatrix<Rank9SelIndex>,
161 pub eva_c: WaveletMatrix<Rank9SelIndex>,
162 pub aev_c: WaveletMatrix<Rank9SelIndex>,
163}
164
165impl<U> SuccinctArchive<U>
166where
167 U: Universe,
168{
169 pub fn iter<'a>(&'a self) -> impl Iterator<Item = Trible> + 'a {
170 (0..self.eav_c.len()).map(move |v_i| {
171 let v = self.eav_c.access(v_i).unwrap();
172 let a_i = self.v_a.select1(v).unwrap() - v + self.eav_c.rank(v_i, v).unwrap();
173 let a = self.vea_c.access(a_i).unwrap();
174 let e_i = self.a_a.select1(a).unwrap() - a + self.vea_c.rank(a_i, a).unwrap();
175 let e = self.ave_c.access(e_i).unwrap();
176
177 let e = self.domain.access(e);
178 let a = self.domain.access(a);
179 let v = self.domain.access(v);
180
181 let e: Id = Id::new(id_from_value(&e).unwrap()).unwrap();
182 let a: Id = Id::new(id_from_value(&a).unwrap()).unwrap();
183 let v: Value<UnknownValue> = Value::new(v);
184
185 Trible::force(&e, &a, &v)
186 })
187 }
188
189 pub fn distinct_in(
196 &self,
197 bv: &BitVector<Rank9SelIndex>,
198 range: &std::ops::Range<usize>,
199 ) -> usize {
200 bv.rank1(range.end).unwrap() - bv.rank1(range.start).unwrap()
201 }
202
203 pub fn enumerate_in<'a>(
211 &'a self,
212 bv: &'a BitVector<Rank9SelIndex>,
213 range: &std::ops::Range<usize>,
214 col: &'a WaveletMatrix<Rank9SelIndex>,
215 prefix: &'a BitVector<Rank9SelIndex>,
216 ) -> impl Iterator<Item = usize> + 'a {
217 let start = bv.rank1(range.start).unwrap();
218 let end = bv.rank1(range.end).unwrap();
219 (start..end).map(move |r| {
220 let idx = bv.select1(r).unwrap();
221 let val = col.access(idx).unwrap();
222 prefix.select1(val).unwrap() - val + col.rank(idx, val).unwrap()
223 })
224 }
225
226 pub fn enumerate_domain<'a>(
229 &'a self,
230 prefix: &'a BitVector<Rank9SelIndex>,
231 ) -> impl Iterator<Item = RawValue> + 'a {
232 let zero_count = prefix.num_bits() - (self.domain.len() + 1);
233 let mut z = 0usize;
234 std::iter::from_fn(move || {
235 if z >= zero_count {
236 return None;
237 }
238 let pos = prefix.select0(z).unwrap();
239 let id = prefix.rank1(pos).unwrap() - 1;
240 z = prefix.rank0(prefix.select1(id + 1).unwrap()).unwrap();
241 Some(self.domain.access(id))
242 })
243 }
244
245 pub fn meta(&self) -> SuccinctArchiveMeta<U::Meta>
246 where
247 U: Serializable,
248 {
249 SuccinctArchiveMeta {
250 entity_count: self.entity_count,
251 attribute_count: self.attribute_count,
252 value_count: self.value_count,
253 domain: self.domain.metadata(),
254 e_a: self.e_a.metadata(),
255 a_a: self.a_a.metadata(),
256 v_a: self.v_a.metadata(),
257 changed_e_a: self.changed_e_a.metadata(),
258 changed_e_v: self.changed_e_v.metadata(),
259 changed_a_e: self.changed_a_e.metadata(),
260 changed_a_v: self.changed_a_v.metadata(),
261 changed_v_e: self.changed_v_e.metadata(),
262 changed_v_a: self.changed_v_a.metadata(),
263 eav_c: self.eav_c.metadata(),
264 vea_c: self.vea_c.metadata(),
265 ave_c: self.ave_c.metadata(),
266 vae_c: self.vae_c.metadata(),
267 eva_c: self.eva_c.metadata(),
268 aev_c: self.aev_c.metadata(),
269 }
270 }
271}
272
273impl<U> From<&TribleSet> for SuccinctArchive<U>
274where
275 U: Universe + Serializable<Error = jerky::error::Error>,
276 <U as Serializable>::Meta: Clone,
277{
278 fn from(set: &TribleSet) -> Self {
279 let triple_count = set.eav.len() as usize;
280
281 let entity_count = set.eav.segmented_len(&[0; 0]) as usize;
282 let attribute_count = set.ave.segmented_len(&[0; 0]) as usize;
283 let value_count = set.vea.segmented_len(&[0; 0]) as usize;
284
285 let e_iter = set
286 .eav
287 .iter_prefix_count::<16>()
288 .map(|(e, _)| id_into_value(&e));
289 let a_iter = set
290 .ave
291 .iter_prefix_count::<16>()
292 .map(|(a, _)| id_into_value(&a));
293 let v_iter = set.vea.iter_prefix_count::<32>().map(|(v, _)| v);
294
295 let mut area = ByteArea::new().unwrap();
296 let mut sections = area.sections();
297
298 let domain_iter = e_iter.merge(a_iter).merge(v_iter).dedup();
299 let domain = U::with_sorted_dedup(domain_iter, &mut sections);
300
301 let e_a = build_prefix_bv(
302 domain.len(),
303 triple_count,
304 set.eav.iter_prefix_count::<16>().map(|(e, c)| {
305 (
306 domain.search(&id_into_value(&e)).expect("e in domain"),
307 c as usize,
308 )
309 }),
310 &mut sections,
311 );
312
313 let a_a = build_prefix_bv(
314 domain.len(),
315 triple_count,
316 set.ave.iter_prefix_count::<16>().map(|(a, c)| {
317 (
318 domain.search(&id_into_value(&a)).expect("a in domain"),
319 c as usize,
320 )
321 }),
322 &mut sections,
323 );
324
325 let v_a = build_prefix_bv(
326 domain.len(),
327 triple_count,
328 set.vea
329 .iter_prefix_count::<32>()
330 .map(|(v, c)| (domain.search(&v).expect("v in domain"), c as usize)),
331 &mut sections,
332 );
333
334 let eav_c = {
335 let mut builder =
336 WaveletMatrixBuilder::with_capacity(domain.len(), triple_count, &mut sections)
337 .unwrap();
338 let mut iter = set
339 .eav
340 .iter_prefix_count::<64>()
341 .map(|(t, _)| t[32..64].try_into().unwrap())
342 .map(|v| domain.search(&v).expect("v in domain"));
343 builder.set_ints_from_iter(0, &mut iter).unwrap();
344 builder.freeze::<Rank9SelIndex>().unwrap()
345 };
346
347 let vea_c = {
348 let mut builder =
349 WaveletMatrixBuilder::with_capacity(domain.len(), triple_count, &mut sections)
350 .unwrap();
351 let mut iter = set
352 .vea
353 .iter_prefix_count::<64>()
354 .map(|(t, _)| id_into_value(t[48..64].try_into().unwrap()))
355 .map(|a| domain.search(&a).expect("a in domain"));
356 builder.set_ints_from_iter(0, &mut iter).unwrap();
357 builder.freeze::<Rank9SelIndex>().unwrap()
358 };
359
360 let ave_c = {
361 let mut builder =
362 WaveletMatrixBuilder::with_capacity(domain.len(), triple_count, &mut sections)
363 .unwrap();
364 let mut iter = set
365 .ave
366 .iter_prefix_count::<64>()
367 .map(|(t, _)| id_into_value(t[48..64].try_into().unwrap()))
368 .map(|e| domain.search(&e).expect("e in domain"));
369 builder.set_ints_from_iter(0, &mut iter).unwrap();
370 builder.freeze::<Rank9SelIndex>().unwrap()
371 };
372
373 let vae_c = {
374 let mut builder =
375 WaveletMatrixBuilder::with_capacity(domain.len(), triple_count, &mut sections)
376 .unwrap();
377 let mut iter = set
378 .vae
379 .iter_prefix_count::<64>()
380 .map(|(t, _)| id_into_value(t[48..64].try_into().unwrap()))
381 .map(|e| domain.search(&e).expect("e in domain"));
382 builder.set_ints_from_iter(0, &mut iter).unwrap();
383 builder.freeze::<Rank9SelIndex>().unwrap()
384 };
385
386 let eva_c = {
387 let mut builder =
388 WaveletMatrixBuilder::with_capacity(domain.len(), triple_count, &mut sections)
389 .unwrap();
390 let mut iter = set
391 .eva
392 .iter_prefix_count::<64>()
393 .map(|(t, _)| id_into_value(t[48..64].try_into().unwrap()))
394 .map(|a| domain.search(&a).expect("a in domain"));
395 builder.set_ints_from_iter(0, &mut iter).unwrap();
396 builder.freeze::<Rank9SelIndex>().unwrap()
397 };
398
399 let aev_c = {
400 let mut builder =
401 WaveletMatrixBuilder::with_capacity(domain.len(), triple_count, &mut sections)
402 .unwrap();
403 let mut iter = set
404 .aev
405 .iter_prefix_count::<64>()
406 .map(|(t, _)| t[32..64].try_into().unwrap())
407 .map(|v| domain.search(&v).expect("v in domain"));
408 builder.set_ints_from_iter(0, &mut iter).unwrap();
409 builder.freeze::<Rank9SelIndex>().unwrap()
410 };
411
412 let changed_e_a = {
413 let mut b = BitVectorBuilder::with_capacity(triple_count, &mut sections).unwrap();
414 let mut bits = set.eav.iter_prefix_count::<32>().flat_map(|(_, c)| {
415 iter::once(true).chain(std::iter::repeat_n(false, c as usize - 1))
416 });
417 b.set_bits_from_iter(0, &mut bits).unwrap();
418 b.freeze::<Rank9SelIndex>()
419 };
420
421 let changed_e_v = {
422 let mut b = BitVectorBuilder::with_capacity(triple_count, &mut sections).unwrap();
423 let mut bits = set.eva.iter_prefix_count::<48>().flat_map(|(_, c)| {
424 iter::once(true).chain(std::iter::repeat_n(false, c as usize - 1))
425 });
426 b.set_bits_from_iter(0, &mut bits).unwrap();
427 b.freeze::<Rank9SelIndex>()
428 };
429
430 let changed_a_e = {
431 let mut b = BitVectorBuilder::with_capacity(triple_count, &mut sections).unwrap();
432 let mut bits = set.aev.iter_prefix_count::<32>().flat_map(|(_, c)| {
433 iter::once(true).chain(std::iter::repeat_n(false, c as usize - 1))
434 });
435 b.set_bits_from_iter(0, &mut bits).unwrap();
436 b.freeze::<Rank9SelIndex>()
437 };
438
439 let changed_a_v = {
440 let mut b = BitVectorBuilder::with_capacity(triple_count, &mut sections).unwrap();
441 let mut bits = set.ave.iter_prefix_count::<48>().flat_map(|(_, c)| {
442 iter::once(true).chain(std::iter::repeat_n(false, c as usize - 1))
443 });
444 b.set_bits_from_iter(0, &mut bits).unwrap();
445 b.freeze::<Rank9SelIndex>()
446 };
447
448 let changed_v_e = {
449 let mut b = BitVectorBuilder::with_capacity(triple_count, &mut sections).unwrap();
450 let mut bits = set.vea.iter_prefix_count::<48>().flat_map(|(_, c)| {
451 iter::once(true).chain(std::iter::repeat_n(false, c as usize - 1))
452 });
453 b.set_bits_from_iter(0, &mut bits).unwrap();
454 b.freeze::<Rank9SelIndex>()
455 };
456
457 let changed_v_a = {
458 let mut b = BitVectorBuilder::with_capacity(triple_count, &mut sections).unwrap();
459 let mut bits = set.vae.iter_prefix_count::<48>().flat_map(|(_, c)| {
460 iter::once(true).chain(std::iter::repeat_n(false, c as usize - 1))
461 });
462 b.set_bits_from_iter(0, &mut bits).unwrap();
463 b.freeze::<Rank9SelIndex>()
464 };
465
466 let meta = SuccinctArchiveMeta {
467 entity_count,
468 attribute_count,
469 value_count,
470 domain: domain.metadata(),
471 e_a: e_a.metadata(),
472 a_a: a_a.metadata(),
473 v_a: v_a.metadata(),
474 changed_e_a: changed_e_a.metadata(),
475 changed_e_v: changed_e_v.metadata(),
476 changed_a_e: changed_a_e.metadata(),
477 changed_a_v: changed_a_v.metadata(),
478 changed_v_e: changed_v_e.metadata(),
479 changed_v_a: changed_v_a.metadata(),
480 eav_c: eav_c.metadata(),
481 vea_c: vea_c.metadata(),
482 ave_c: ave_c.metadata(),
483 vae_c: vae_c.metadata(),
484 eva_c: eva_c.metadata(),
485 aev_c: aev_c.metadata(),
486 };
487
488 let mut meta_sec = sections.reserve::<SuccinctArchiveMeta<U::Meta>>(1).unwrap();
489 meta_sec.as_mut_slice()[0] = meta.clone();
490 meta_sec.freeze().unwrap();
491
492 let bytes = area.freeze().unwrap();
493
494 SuccinctArchive::from_bytes(meta, bytes).unwrap()
495 }
496}
497
498impl<U> From<&SuccinctArchive<U>> for TribleSet
499where
500 U: Universe,
501{
502 fn from(archive: &SuccinctArchive<U>) -> Self {
503 archive.iter().collect()
504 }
505}
506
507impl<U> TriblePattern for SuccinctArchive<U>
508where
509 U: Universe,
510{
511 type PatternConstraint<'a>
512 = SuccinctArchiveConstraint<'a, U>
513 where
514 U: 'a;
515
516 fn pattern<'a, V: ValueSchema>(
517 &'a self,
518 e: crate::query::Variable<GenId>,
519 a: crate::query::Variable<GenId>,
520 v: crate::query::Variable<V>,
521 ) -> Self::PatternConstraint<'a> {
522 SuccinctArchiveConstraint::new(e, a, v, self)
523 }
524}
525
526impl<U> Serializable for SuccinctArchive<U>
527where
528 U: Universe + Serializable<Error = jerky::error::Error>,
529{
530 type Meta = SuccinctArchiveMeta<U::Meta>;
531 type Error = jerky::error::Error;
532
533 fn metadata(&self) -> Self::Meta {
534 self.meta()
535 }
536
537 fn from_bytes(meta: Self::Meta, bytes: Bytes) -> Result<Self, Self::Error> {
538 let domain = U::from_bytes(meta.domain, bytes.clone())?;
539
540 let e_a = BitVector::from_bytes(meta.e_a, bytes.clone())?;
541 let a_a = BitVector::from_bytes(meta.a_a, bytes.clone())?;
542 let v_a = BitVector::from_bytes(meta.v_a, bytes.clone())?;
543 let changed_e_a = BitVector::from_bytes(meta.changed_e_a, bytes.clone())?;
544 let changed_e_v = BitVector::from_bytes(meta.changed_e_v, bytes.clone())?;
545 let changed_a_e = BitVector::from_bytes(meta.changed_a_e, bytes.clone())?;
546 let changed_a_v = BitVector::from_bytes(meta.changed_a_v, bytes.clone())?;
547 let changed_v_e = BitVector::from_bytes(meta.changed_v_e, bytes.clone())?;
548 let changed_v_a = BitVector::from_bytes(meta.changed_v_a, bytes.clone())?;
549
550 let eav_c = WaveletMatrix::from_bytes(meta.eav_c, bytes.clone())?;
551 let vea_c = WaveletMatrix::from_bytes(meta.vea_c, bytes.clone())?;
552 let ave_c = WaveletMatrix::from_bytes(meta.ave_c, bytes.clone())?;
553 let vae_c = WaveletMatrix::from_bytes(meta.vae_c, bytes.clone())?;
554 let eva_c = WaveletMatrix::from_bytes(meta.eva_c, bytes.clone())?;
555 let aev_c = WaveletMatrix::from_bytes(meta.aev_c, bytes.clone())?;
556
557 Ok(SuccinctArchive {
558 bytes,
559 domain,
560 entity_count: meta.entity_count,
561 attribute_count: meta.attribute_count,
562 value_count: meta.value_count,
563 e_a,
564 a_a,
565 v_a,
566 changed_e_a,
567 changed_e_v,
568 changed_a_e,
569 changed_a_v,
570 changed_v_e,
571 changed_v_a,
572 eav_c,
573 vea_c,
574 ave_c,
575 vae_c,
576 eva_c,
577 aev_c,
578 })
579 }
580}
581
582impl<U> ToBlob<SuccinctArchiveBlob> for &SuccinctArchive<U>
583where
584 U: Universe + Serializable,
585{
586 fn to_blob(self) -> Blob<SuccinctArchiveBlob> {
587 Blob::new(self.bytes.clone())
588 }
589}
590
591impl<U> ToBlob<SuccinctArchiveBlob> for SuccinctArchive<U>
592where
593 U: Universe + Serializable,
594{
595 fn to_blob(self) -> Blob<SuccinctArchiveBlob> {
596 Blob::new(self.bytes)
597 }
598}
599
600pub struct SuccinctArchiveError;
601
602impl std::error::Error for SuccinctArchiveError {}
603
604impl std::fmt::Display for SuccinctArchiveError {
605 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
606 write!(f, "SuccinctArchiveError")
607 }
608}
609
610impl std::fmt::Debug for SuccinctArchiveError {
611 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
612 write!(f, "SuccinctArchiveError")
613 }
614}
615
616impl<U> TryFromBlob<SuccinctArchiveBlob> for SuccinctArchive<U>
617where
618 U: Universe + Serializable<Error = jerky::error::Error>,
619 <U as Serializable>::Meta: Copy + 'static,
620{
621 type Error = SuccinctArchiveError;
622
623 fn try_from_blob(blob: Blob<SuccinctArchiveBlob>) -> Result<Self, Self::Error> {
624 let bytes = blob.bytes;
625 let mut tail = bytes.clone();
626 let meta = *tail
627 .view_suffix::<SuccinctArchiveMeta<U::Meta>>()
628 .map_err(|_| SuccinctArchiveError)?;
629 SuccinctArchive::from_bytes(meta, bytes).map_err(|_| SuccinctArchiveError)
630 }
631}
632
633#[cfg(test)]
634mod tests {
635 use std::convert::TryInto;
636
637 use crate::blob::ToBlob;
638 use crate::id::fucid;
639 use crate::prelude::*;
640 use crate::query::find;
641 use crate::trible::Trible;
642 use crate::value::ToValue;
643 use crate::value::TryToValue;
644
645 use super::*;
646 use anybytes::area::ByteArea;
647 use itertools::Itertools;
648 use proptest::prelude::*;
649
650 pub mod knights {
651 use crate::prelude::*;
652
653 attributes! {
654 "328edd7583de04e2bedd6bd4fd50e651" as loves: valueschemas::GenId;
655 "328147856cc1984f0806dbb824d2b4cb" as name: valueschemas::ShortString;
656 "328f2c33d2fdd675e733388770b2d6c4" as title: valueschemas::ShortString;
657 }
658 }
659
660 proptest! {
661 #[test]
662 fn create(entries in prop::collection::vec(prop::collection::vec(0u8..255, 64), 1..128)) {
663 let mut set = TribleSet::new();
664 for entry in entries {
665 let mut key = [0; 64];
666 key.iter_mut().set_from(entry.iter().cloned());
667 set.insert(&Trible{ data: key});
668 }
669
670 let _archive: SuccinctArchive<CompressedUniverse> = (&set).into();
671 }
672
673 #[test]
674 fn roundtrip(entries in prop::collection::vec(prop::collection::vec(0u8..255, 64), 1..128)) {
675 let mut set = TribleSet::new();
676 for entry in entries {
677 let mut key = [0; 64];
678 key.iter_mut().set_from(entry.iter().cloned());
679 set.insert(&Trible{ data: key});
680 }
681
682 let archive: SuccinctArchive<CompressedUniverse> = (&set).into();
683 let set_: TribleSet = (&archive).into();
684
685 assert_eq!(set, set_);
686 }
687
688 #[test]
689 fn ordered_universe(values in prop::collection::vec(prop::collection::vec(0u8..255, 32), 1..128)) {
690 let mut values: Vec<RawValue> = values.into_iter().map(|v| v.try_into().unwrap()).collect();
691 values.sort();
692 let mut area = ByteArea::new().unwrap();
693 let mut sections = area.sections();
694 let u = OrderedUniverse::with(values.iter().copied(), &mut sections);
695 drop(sections);
696 let _bytes = area.freeze().unwrap();
697 for i in 0..u.len() {
698 let original = values[i];
699 let reconstructed = u.access(i);
700 assert_eq!(original, reconstructed);
701 }
702 for i in 0..u.len() {
703 let original = Some(i);
704 let found = u.search(&values[i]);
705 assert_eq!(original, found);
706 }
707 }
708
709 #[test]
710 fn compressed_universe(values in prop::collection::vec(prop::collection::vec(0u8..255, 32), 1..128)) {
711 let mut values: Vec<RawValue> = values.into_iter().map(|v| v.try_into().unwrap()).collect();
712 values.sort();
713 let mut area = ByteArea::new().unwrap();
714 let mut sections = area.sections();
715 let u = CompressedUniverse::with(values.iter().copied(), &mut sections);
716 drop(sections);
717 let _bytes = area.freeze().unwrap();
718 for i in 0..u.len() {
719 let original = values[i];
720 let reconstructed = u.access(i);
721 assert_eq!(original, reconstructed);
722 }
723 for i in 0..u.len() {
724 let original = Some(i);
725 let found = u.search(&values[i]);
726 assert_eq!(original, found);
727 }
728 }
729 }
730
731 #[test]
732 fn archive_pattern() {
733 let juliet = fucid();
734 let romeo = fucid();
735
736 let mut kb = TribleSet::new();
737
738 kb += entity! { &juliet @
739 knights::name: "Juliet",
740 knights::loves: &romeo,
741 knights::title: "Maiden"
742 };
743 kb += entity! { &romeo @
744 knights::name: "Romeo",
745 knights::loves: &juliet,
746 knights::title: "Prince"
747 };
748 kb += entity! {
749 knights::name: "Angelica",
750 knights::title: "Nurse"
751 };
752
753 let archive: SuccinctArchive<OrderedUniverse> = (&kb).into();
754
755 let r: Vec<_> = find!(
756 (juliet, name),
757 pattern!(&archive, [
758 {knights::name: "Romeo",
759 knights::loves: ?juliet},
760 {?juliet @
761 knights::name: ?name
762 }])
763 )
764 .collect();
765 assert_eq!(
766 vec![((&juliet).to_value(), "Juliet".try_to_value().unwrap(),)],
767 r
768 );
769 }
770
771 #[test]
772 fn blob_roundtrip() {
773 let juliet = fucid();
774 let romeo = fucid();
775
776 let mut kb = TribleSet::new();
777
778 kb += entity! {&juliet @
779 knights::name: "Juliet",
780 knights::loves: &romeo,
781 knights::title: "Maiden"
782 };
783 kb += entity! {&romeo @
784 knights::name: "Romeo",
785 knights::loves: &juliet,
786 knights::title: "Prince"
787 };
788
789 let archive: SuccinctArchive<OrderedUniverse> = (&kb).into();
790 let blob = (&archive).to_blob();
791 let rebuilt: SuccinctArchive<OrderedUniverse> = blob.try_from_blob().unwrap();
792 let kb2: TribleSet = (&rebuilt).into();
793 assert_eq!(kb, kb2);
794 }
795}