1use core::cmp::Ordering;
158use core::ops::Bound;
159
160use yo_common::num::i64_digits;
161use yo_common::small::Small;
162use yo_common::{Code, Error, Result};
163use yo_kv::{Elements, Rank, Set, SetLimits, Slab, rank};
164
165use crate::head::Kind;
166use crate::read::Value;
167
168pub const KEY_MAX: usize = yo_kv::NAME_MAX - 1;
176
177const KEY_INLINE: usize = 32;
183
184const TAG_NULL: u8 = 0;
185const TAG_FALSE: u8 = 1;
186const TAG_TRUE: u8 = 2;
187const TAG_NUM: u8 = 3;
188const TAG_TEXT: u8 = 4;
189
190#[derive(Clone)]
198pub struct Key(Small<u8, KEY_INLINE>);
199
200impl Key {
201 #[must_use]
203 pub fn null() -> Key {
204 Key(Small::collect([TAG_NULL]))
205 }
206
207 #[must_use]
209 pub fn bool(v: bool) -> Key {
210 Key(Small::collect([if v { TAG_TRUE } else { TAG_FALSE }]))
211 }
212
213 #[must_use]
215 pub fn int(v: i64) -> Key {
216 let (neg, mant) = if v < 0 {
217 (true, v.unsigned_abs())
218 } else {
219 (false, v as u64)
220 };
221 number(Class::of(neg, mant == 0), mant, i32::from(bits(mant)))
222 }
223
224 #[must_use]
229 pub fn float(v: f64) -> Key {
230 if v.is_nan() {
231 return number(Class::Nan, 0, 0);
232 }
233 if v.is_infinite() {
234 return number(
235 if v.is_sign_negative() {
236 Class::NegInf
237 } else {
238 Class::PosInf
239 },
240 0,
241 0,
242 );
243 }
244 let raw = v.to_bits();
245 let neg = raw >> 63 == 1;
246 let exponent = ((raw >> 52) & 0x7ff) as i32;
247 let fraction = raw & ((1 << 52) - 1);
248 let (mant, scale) = if exponent == 0 {
251 (fraction, -1074)
252 } else {
253 (fraction | (1 << 52), exponent - 1075)
254 };
255 number(
256 Class::of(neg, mant == 0),
257 mant,
258 scale + i32::from(bits(mant)),
259 )
260 }
261
262 #[must_use]
264 pub fn text(v: &str) -> Key {
265 Key::text_bytes(v.as_bytes())
266 }
267
268 #[must_use]
270 pub fn text_bytes(v: &[u8]) -> Key {
271 let mut k = Small::collect([TAG_TEXT]);
272 for &b in v {
273 k.push(b);
274 }
275 Key(k)
276 }
277
278 #[must_use]
288 pub fn word(v: &str) -> Option<Key> {
289 let mut rest = v.as_bytes();
290 let word = next_word(&mut rest)?;
291 if next_word(&mut rest).is_some() {
292 return None;
293 }
294 Some(fold(word))
295 }
296
297 #[must_use]
300 pub fn of(v: Value<'_>) -> Option<Key> {
301 match v.kind() {
302 Kind::Null => Some(Key::null()),
303 Kind::Bool => Some(Key::bool(v.as_bool()?)),
304 Kind::Int => Some(Key::int(v.as_int()?)),
305 Kind::Float => Some(Key::float(v.as_float()?)),
306 Kind::Text => Some(Key::text_bytes(v.text_bytes()?)),
307 Kind::Array | Kind::Object => None,
308 }
309 }
310
311 #[must_use]
313 pub fn as_bytes(&self) -> &[u8] {
314 self.0.as_slice()
315 }
316
317 #[must_use]
319 pub fn is_too_long(&self) -> bool {
320 self.as_bytes().len() > KEY_MAX
321 }
322}
323
324impl PartialEq for Key {
325 fn eq(&self, other: &Key) -> bool {
326 self.as_bytes() == other.as_bytes()
327 }
328}
329
330impl Eq for Key {}
331
332impl core::fmt::Debug for Key {
333 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
334 let b = self.as_bytes();
335 match b.first() {
336 Some(&TAG_NULL) => f.write_str("null"),
337 Some(&TAG_FALSE) => f.write_str("false"),
338 Some(&TAG_TRUE) => f.write_str("true"),
339 Some(&TAG_TEXT) => write!(f, "{:?}", String::from_utf8_lossy(&b[1..])),
340 Some(&TAG_NUM) => write!(f, "{}", Hex(&b[1..])),
341 _ => f.write_str("<no key>"),
342 }
343 }
344}
345
346struct Hex<'a>(&'a [u8]);
349
350impl core::fmt::Display for Hex<'_> {
351 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
352 for b in self.0 {
353 write!(f, "{b:02x}")?;
354 }
355 Ok(())
356 }
357}
358
359#[derive(Debug, Clone, Copy, PartialEq, Eq)]
365enum Class {
366 NegInf = 0,
367 Negative = 1,
368 Zero = 2,
369 Positive = 3,
370 PosInf = 4,
371 Nan = 5,
375}
376
377impl Class {
378 fn of(neg: bool, zero: bool) -> Class {
379 match (zero, neg) {
380 (true, _) => Class::Zero,
381 (false, true) => Class::Negative,
382 (false, false) => Class::Positive,
383 }
384 }
385}
386
387fn bits(mant: u64) -> u16 {
389 (64 - mant.leading_zeros()) as u16
390}
391
392fn number(class: Class, mant: u64, place: i32) -> Key {
407 let mut k = Small::collect([TAG_NUM, class as u8]);
408 let (place, mant) = match class {
409 Class::Negative | Class::Positive => (place, mant << mant.leading_zeros()),
412 _ => (0, 0),
413 };
414 let place = ((place + 32768) as u16).to_be_bytes();
417 let flip = if class == Class::Negative { 0xff } else { 0 };
418 for b in place.into_iter().chain(mant.to_be_bytes()) {
419 k.push(b ^ flip);
420 }
421 Key(k)
422}
423
424#[derive(Debug, Clone, Copy, PartialEq, Eq)]
427pub enum IndexKind {
428 Equality,
430 Ordered,
433 Array,
436 Text,
439}
440
441impl IndexKind {
442 #[must_use]
444 pub fn is_ordered(self) -> bool {
445 self == IndexKind::Ordered
446 }
447
448 #[must_use]
450 pub fn is_multi(self) -> bool {
451 matches!(self, IndexKind::Array | IndexKind::Text)
452 }
453}
454
455#[derive(Debug, Clone, Copy)]
461pub(crate) struct TooLong;
462
463pub(crate) fn keys_at(
475 kind: IndexKind,
476 at: Value<'_>,
477 out: &mut Vec<u8>,
478) -> core::result::Result<(), TooLong> {
479 match kind {
480 IndexKind::Equality | IndexKind::Ordered => {
481 if let Some(key) = Key::of(at) {
482 push_key(&key, out)?;
483 }
484 }
485 IndexKind::Array => match at.kind() {
486 Kind::Array => {
491 for elem in at.iter() {
492 if let Some(key) = Key::of(elem) {
493 push_key(&key, out)?;
494 }
495 }
496 }
497 Kind::Object => {}
498 _ => {
499 if let Some(key) = Key::of(at) {
500 push_key(&key, out)?;
501 }
502 }
503 },
504 IndexKind::Text => {
505 if let Some(text) = at.text_bytes() {
506 let mut rest = text;
507 while let Some(word) = next_word(&mut rest) {
508 push_key(&fold(word), out)?;
509 }
510 }
511 }
512 }
513 Ok(())
514}
515
516fn push_key(key: &Key, out: &mut Vec<u8>) -> core::result::Result<(), TooLong> {
518 let bytes = key.as_bytes();
519 if key.is_too_long() {
520 return Err(TooLong);
521 }
522 let n = bytes.len() as u16;
524 out.extend_from_slice(&n.to_le_bytes());
525 out.extend_from_slice(bytes);
526 Ok(())
527}
528
529pub(crate) fn each_key(mut list: &[u8], mut f: impl FnMut(&[u8])) {
531 while list.len() >= 2 {
532 let n = usize::from(u16::from_le_bytes([list[0], list[1]]));
533 let Some(key) = list.get(2..2 + n) else {
534 return;
535 };
536 f(key);
537 list = &list[2 + n..];
538 }
539}
540
541fn fold(word: &[u8]) -> Key {
550 Key(Small::collect(
551 core::iter::once(TAG_TEXT).chain(word.iter().map(u8::to_ascii_lowercase)),
552 ))
553}
554
555fn next_word<'a>(rest: &mut &'a [u8]) -> Option<&'a [u8]> {
556 let start = rest.iter().position(|b| b.is_ascii_alphanumeric())?;
557 let after = rest[start..]
558 .iter()
559 .position(|b| !b.is_ascii_alphanumeric())
560 .map_or(rest.len(), |n| start + n);
561 let word = &rest[start..after];
562 *rest = &rest[after..];
563 Some(word)
564}
565
566#[derive(Debug)]
568pub struct PathIndex {
569 path: Box<[u8]>,
573 kind: IndexKind,
575 keys: Elements<u32>,
577 order: Option<Rank>,
585 posts: Slab<Set>,
589 postings: usize,
591}
592
593impl PathIndex {
594 pub(crate) fn new(path: &[u8], kind: IndexKind) -> PathIndex {
596 PathIndex {
597 path: path.into(),
598 kind,
599 keys: Elements::new(),
600 order: kind.is_ordered().then(Rank::new),
601 posts: Slab::new(),
602 postings: 0,
603 }
604 }
605
606 #[must_use]
608 pub fn path(&self) -> &[u8] {
609 &self.path
610 }
611
612 #[must_use]
614 pub fn kind(&self) -> IndexKind {
615 self.kind
616 }
617
618 pub(crate) fn keys_at(
620 &self,
621 at: Value<'_>,
622 out: &mut Vec<u8>,
623 ) -> core::result::Result<(), TooLong> {
624 keys_at(self.kind, at, out)
625 }
626
627 #[must_use]
629 pub fn len(&self) -> usize {
630 self.keys.len()
631 }
632
633 #[must_use]
635 pub fn is_empty(&self) -> bool {
636 self.keys.is_empty()
637 }
638
639 #[must_use]
645 pub fn postings(&self) -> usize {
646 self.postings
647 }
648
649 #[must_use]
654 pub fn get(&self, key: &Key) -> Option<&Set> {
655 self.posts.get(*self.keys.get(key.as_bytes())?)
656 }
657
658 #[must_use]
663 pub fn count(&self, key: &Key) -> usize {
664 self.get(key).map_or(0, Set::len)
665 }
666
667 #[must_use]
676 pub fn range(&self, lo: Bound<&Key>, hi: Bound<&Key>) -> Ranged<'_> {
677 let Some((order, start, left)) = self.span(lo, hi) else {
678 return Ranged {
679 index: self,
680 walk: None,
681 left: 0,
682 };
683 };
684 Ranged {
685 index: self,
686 walk: Some(order.iter_from(start)),
687 left,
688 }
689 }
690
691 #[must_use]
693 pub fn range_rev(&self, lo: Bound<&Key>, hi: Bound<&Key>) -> RangedRev<'_> {
694 let Some((order, start, left)) = self.span(lo, hi) else {
695 return RangedRev {
696 index: self,
697 walk: None,
698 left: 0,
699 };
700 };
701 RangedRev {
702 index: self,
703 walk: Some(order.iter_back_from(start + left - 1)),
704 left,
705 }
706 }
707
708 #[must_use]
713 pub fn count_in(&self, lo: Bound<&Key>, hi: Bound<&Key>) -> usize {
714 self.range(lo, hi).map(|(_, set)| set.len()).sum()
715 }
716
717 fn span(&self, lo: Bound<&Key>, hi: Bound<&Key>) -> Option<(&Rank, usize, usize)> {
720 let order = self.order.as_ref()?;
721 let keys = &self.keys;
722 let start = match lo {
723 Bound::Unbounded => 0,
724 Bound::Included(k) => rank_of(order, keys, k.as_bytes()),
725 Bound::Excluded(k) => rank_after(order, keys, k.as_bytes()),
726 };
727 let end = match hi {
728 Bound::Unbounded => keys.len(),
729 Bound::Included(k) => rank_after(order, keys, k.as_bytes()),
730 Bound::Excluded(k) => rank_of(order, keys, k.as_bytes()),
731 };
732 if end <= start {
733 return None;
734 }
735 Some((order, start, end - start))
736 }
737
738 pub(crate) fn add(&mut self, key: &[u8], id: &[u8]) -> Result<()> {
740 if let Some(&slot) = self.keys.get(key) {
741 let set = self.posts.get_mut(slot).expect("a row points at its list");
742 if set.add(id, &SetLimits::DEFAULT) {
743 self.postings += 1;
744 }
745 return Ok(());
746 }
747 let mut set = Set::new();
748 set.add(id, &SetLimits::DEFAULT);
749 let slot = self.posts.insert(set);
750 let row = self.keys.len() as u32;
751 if self.keys.insert(key, slot).is_err() {
752 self.posts.remove(slot);
753 return Err(Error::new(
754 Code::Full,
755 "the index cannot hold another distinct value",
756 ));
757 }
758 let PathIndex { keys, order, .. } = self;
759 if let Some(order) = order {
760 let at = rank_of(order, keys, key);
763 order.insert_at(at, row);
764 }
765 self.postings += 1;
766 Ok(())
767 }
768
769 pub(crate) fn take(&mut self, key: &[u8], id: &[u8]) {
771 let Some(row) = self.keys.index_of(key) else {
772 return;
773 };
774 let slot = *self.keys.at(row).expect("a row that was just found").1;
775 let set = self.posts.get_mut(slot).expect("a row points at its list");
776 if !set.remove(id) {
777 return;
778 }
779 self.postings -= 1;
780 if !set.is_empty() {
781 return;
782 }
783 self.posts.remove(slot);
784 self.untrack(key, row);
785 self.keys.remove_at(row);
786 }
787
788 fn untrack(&mut self, key: &[u8], row: usize) {
799 let PathIndex { keys, order, .. } = self;
800 let Some(order) = order else {
801 return;
802 };
803 let rank = rank_of(order, keys, key);
804 let last = keys.len() - 1;
805 let moved = if last == row {
806 None
807 } else {
808 let name = keys.at(last).expect("the last row").0;
809 Some(order.seek(|other| {
810 let (other_name, _) = keys.at(other as usize).expect("a row the tree holds");
811 name.cmp(other_name)
812 }))
813 };
814 order.remove_at(rank);
815 if let Some(at) = moved {
816 let at = if at > rank { at - 1 } else { at };
819 order.set_at(at, row as u32);
820 }
821 }
822
823 pub(crate) fn clear(&mut self) {
825 self.keys.clear();
826 self.posts.clear();
827 self.postings = 0;
828 if let Some(order) = &mut self.order {
829 *order = Rank::new();
830 }
831 }
832
833 #[must_use]
835 pub fn memory_bytes(&self) -> usize {
836 self.keys.memory_bytes()
837 + self.posts.slot_bytes()
838 + self.posts.iter().map(Set::memory_bytes).sum::<usize>()
839 + self.order.as_ref().map_or(0, Rank::bytes)
840 }
841}
842
843pub struct Ranged<'a> {
845 index: &'a PathIndex,
846 walk: Option<rank::Walk<'a>>,
847 left: usize,
848}
849
850impl<'a> Iterator for Ranged<'a> {
851 type Item = (&'a [u8], &'a Set);
852
853 fn next(&mut self) -> Option<(&'a [u8], &'a Set)> {
854 if self.left == 0 {
855 return None;
856 }
857 let row = self.walk.as_mut()?.next()?;
858 self.left -= 1;
859 entry(self.index, row)
860 }
861
862 fn size_hint(&self) -> (usize, Option<usize>) {
863 (self.left, Some(self.left))
864 }
865}
866
867impl ExactSizeIterator for Ranged<'_> {}
868
869pub struct RangedRev<'a> {
872 index: &'a PathIndex,
873 walk: Option<rank::Back<'a>>,
874 left: usize,
875}
876
877impl<'a> Iterator for RangedRev<'a> {
878 type Item = (&'a [u8], &'a Set);
879
880 fn next(&mut self) -> Option<(&'a [u8], &'a Set)> {
881 if self.left == 0 {
882 return None;
883 }
884 let row = self.walk.as_mut()?.next()?;
885 self.left -= 1;
886 entry(self.index, row)
887 }
888
889 fn size_hint(&self) -> (usize, Option<usize>) {
890 (self.left, Some(self.left))
891 }
892}
893
894impl ExactSizeIterator for RangedRev<'_> {}
895
896fn rank_of(order: &Rank, keys: &Elements<u32>, key: &[u8]) -> usize {
903 order.seek(|row| {
904 let (name, _) = keys.at(row as usize).expect("a row the tree holds");
905 key.cmp(name)
906 })
907}
908
909fn rank_after(order: &Rank, keys: &Elements<u32>, key: &[u8]) -> usize {
912 order.seek(|row| {
913 let (name, _) = keys.at(row as usize).expect("a row the tree holds");
914 match key.cmp(name) {
915 Ordering::Less => Ordering::Less,
916 Ordering::Equal | Ordering::Greater => Ordering::Greater,
917 }
918 })
919}
920
921fn entry(index: &PathIndex, row: u32) -> Option<(&[u8], &Set)> {
923 let (name, &slot) = index.keys.at(row as usize)?;
924 Some((name, index.posts.get(slot)?))
925}
926
927pub(crate) fn each_id(set: &Set, mut f: impl FnMut(&[u8])) -> usize {
933 let mut digits = [0u8; yo_common::num::DIGITS_MAX];
934 let mut n = 0usize;
935 for member in set.iter() {
936 match member {
937 yo_kv::listpack::Entry::Str(s) => f(s),
938 yo_kv::listpack::Entry::Int(v) => f(i64_digits(&mut digits, v)),
939 }
940 n += 1;
941 }
942 n
943}
944
945#[cfg(test)]
946mod tests {
947 use super::*;
948
949 fn taken(kind: IndexKind, build: impl FnOnce(&mut crate::Builder)) -> Vec<String> {
951 let mut b = crate::Builder::new();
952 build(&mut b);
953 let bytes = b.finish().expect("built").to_vec();
954 let value = Value::new(&bytes).expect("readable");
955 let mut list = Vec::new();
956 keys_at(kind, value, &mut list).expect("short enough");
957 let mut out = Vec::new();
958 each_key(&list, |key| {
959 out.push(format!("{:?}", Key(Small::collect(key.iter().copied()))))
960 });
961 out
962 }
963
964 #[test]
965 fn an_array_index_takes_one_key_per_element() {
966 let keys = taken(IndexKind::Array, |b| {
967 b.begin_array().expect("open");
968 b.text("red").expect("value");
969 b.int(7).expect("value");
970 b.begin_object().expect("open");
971 b.end_object().expect("close");
972 b.end_array().expect("close");
973 });
974 assert_eq!(keys.len(), 2, "the object inside is not a key: {keys:?}");
975 assert_eq!(keys[0], "\"red\"");
976
977 assert_eq!(
979 taken(IndexKind::Array, |b| b.text("red").expect("v")).len(),
980 1
981 );
982 assert_eq!(
983 taken(IndexKind::Array, |b| {
984 b.begin_object().expect("open");
985 b.end_object().expect("close");
986 })
987 .len(),
988 0
989 );
990 }
991
992 #[test]
993 fn a_text_index_splits_on_everything_that_is_not_a_letter_or_a_digit() {
994 let keys = taken(IndexKind::Text, |b| {
995 b.text(" The RED car, model 3! ").expect("value")
996 });
997 assert_eq!(
998 keys,
999 ["\"the\"", "\"red\"", "\"car\"", "\"model\"", "\"3\""]
1000 );
1001
1002 assert!(taken(IndexKind::Text, |b| b.text("!!! ...").expect("v")).is_empty());
1003 assert!(taken(IndexKind::Text, |b| b.int(7).expect("v")).is_empty());
1004 }
1005
1006 #[test]
1007 fn a_word_key_is_what_a_text_index_filed_and_a_phrase_is_not_one() {
1008 assert_eq!(Key::word("RED"), Key::word("red"));
1009 assert_eq!(Key::word("red!"), Key::word("red"));
1010 assert!(Key::word("red car").is_none(), "a phrase is two words");
1011 assert!(Key::word("").is_none());
1012 assert!(Key::word("!!!").is_none());
1013 assert_eq!(
1014 Key::word("red").expect("a word"),
1015 Key::text("red"),
1016 "a word that needs no folding is the string key, and there is no \
1017 second text tag to keep them apart"
1018 );
1019 assert_ne!(Key::word("RED").expect("a word"), Key::text("RED"));
1020 }
1021
1022 #[test]
1023 fn a_key_list_reads_back_exactly_what_went_into_it() {
1024 let mut list = Vec::new();
1025 push_key(&Key::text("red"), &mut list).expect("short");
1026 push_key(&Key::int(7), &mut list).expect("short");
1027 push_key(&Key::null(), &mut list).expect("short");
1028 let mut out = Vec::new();
1029 each_key(&list, |key| out.push(key.to_vec()));
1030 assert_eq!(
1031 out,
1032 [
1033 Key::text("red").as_bytes().to_vec(),
1034 Key::int(7).as_bytes().to_vec(),
1035 Key::null().as_bytes().to_vec(),
1036 ]
1037 );
1038
1039 let long = "x".repeat(KEY_MAX);
1040 assert!(push_key(&Key::text(&long), &mut list).is_err());
1041 }
1042
1043 #[test]
1044 fn a_number_and_the_string_of_it_are_different_keys() {
1045 assert_ne!(Key::int(7), Key::text("7"));
1046 assert_ne!(Key::null(), Key::text(""));
1047 assert_ne!(Key::bool(true), Key::int(1));
1048 }
1049
1050 #[test]
1051 fn a_float_that_names_a_whole_number_is_that_number() {
1052 assert_eq!(Key::float(7.0), Key::int(7));
1053 assert_eq!(Key::float(-0.0), Key::int(0));
1054 assert_eq!(Key::float(-3.0), Key::int(-3));
1055 assert_ne!(Key::float(7.5), Key::int(7));
1056 assert_ne!(Key::float(1e30), Key::int(i64::MAX));
1057 assert_ne!(Key::float(f64::NAN), Key::float(0.0));
1058 }
1059
1060 #[test]
1061 fn numbers_sort_as_bytes_the_way_they_sort_as_numbers() {
1062 let mut ns = [0i64, -1, i64::MIN, i64::MAX, 7, -7, 1 << 40];
1063 let mut keys: Vec<Key> = ns.iter().map(|&n| Key::int(n)).collect();
1064 ns.sort_unstable();
1065 keys.sort_by(|a, b| a.as_bytes().cmp(b.as_bytes()));
1066 let want: Vec<Key> = ns.iter().map(|&n| Key::int(n)).collect();
1067 assert_eq!(keys, want);
1068
1069 let mut fs = [0.5f64, -0.5, -1.5, 1e300, -1e300, f64::MIN_POSITIVE];
1070 let mut keys: Vec<Key> = fs.iter().map(|&f| Key::float(f)).collect();
1071 fs.sort_by(f64::total_cmp);
1072 keys.sort_by(|a, b| a.as_bytes().cmp(b.as_bytes()));
1073 let want: Vec<Key> = fs.iter().map(|&f| Key::float(f)).collect();
1074 assert_eq!(keys, want);
1075 }
1076
1077 #[test]
1078 fn an_integer_and_a_float_sort_among_each_other() {
1079 let mut mixed: Vec<Key> = [
1083 Key::float(12.5),
1084 Key::int(99),
1085 Key::int(-3),
1086 Key::float(-2.5),
1087 Key::int(0),
1088 Key::float(0.25),
1089 Key::int(13),
1090 ]
1091 .to_vec();
1092 mixed.sort_by(|a, b| a.as_bytes().cmp(b.as_bytes()));
1093 let want = [
1094 Key::int(-3),
1095 Key::float(-2.5),
1096 Key::int(0),
1097 Key::float(0.25),
1098 Key::float(12.5),
1099 Key::int(13),
1100 Key::int(99),
1101 ];
1102 assert_eq!(mixed, want);
1103 }
1104
1105 #[test]
1106 fn seven_and_seven_point_zero_are_one_key() {
1107 assert_eq!(Key::int(7), Key::float(7.0));
1108 assert_eq!(Key::int(-7), Key::float(-7.0));
1109 assert_eq!(Key::int(0), Key::float(0.0));
1110 assert_eq!(Key::int(0), Key::float(-0.0));
1113 assert_eq!(Key::int(1 << 53), Key::float((1u64 << 53) as f64));
1114 assert_ne!(Key::int(i64::MAX), Key::float(i64::MAX as f64));
1118 }
1119
1120 #[test]
1121 fn the_ends_of_the_number_line_sort_where_they_belong() {
1122 let mut ends = [
1123 Key::float(f64::NAN),
1124 Key::float(f64::INFINITY),
1125 Key::int(1),
1126 Key::float(f64::NEG_INFINITY),
1127 Key::int(-1),
1128 Key::float(f64::MIN),
1129 Key::float(f64::MAX),
1130 ]
1131 .to_vec();
1132 ends.sort_by(|a, b| a.as_bytes().cmp(b.as_bytes()));
1133 let want = [
1134 Key::float(f64::NEG_INFINITY),
1135 Key::float(f64::MIN),
1136 Key::int(-1),
1137 Key::int(1),
1138 Key::float(f64::MAX),
1139 Key::float(f64::INFINITY),
1140 Key::float(f64::NAN),
1142 ];
1143 assert_eq!(ends, want);
1144 }
1145
1146 #[test]
1147 fn every_number_is_the_same_width() {
1148 for k in [
1149 Key::int(0),
1150 Key::int(i64::MIN),
1151 Key::float(1e300),
1152 Key::float(f64::MIN_POSITIVE),
1153 Key::float(f64::NAN),
1154 Key::float(f64::NEG_INFINITY),
1155 ] {
1156 assert_eq!(k.as_bytes().len(), 12, "{k:?}");
1157 }
1158 }
1159
1160 #[test]
1161 fn a_short_key_stays_off_the_heap() {
1162 assert!(Key::int(i64::MIN).0.is_inline());
1163 assert!(Key::text("a-fairly-ordinary-status").0.is_inline());
1164 assert!(!Key::text(&"x".repeat(64)).0.is_inline());
1165 }
1166
1167 #[test]
1168 fn a_key_prints_as_what_it_is() {
1169 assert_eq!(format!("{:?}", Key::null()), "null");
1170 assert_eq!(format!("{:?}", Key::bool(true)), "true");
1171 assert_eq!(format!("{:?}", Key::text("open")), "\"open\"");
1172 assert_eq!(format!("{:?}", Key::int(0)), "0280000000000000000000");
1175 }
1176
1177 fn ordered(ns: impl IntoIterator<Item = i64>) -> PathIndex {
1180 let mut index = PathIndex::new(b"$.n", IndexKind::Ordered);
1181 for n in ns {
1182 index
1183 .add(Key::int(n).as_bytes(), n.to_string().as_bytes())
1184 .expect("room");
1185 }
1186 index
1187 }
1188
1189 fn walked(index: &PathIndex, lo: Bound<&Key>, hi: Bound<&Key>) -> Vec<i64> {
1191 let out: Vec<i64> = index.range(lo, hi).map(|(k, _)| unorder_int(k)).collect();
1192 let mut back: Vec<i64> = index
1193 .range_rev(lo, hi)
1194 .map(|(k, _)| unorder_int(k))
1195 .collect();
1196 back.reverse();
1197 assert_eq!(out, back, "backwards is forwards read the other way");
1198 out
1199 }
1200
1201 fn unorder_int(key: &[u8]) -> i64 {
1204 assert_eq!(key[0], TAG_NUM, "these tests only file numbers");
1205 let class = key[1];
1206 if class == Class::Zero as u8 {
1207 return 0;
1208 }
1209 let flip = if class == Class::Negative as u8 {
1210 0xffu8
1211 } else {
1212 0
1213 };
1214 let place = u16::from_be_bytes([key[2] ^ flip, key[3] ^ flip]) as i32 - 32768;
1215 let mut mant = [0u8; 8];
1216 for (out, b) in mant.iter_mut().zip(&key[4..12]) {
1217 *out = b ^ flip;
1218 }
1219 let n = (u64::from_be_bytes(mant) >> (64 - place)) as i64;
1222 if flip == 0 { n } else { -n }
1223 }
1224
1225 #[test]
1226 fn an_ordered_index_walks_its_keys_in_order() {
1227 let index = ordered((0..500i64).map(|i| (i * 137) % 500 - 250));
1230 assert_eq!(index.len(), 500);
1231 assert_eq!(index.kind(), IndexKind::Ordered);
1232
1233 let all = walked(&index, Bound::Unbounded, Bound::Unbounded);
1234 assert_eq!(all, (-250..250).collect::<Vec<i64>>());
1235
1236 let (lo, hi) = (Key::int(-3), Key::int(4));
1237 assert_eq!(
1238 walked(&index, Bound::Included(&lo), Bound::Excluded(&hi)),
1239 [-3, -2, -1, 0, 1, 2, 3]
1240 );
1241 assert_eq!(
1242 walked(&index, Bound::Excluded(&lo), Bound::Included(&hi)),
1243 [-2, -1, 0, 1, 2, 3, 4]
1244 );
1245 assert_eq!(
1246 walked(&index, Bound::Unbounded, Bound::Excluded(&Key::int(-247))),
1247 [-250, -249, -248]
1248 );
1249 assert_eq!(
1250 walked(&index, Bound::Included(&Key::int(247)), Bound::Unbounded),
1251 [247, 248, 249]
1252 );
1253 }
1254
1255 #[test]
1256 fn a_range_that_names_nothing_is_empty_rather_than_wrong() {
1257 let index = ordered([10i64, 20, 30]);
1258 let (lo, hi) = (Key::int(20), Key::int(20));
1259 assert!(walked(&index, Bound::Excluded(&lo), Bound::Excluded(&hi)).is_empty());
1260 assert_eq!(
1261 walked(&index, Bound::Included(&lo), Bound::Included(&hi)),
1262 [20]
1263 );
1264 assert!(
1266 walked(
1267 &index,
1268 Bound::Included(&Key::int(30)),
1269 Bound::Excluded(&Key::int(10))
1270 )
1271 .is_empty()
1272 );
1273 assert!(
1275 walked(
1276 &index,
1277 Bound::Included(&Key::int(21)),
1278 Bound::Excluded(&Key::int(29))
1279 )
1280 .is_empty()
1281 );
1282 assert!(walked(&index, Bound::Included(&Key::int(31)), Bound::Unbounded).is_empty());
1283 assert!(walked(&index, Bound::Unbounded, Bound::Excluded(&Key::int(10))).is_empty());
1284 assert_eq!(index.count_in(Bound::Unbounded, Bound::Unbounded), 3);
1285 }
1286
1287 #[test]
1288 fn an_equality_index_has_no_range_and_says_so_by_being_empty() {
1289 let mut index = PathIndex::new(b"$.n", IndexKind::Equality);
1290 index.add(Key::int(1).as_bytes(), b"a").expect("room");
1291 assert_eq!(index.kind(), IndexKind::Equality);
1292 assert_eq!(index.range(Bound::Unbounded, Bound::Unbounded).count(), 0);
1293 assert_eq!(index.count_in(Bound::Unbounded, Bound::Unbounded), 0);
1294 assert_eq!(index.count(&Key::int(1)), 1, "equality still works");
1295 }
1296
1297 #[test]
1298 fn removing_keys_from_an_ordered_index_keeps_the_rest_in_order() {
1299 let mut index = ordered(0..200i64);
1303 for n in (0..200i64).step_by(3) {
1304 index.take(Key::int(n).as_bytes(), n.to_string().as_bytes());
1305 }
1306 let left: Vec<i64> = (0..200i64).filter(|n| n % 3 != 0).collect();
1307 assert_eq!(index.len(), left.len());
1308 assert_eq!(walked(&index, Bound::Unbounded, Bound::Unbounded), left);
1309
1310 for n in &left {
1312 assert_eq!(index.count(&Key::int(*n)), 1, "{n} lost its list");
1313 }
1314 for n in (0..200i64).step_by(3) {
1315 assert_eq!(index.count(&Key::int(n)), 0, "{n} kept one");
1316 }
1317 }
1318
1319 #[test]
1320 fn an_ordered_index_that_is_emptied_and_refilled_is_still_ordered() {
1321 let mut index = ordered(0..64i64);
1322 for n in 0..64i64 {
1323 index.take(Key::int(n).as_bytes(), n.to_string().as_bytes());
1324 }
1325 assert!(index.is_empty());
1326 assert_eq!(index.postings(), 0);
1327 assert!(walked(&index, Bound::Unbounded, Bound::Unbounded).is_empty());
1328
1329 for n in (0..32i64).rev() {
1330 index
1331 .add(Key::int(n).as_bytes(), n.to_string().as_bytes())
1332 .expect("room");
1333 }
1334 assert_eq!(
1335 walked(&index, Bound::Unbounded, Bound::Unbounded),
1336 (0..32).collect::<Vec<i64>>()
1337 );
1338
1339 index.clear();
1340 assert_eq!(index.kind(), IndexKind::Ordered, "a clear keeps the kind");
1341 assert!(index.is_empty());
1342 index.add(Key::int(9).as_bytes(), b"9").expect("room");
1343 assert_eq!(walked(&index, Bound::Unbounded, Bound::Unbounded), [9]);
1344 }
1345
1346 #[test]
1347 fn a_key_with_many_documents_counts_once_in_the_order() {
1348 let mut index = PathIndex::new(b"$.n", IndexKind::Ordered);
1349 for i in 0..100 {
1350 index
1351 .add(
1352 Key::int(i64::from(i % 5)).as_bytes(),
1353 format!("d{i}").as_bytes(),
1354 )
1355 .expect("room");
1356 }
1357 assert_eq!(index.len(), 5, "five distinct values");
1358 assert_eq!(index.postings(), 100);
1359 assert_eq!(
1360 walked(&index, Bound::Unbounded, Bound::Unbounded),
1361 [0, 1, 2, 3, 4]
1362 );
1363 assert_eq!(index.count_in(Bound::Unbounded, Bound::Unbounded), 100);
1364 assert_eq!(
1365 index.count_in(Bound::Included(&Key::int(1)), Bound::Included(&Key::int(2))),
1366 40
1367 );
1368 }
1369
1370 #[test]
1371 fn the_last_document_under_a_key_takes_the_key_with_it() {
1372 let mut index = PathIndex::new(b"$.status", IndexKind::Equality);
1373 let open = Key::text("open");
1374 index.add(open.as_bytes(), b"a").expect("room");
1375 index.add(open.as_bytes(), b"b").expect("room");
1376 assert_eq!(index.len(), 1);
1377 assert_eq!(index.postings(), 2);
1378 assert_eq!(index.count(&open), 2);
1379
1380 index.take(open.as_bytes(), b"a");
1381 assert_eq!(index.postings(), 1);
1382 assert_eq!(index.len(), 1);
1383 index.take(open.as_bytes(), b"b");
1384 assert_eq!(index.postings(), 0);
1385 assert!(index.is_empty(), "an empty posting list is not a key");
1386 assert_eq!(index.count(&open), 0);
1387 }
1388
1389 #[test]
1390 fn filing_the_same_document_twice_files_it_once() {
1391 let mut index = PathIndex::new(b"$.status", IndexKind::Equality);
1392 let open = Key::text("open");
1393 index.add(open.as_bytes(), b"a").expect("room");
1394 index.add(open.as_bytes(), b"a").expect("room");
1395 assert_eq!(index.postings(), 1);
1396 index.take(open.as_bytes(), b"a");
1397 assert_eq!(index.postings(), 0);
1398 }
1399
1400 #[test]
1401 fn taking_out_something_that_was_never_filed_changes_nothing() {
1402 let mut index = PathIndex::new(b"$.status", IndexKind::Equality);
1403 let open = Key::text("open");
1404 index.add(open.as_bytes(), b"a").expect("room");
1405 index.take(open.as_bytes(), b"never");
1406 index.take(Key::text("shut").as_bytes(), b"a");
1407 assert_eq!(index.postings(), 1);
1408 assert_eq!(index.count(&open), 1);
1409 }
1410
1411 #[test]
1412 fn a_posting_list_of_numbers_reads_back_as_bytes() {
1413 let mut index = PathIndex::new(b"$.customer", IndexKind::Equality);
1414 let key = Key::int(4);
1415 for id in ["11", "2", "333"] {
1416 index.add(key.as_bytes(), id.as_bytes()).expect("room");
1417 }
1418 let mut got = Vec::new();
1419 let n = each_id(index.get(&key).expect("filed"), |id| {
1420 got.push(String::from_utf8_lossy(id).into_owned());
1421 });
1422 assert_eq!(n, 3);
1423 got.sort();
1424 assert_eq!(got, ["11", "2", "333"]);
1425 }
1426}