1use yo_common::{Code, Error, Result};
25
26use crate::db::Db;
27use crate::keyspace::Keyspace;
28use crate::list::{Element, List};
29use crate::strings;
30use crate::value::{self, Kind};
31
32const NO_KEY: &str = "no such key";
36
37const OUT_OF_RANGE: &str = "index out of range";
39
40const ZERO_RANK: &str = "RANK can't be zero: use 1 to start from the first match, 2 from the second ... or use negative to start from the end of the list";
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum End {
55 Left,
57 Right,
59}
60
61impl End {
62 #[inline]
64 #[must_use]
65 pub const fn is_left(self) -> bool {
66 matches!(self, End::Left)
67 }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum Order {
80 OneByOne,
84 Bulk,
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
100pub struct Movem {
101 pub from: End,
103 pub to: End,
105 pub count: usize,
107 pub exactly: bool,
109 pub order: Order,
111}
112
113impl Keyspace {
114 pub fn push<'v>(
125 &mut self,
126 key: &[u8],
127 end: End,
128 values: impl Iterator<Item = &'v [u8]> + Clone,
129 ) -> Result<usize> {
130 for v in values.clone() {
131 strings::check_len(key, v.len())?;
132 }
133 let at = match self.list_slot(key)? {
134 Some(at) => at,
135 None => {
136 if values.clone().next().is_none() {
141 return Ok(0);
142 }
143 self.new_list(key)
144 }
145 };
146 let limits = self.list_limits;
147 let list = self
148 .lists
149 .get_mut(at)
150 .expect("the record points at its body");
151 for v in values {
152 if end.is_left() {
153 list.push_front(v, &limits);
154 } else {
155 list.push_back(v, &limits);
156 }
157 }
158 Ok(list.len())
159 }
160
161 pub fn pushx<'v>(
166 &mut self,
167 key: &[u8],
168 end: End,
169 values: impl Iterator<Item = &'v [u8]> + Clone,
170 ) -> Result<usize> {
171 if self.list_slot(key)?.is_none() {
172 return Ok(0);
173 }
174 self.push(key, end, values)
175 }
176
177 pub fn pop(&mut self, key: &[u8], end: End) -> Result<Option<Vec<u8>>> {
184 let Some(at) = self.list_slot(key)? else {
185 return Ok(None);
186 };
187 let limits = self.list_limits;
188 let list = self
189 .lists
190 .get_mut(at)
191 .expect("the record points at its body");
192 let got = if end.is_left() {
193 list.pop_front(&limits)
194 } else {
195 list.pop_back(&limits)
196 };
197 if list.is_empty() {
198 self.drop_key(key);
199 }
200 Ok(got)
201 }
202
203 pub fn pop_into<F>(&mut self, key: &[u8], end: End, count: usize, mut f: F) -> Result<usize>
213 where
214 F: FnMut(Element<'_>),
215 {
216 let Some(at) = self.list_slot(key)? else {
217 return Ok(0);
218 };
219 let limits = self.list_limits;
220 let list = self
221 .lists
222 .get_mut(at)
223 .expect("the record points at its body");
224 let take = count.min(list.len());
225 for _ in 0..take {
226 let e = if end.is_left() {
231 list.front()
232 } else {
233 list.back()
234 };
235 f(e.expect("a list shorter than it says it is"));
236 if end.is_left() {
237 list.drop_front(&limits);
238 } else {
239 list.drop_back(&limits);
240 }
241 }
242 if list.is_empty() {
243 self.drop_key(key);
244 }
245 Ok(take)
246 }
247
248 pub fn llen(&mut self, key: &[u8]) -> Result<usize> {
250 Ok(match self.list_slot(key)? {
251 Some(at) => self.list_at(at).len(),
252 None => 0,
253 })
254 }
255
256 pub fn lindex(&mut self, key: &[u8], index: i64) -> Result<Option<Element<'_>>> {
258 let Some(slot) = self.list_slot(key)? else {
259 return Ok(None);
260 };
261 let list = self.list_at(slot);
262 Ok(at(index, list.len()).and_then(|i| list.get(i)))
263 }
264
265 pub fn lrange(
273 &mut self,
274 key: &[u8],
275 start: i64,
276 stop: i64,
277 ) -> Result<impl Iterator<Item = Element<'_>>> {
278 let slot = self.list_slot(key)?;
279 let list = slot.map(|at| self.list_at(at));
280 let (from, count) = match list {
281 Some(l) => window(start, stop, l.len()),
282 None => (0, 0),
283 };
284 Ok(list
285 .into_iter()
286 .flat_map(move |l| l.range(from, count))
287 .take(count))
288 }
289
290 pub fn lset(&mut self, key: &[u8], index: i64, value: &[u8]) -> Result<()> {
297 strings::check_len(key, value.len())?;
298 let Some(slot) = self.list_slot(key)? else {
299 return Err(Error::new(Code::Invalid, NO_KEY));
300 };
301 let limits = self.list_limits;
302 let list = self
303 .lists
304 .get_mut(slot)
305 .expect("the record points at its body");
306 let Some(i) = at(index, list.len()) else {
307 return Err(Error::new(Code::Invalid, OUT_OF_RANGE));
308 };
309 if !list.set(i, value, &limits) {
310 return Err(Error::new(Code::Invalid, OUT_OF_RANGE));
311 }
312 Ok(())
313 }
314
315 pub fn linsert(&mut self, key: &[u8], before: bool, pivot: &[u8], value: &[u8]) -> Result<i64> {
321 strings::check_len(key, value.len())?;
322 let Some(slot) = self.list_slot(key)? else {
323 return Ok(0);
324 };
325 let limits = self.list_limits;
326 let list = self
327 .lists
328 .get_mut(slot)
329 .expect("the record points at its body");
330 Ok(match list.insert_at_pivot(pivot, value, before, &limits) {
331 Some(len) => len as i64,
332 None => -1,
333 })
334 }
335
336 pub fn lrem(&mut self, key: &[u8], count: i64, value: &[u8]) -> Result<usize> {
342 let Some(slot) = self.list_slot(key)? else {
343 return Ok(0);
344 };
345 let limits = self.list_limits;
346 let list = self
347 .lists
348 .get_mut(slot)
349 .expect("the record points at its body");
350 let gone = list.remove(count, value, &limits);
351 if list.is_empty() {
352 self.drop_key(key);
353 }
354 Ok(gone)
355 }
356
357 pub fn ltrim(&mut self, key: &[u8], start: i64, stop: i64) -> Result<()> {
362 let Some(slot) = self.list_slot(key)? else {
363 return Ok(());
364 };
365 let limits = self.list_limits;
366 let list = self
367 .lists
368 .get_mut(slot)
369 .expect("the record points at its body");
370 let (from, count) = window(start, stop, list.len());
371 list.trim(from, count, &limits);
372 if list.is_empty() {
373 self.drop_key(key);
374 }
375 Ok(())
376 }
377
378 pub fn lpos(
391 &mut self,
392 key: &[u8],
393 value: &[u8],
394 rank: i64,
395 count: usize,
396 maxlen: usize,
397 out: &mut Vec<usize>,
398 ) -> Result<()> {
399 out.clear();
400 if rank == 0 {
401 return Err(Error::new(Code::Invalid, ZERO_RANK));
402 }
403 self.lpos_into(key, value, rank, count, maxlen, |at| out.push(at))?;
404 Ok(())
405 }
406
407 pub fn lpos_into<F>(
418 &mut self,
419 key: &[u8],
420 value: &[u8],
421 rank: i64,
422 count: usize,
423 maxlen: usize,
424 mut found: F,
425 ) -> Result<usize>
426 where
427 F: FnMut(usize),
428 {
429 if rank == 0 {
430 return Err(Error::new(Code::Invalid, ZERO_RANK));
431 }
432 let Some(slot) = self.list_slot(key)? else {
433 return Ok(0);
434 };
435 Ok(self
436 .list_at(slot)
437 .positions(value, rank, count, maxlen, &mut found))
438 }
439
440 pub fn lmove(&mut self, src: &[u8], dst: &[u8], from: End, to: End) -> Result<Option<&[u8]>> {
465 self.list_slot(dst)?;
469 let mut buf = std::mem::take(&mut self.scratch);
474 buf.clear();
475 let took = self.pop_into(src, from, 1, |e| e.write_to(&mut buf));
476 let moved = match took {
477 Ok(n) => n,
478 Err(e) => {
479 self.scratch = buf;
480 return Err(e);
481 }
482 };
483 if moved == 0 {
484 self.scratch = buf;
485 return Ok(None);
486 }
487 let pushed = self.push(dst, to, std::iter::once(buf.as_slice()));
488 self.scratch = buf;
489 pushed?;
490 Ok(Some(&self.scratch))
491 }
492
493 pub fn lmovem<F>(&mut self, src: &[u8], dst: &[u8], b: Movem, f: F) -> Result<usize>
521 where
522 F: FnMut(&[u8]),
523 {
524 self.list_slot(dst)?;
528 let have = self.llen(src)?;
529 if b.exactly && have < b.count {
530 return Ok(0);
531 }
532
533 let mut buf = std::mem::take(&mut self.scratch);
534 let mut ends = std::mem::take(&mut self.rows);
535 buf.clear();
536 ends.clear();
537 let took = self.pop_into(src, b.from, b.count, |e| {
538 e.write_to(&mut buf);
539 ends.push(buf.len());
540 });
541 let moved = match took {
542 Ok(n) => n,
543 Err(e) => {
544 self.scratch = buf;
545 self.rows = ends;
546 return Err(e);
547 }
548 };
549 if moved == 0 {
550 self.scratch = buf;
551 self.rows = ends;
552 return Ok(0);
553 }
554
555 let pushed = self.push_block(dst, b, moved, &buf, &ends, f);
556 self.scratch = buf;
557 self.rows = ends;
558 pushed?;
559 Ok(moved)
560 }
561
562 pub(crate) fn push_block<F>(
582 &mut self,
583 dst: &[u8],
584 b: Movem,
585 moved: usize,
586 buf: &[u8],
587 ends: &[usize],
588 mut f: F,
589 ) -> Result<()>
590 where
591 F: FnMut(&[u8]),
592 {
593 let flip = match b.order {
594 Order::Bulk => !b.from.is_left(),
595 Order::OneByOne => b.to.is_left(),
596 };
597 let at = |i: usize| {
598 let end = ends[i];
599 let start = if i == 0 { 0 } else { ends[i - 1] };
600 &buf[start..end]
601 };
602 let placed = |i: usize| if flip { moved - 1 - i } else { i };
603 let sent = |i: usize| placed(if b.to.is_left() { moved - 1 - i } else { i });
607
608 self.push(dst, b.to, (0..moved).map(|i| at(sent(i))))?;
609 for i in 0..moved {
610 f(at(placed(i)));
611 }
612 Ok(())
613 }
614
615 #[inline]
617 fn list_slot(&mut self, key: &[u8]) -> Result<Option<u32>> {
618 self.live_slot(key, Kind::List)
619 }
620
621 #[inline]
626 fn list_at(&self, at: u32) -> &List {
627 self.lists.get(at).expect("the record points at its body")
628 }
629
630 fn new_list(&mut self, key: &[u8]) -> u32 {
636 let at = yo_alloc::first_touch(|| self.lists.insert(List::new()));
640 let len = value::slot_record_len(false);
641 self.write_rec(key, len, |out| {
642 value::write_slot_record(out, Kind::List, at, None);
643 });
644 self.bodies += 1;
645 at
646 }
647
648 pub(crate) fn put_list<'v>(
662 &mut self,
663 key: &[u8],
664 values: impl Iterator<Item = &'v [u8]> + Clone,
665 ) -> Result<usize> {
666 for v in values.clone() {
667 strings::check_len(key, v.len())?;
668 }
669 self.replacing(key, Kind::List);
670 self.free_body(key);
671 let at = self.new_list(key);
672 let limits = self.list_limits;
673 let list = self
674 .lists
675 .get_mut(at)
676 .expect("the record points at its body");
677 for v in values {
678 list.push_back(v, &limits);
679 }
680 Ok(list.len())
681 }
682}
683
684impl Db {
685 pub fn lmove<F>(&self, src: &[u8], dst: &[u8], from: End, to: End, f: F) -> Result<bool>
697 where
698 F: FnOnce(&[u8]),
699 {
700 let (home, onto) = (self.stripe_of(src), self.stripe_of(dst));
701 if home == onto {
702 return match self.hold_stripe(home).lmove(src, dst, from, to)? {
703 Some(moved) => {
704 f(moved);
705 Ok(true)
706 }
707 None => Ok(false),
708 };
709 }
710 self.hold_stripe(onto).list_slot(dst)?;
713 let mut spare = self.spare();
716 let buf = &mut spare.bytes;
717 buf.clear();
718 let moved = self
719 .hold_stripe(home)
720 .pop_into(src, from, 1, |e| e.write_to(buf))?;
721 if moved == 0 {
722 return Ok(false);
723 }
724 self.hold_stripe(onto)
725 .push(dst, to, std::iter::once(buf.as_slice()))?;
726 f(buf);
727 Ok(true)
728 }
729
730 pub fn lmovem<F>(&self, src: &[u8], dst: &[u8], b: Movem, f: F) -> Result<usize>
743 where
744 F: FnMut(&[u8]),
745 {
746 let (home, onto) = (self.stripe_of(src), self.stripe_of(dst));
747 if home == onto {
748 return self.hold_stripe(home).lmovem(src, dst, b, f);
749 }
750 self.hold_stripe(onto).list_slot(dst)?;
753 let have = self.hold_stripe(home).llen(src)?;
754 if have == 0 || (b.exactly && have < b.count) {
755 return Ok(0);
756 }
757 let mut spare = self.spare();
760 let spare = &mut *spare;
761 let (buf, ends) = (&mut spare.bytes, &mut spare.rows);
762 buf.clear();
763 ends.clear();
764 let moved = self.hold_stripe(home).pop_into(src, b.from, b.count, |e| {
765 e.write_to(buf);
766 ends.push(buf.len());
767 })?;
768 self.hold_stripe(onto)
769 .push_block(dst, b, moved, buf, ends, f)?;
770 Ok(moved)
771 }
772}
773
774#[inline]
780fn at(index: i64, len: usize) -> Option<usize> {
781 let i = if index < 0 { len as i64 + index } else { index };
782 (i >= 0 && (i as usize) < len).then_some(i as usize)
783}
784
785#[inline]
791fn window(start: i64, stop: i64, len: usize) -> (usize, usize) {
792 let n = len as i64;
793 let from = if start < 0 { (n + start).max(0) } else { start };
794 let to = if stop < 0 { n + stop } else { stop.min(n - 1) };
795 if from > to || from >= n || to < 0 {
796 return (0, 0);
797 }
798 (from as usize, (to - from + 1) as usize)
799}
800
801#[cfg(test)]
802mod tests {
803 use super::*;
804 use crate::Clock;
805 use crate::list::Encoding;
806 use yo_common::Code;
807
808 fn db() -> Keyspace {
809 Keyspace::with_clock(Clock::fixed(1_000))
810 }
811
812 fn rpush(d: &mut Keyspace, key: &[u8], values: &[&[u8]]) -> usize {
813 d.push(key, End::Right, values.iter().copied())
814 .expect("a list")
815 }
816
817 fn all(d: &mut Keyspace, key: &[u8]) -> Vec<String> {
818 d.lrange(key, 0, -1)
819 .expect("a list")
820 .map(|e| String::from_utf8(e.to_vec()).expect("utf8 in these tests"))
821 .collect()
822 }
823
824 #[test]
825 fn pushing_to_a_key_that_is_not_there_makes_it() {
826 let mut d = db();
827 assert_eq!(rpush(&mut d, b"l", &[b"a", b"b", b"c"]), 3);
828 assert_eq!(all(&mut d, b"l"), ["a", "b", "c"]);
829 assert_eq!(d.llen(b"l").expect("a list"), 3);
830 }
831
832 #[test]
833 fn lpush_puts_the_last_element_in_front() {
834 let mut d = db();
835 d.push(b"l", End::Left, [b"a".as_slice(), b"b", b"c"].into_iter())
836 .expect("a list");
837 assert_eq!(all(&mut d, b"l"), ["c", "b", "a"]);
838 }
839
840 #[test]
841 fn pushing_nothing_does_not_make_a_key() {
842 let mut d = db();
843 let none: [&[u8]; 0] = [];
844 assert_eq!(d.push(b"l", End::Left, none.into_iter()).expect("ok"), 0);
845 assert_eq!(d.kind_of(b"l"), None);
846 }
847
848 #[test]
849 fn pushx_only_pushes_to_a_list_that_is_there() {
850 let mut d = db();
851 assert_eq!(
852 d.pushx(b"l", End::Right, [b"a".as_slice()].into_iter())
853 .expect("ok"),
854 0
855 );
856 assert_eq!(d.kind_of(b"l"), None);
857 rpush(&mut d, b"l", &[b"a"]);
858 assert_eq!(
859 d.pushx(b"l", End::Right, [b"b".as_slice()].into_iter())
860 .expect("ok"),
861 2
862 );
863 }
864
865 #[test]
866 fn popping_the_last_element_takes_the_key_with_it() {
867 let mut d = db();
868 rpush(&mut d, b"l", &[b"only"]);
869 assert_eq!(
870 d.pop(b"l", End::Left).expect("ok").as_deref(),
871 Some(&b"only"[..])
872 );
873 assert_eq!(d.kind_of(b"l"), None);
874 assert_eq!(d.pop(b"l", End::Left).expect("ok"), None);
875 }
876
877 #[test]
878 fn a_count_pop_takes_from_the_end_it_was_asked_for() {
879 let mut d = db();
880 rpush(&mut d, b"l", &[b"a", b"b", b"c", b"d"]);
881 let mut got = Vec::new();
882 d.pop_into(b"l", End::Right, 2, |e| got.push(e.to_vec()))
883 .expect("a list");
884 assert_eq!(got, [b"d".to_vec(), b"c".to_vec()]);
885 assert_eq!(all(&mut d, b"l"), ["a", "b"]);
886 }
887
888 #[test]
889 fn a_count_pop_larger_than_the_list_empties_it() {
890 let mut d = db();
891 rpush(&mut d, b"l", &[b"a", b"b"]);
892 let mut n = 0;
893 assert_eq!(
894 d.pop_into(b"l", End::Left, 99, |_| n += 1).expect("a list"),
895 2
896 );
897 assert_eq!(n, 2);
898 assert_eq!(d.kind_of(b"l"), None);
899 }
900
901 #[test]
902 fn lrange_clamps_at_both_ends() {
903 let mut d = db();
904 rpush(&mut d, b"l", &[b"a", b"b", b"c"]);
905 assert_eq!(all(&mut d, b"l"), ["a", "b", "c"]);
906 let got: Vec<_> = d
907 .lrange(b"l", -100, 100)
908 .expect("a list")
909 .map(|e| e.to_vec())
910 .collect();
911 assert_eq!(got.len(), 3);
912 assert_eq!(d.lrange(b"l", 2, 1).expect("a list").count(), 0);
913 assert_eq!(d.lrange(b"l", 5, 9).expect("a list").count(), 0);
914 assert_eq!(d.lrange(b"nope", 0, -1).expect("no key").count(), 0);
915 }
916
917 #[test]
918 fn lindex_counts_from_the_back_when_it_is_negative() {
919 let mut d = db();
920 rpush(&mut d, b"l", &[b"a", b"b", b"c"]);
921 assert_eq!(
922 d.lindex(b"l", 0).expect("ok").map(|e| e.to_vec()),
923 Some(b"a".to_vec())
924 );
925 assert_eq!(
926 d.lindex(b"l", -1).expect("ok").map(|e| e.to_vec()),
927 Some(b"c".to_vec())
928 );
929 assert!(d.lindex(b"l", 3).expect("ok").is_none());
930 assert!(d.lindex(b"l", -4).expect("ok").is_none());
931 assert!(d.lindex(b"nope", 0).expect("ok").is_none());
932 }
933
934 #[test]
935 fn lset_says_which_of_the_two_ways_it_missed() {
936 let mut d = db();
937 let e = d.lset(b"nope", 0, b"x").expect_err("no key");
938 assert_eq!(e.message(), NO_KEY);
939 rpush(&mut d, b"l", &[b"a", b"b"]);
940 d.lset(b"l", -1, b"z").expect("in range");
941 assert_eq!(all(&mut d, b"l"), ["a", "z"]);
942 let e = d.lset(b"l", 9, b"x").expect_err("out of range");
943 assert_eq!(e.message(), OUT_OF_RANGE);
944 }
945
946 #[test]
947 fn linsert_has_three_answers() {
948 let mut d = db();
949 assert_eq!(d.linsert(b"nope", true, b"a", b"x").expect("ok"), 0);
950 rpush(&mut d, b"l", &[b"a", b"c"]);
951 assert_eq!(d.linsert(b"l", true, b"c", b"b").expect("ok"), 3);
952 assert_eq!(all(&mut d, b"l"), ["a", "b", "c"]);
953 assert_eq!(d.linsert(b"l", false, b"zz", b"x").expect("ok"), -1);
954 }
955
956 #[test]
957 fn lrem_counts_from_the_end_the_sign_says() {
958 let mut d = db();
959 rpush(&mut d, b"l", &[b"a", b"x", b"b", b"x", b"c", b"x"]);
960 assert_eq!(d.lrem(b"l", 1, b"x").expect("ok"), 1);
961 assert_eq!(all(&mut d, b"l"), ["a", "b", "x", "c", "x"]);
962 assert_eq!(d.lrem(b"l", -1, b"x").expect("ok"), 1);
963 assert_eq!(all(&mut d, b"l"), ["a", "b", "x", "c"]);
964 assert_eq!(d.lrem(b"l", 0, b"x").expect("ok"), 1);
965 assert_eq!(all(&mut d, b"l"), ["a", "b", "c"]);
966 }
967
968 #[test]
969 fn removing_everything_takes_the_key() {
970 let mut d = db();
971 rpush(&mut d, b"l", &[b"x", b"x"]);
972 assert_eq!(d.lrem(b"l", 0, b"x").expect("ok"), 2);
973 assert_eq!(d.kind_of(b"l"), None);
974 }
975
976 #[test]
977 fn ltrim_keeps_the_window() {
978 let mut d = db();
979 rpush(&mut d, b"l", &[b"a", b"b", b"c", b"d", b"e"]);
980 d.ltrim(b"l", 1, -2).expect("ok");
981 assert_eq!(all(&mut d, b"l"), ["b", "c", "d"]);
982 }
983
984 #[test]
985 fn an_empty_window_deletes_the_key() {
986 let mut d = db();
987 rpush(&mut d, b"l", &[b"a", b"b"]);
988 d.ltrim(b"l", 1, 0).expect("ok");
989 assert_eq!(d.kind_of(b"l"), None);
990 d.ltrim(b"nope", 0, -1).expect("no key is not an error");
991 }
992
993 #[test]
994 fn lpos_answers_where_and_how_many() {
995 let mut d = db();
996 rpush(&mut d, b"l", &[b"a", b"b", b"c", b"b", b"b"]);
997 let mut out = Vec::new();
998 d.lpos(b"l", b"b", 1, 0, 0, &mut out).expect("ok");
999 assert_eq!(out, [1, 3, 4]);
1000 d.lpos(b"l", b"b", -1, 2, 0, &mut out).expect("ok");
1001 assert_eq!(out, [4, 3]);
1002 d.lpos(b"l", b"b", 1, 0, 2, &mut out).expect("ok");
1003 assert_eq!(out, [1]);
1004 d.lpos(b"l", b"zz", 1, 0, 0, &mut out).expect("ok");
1005 assert!(out.is_empty());
1006 d.lpos(b"nope", b"b", 1, 0, 0, &mut out).expect("ok");
1007 assert!(out.is_empty());
1008 }
1009
1010 #[test]
1011 fn a_rank_of_zero_is_an_error() {
1012 let mut d = db();
1013 rpush(&mut d, b"l", &[b"a"]);
1014 let e = d
1015 .lpos(b"l", b"a", 0, 0, 0, &mut Vec::new())
1016 .expect_err("zero");
1017 assert_eq!(e.message(), ZERO_RANK);
1018 }
1019
1020 #[test]
1027 fn lmovem_orders_the_block_four_ways() {
1028 use End::{Left, Right};
1029 use Order::{Bulk, OneByOne};
1030 for (from, to, order, want, left) in [
1031 (Left, Right, OneByOne, ["a", "b"], ["c", "d", "e"]),
1032 (Left, Right, Bulk, ["a", "b"], ["c", "d", "e"]),
1033 (Left, Left, OneByOne, ["b", "a"], ["c", "d", "e"]),
1034 (Left, Left, Bulk, ["a", "b"], ["c", "d", "e"]),
1035 (Right, Left, OneByOne, ["d", "e"], ["a", "b", "c"]),
1036 (Right, Left, Bulk, ["d", "e"], ["a", "b", "c"]),
1037 (Right, Right, OneByOne, ["e", "d"], ["a", "b", "c"]),
1038 (Right, Right, Bulk, ["d", "e"], ["a", "b", "c"]),
1039 ] {
1040 let mut d = db();
1041 rpush(&mut d, b"s", &[b"a", b"b", b"c", b"d", b"e"]);
1042 let mut got = Vec::new();
1043 let b = Movem {
1044 from,
1045 to,
1046 count: 2,
1047 exactly: false,
1048 order,
1049 };
1050 let n = d
1051 .lmovem(b"s", b"t", b, |v| {
1052 got.push(String::from_utf8(v.to_vec()).expect("utf8 in these tests"));
1053 })
1054 .expect("two lists");
1055 let how = format!("{from:?} {to:?} {order:?}");
1056 assert_eq!(n, 2, "{how}");
1057 assert_eq!(got, want, "the reply for {how}");
1058 assert_eq!(all(&mut d, b"t"), want, "the destination for {how}");
1059 assert_eq!(all(&mut d, b"s"), left, "what is left for {how}");
1060 }
1061 }
1062
1063 fn block(from: End, to: End, count: usize, exactly: bool) -> Movem {
1066 Movem {
1067 from,
1068 to,
1069 count,
1070 exactly,
1071 order: Order::Bulk,
1072 }
1073 }
1074
1075 #[test]
1078 fn lmovem_exactly_takes_all_of_them_or_none() {
1079 let mut d = db();
1080 rpush(&mut d, b"s", &[b"a", b"b", b"c"]);
1081 let all_of_four = block(End::Left, End::Right, 4, true);
1082 let n = d
1083 .lmovem(b"s", b"t", all_of_four, |_| {
1084 panic!("nothing should have moved")
1085 })
1086 .expect("two lists");
1087 assert_eq!(n, 0);
1088 assert_eq!(
1089 all(&mut d, b"s"),
1090 ["a", "b", "c"],
1091 "the source is untouched"
1092 );
1093 assert_eq!(d.llen(b"t").expect("a list"), 0, "and nothing was made");
1094
1095 let mut got = Vec::new();
1097 let up_to_four = block(End::Left, End::Right, 4, false);
1098 let n = d
1099 .lmovem(b"s", b"t", up_to_four, |v| got.push(v.to_vec()))
1100 .expect("two lists");
1101 assert_eq!(n, 3);
1102 assert_eq!(got.len(), 3);
1103 assert!(!d.exists(b"s"), "an emptied source goes");
1104 }
1105
1106 #[test]
1109 fn lmovem_onto_itself_rotates_by_the_count() {
1110 let mut d = db();
1111 rpush(&mut d, b"l", &[b"a", b"b", b"c"]);
1112 d.lmovem(b"l", b"l", block(End::Left, End::Right, 2, false), |_| {})
1113 .expect("a list");
1114 assert_eq!(all(&mut d, b"l"), ["c", "a", "b"]);
1115
1116 let mut d = db();
1117 rpush(&mut d, b"l", &[b"a", b"b", b"c"]);
1118 d.lmovem(b"l", b"l", block(End::Right, End::Left, 2, false), |_| {})
1119 .expect("a list");
1120 assert_eq!(all(&mut d, b"l"), ["b", "c", "a"]);
1121 }
1122
1123 #[test]
1126 fn lmovem_checks_the_destination_before_taking_anything() {
1127 let mut d = db();
1128 rpush(&mut d, b"s", &[b"a", b"b"]);
1129 d.set_plain(b"str", b"v").expect("room");
1130 let two = block(End::Left, End::Right, 2, false);
1131 let e = d
1132 .lmovem(b"s", b"str", two, |_| {})
1133 .expect_err("the destination is a string");
1134 assert_eq!(e.code(), Code::WrongType);
1135 assert_eq!(all(&mut d, b"s"), ["a", "b"], "the source is untouched");
1136
1137 let n = d
1138 .lmovem(b"nope", b"t", two, |_| {})
1139 .expect("a source that is not there is not an error");
1140 assert_eq!(n, 0);
1141 }
1142
1143 #[test]
1144 fn lmove_between_two_keys_makes_the_second_one() {
1145 let mut d = db();
1146 rpush(&mut d, b"src", &[b"a", b"b"]);
1147 let got = d.lmove(b"src", b"dst", End::Right, End::Left).expect("ok");
1148 assert_eq!(got, Some(&b"b"[..]));
1149 assert_eq!(all(&mut d, b"src"), ["a"]);
1150 assert_eq!(all(&mut d, b"dst"), ["b"]);
1151 }
1152
1153 #[test]
1154 fn lmove_onto_itself_rotates() {
1155 let mut d = db();
1156 rpush(&mut d, b"l", &[b"a", b"b", b"c"]);
1157 d.lmove(b"l", b"l", End::Right, End::Left).expect("ok");
1158 assert_eq!(all(&mut d, b"l"), ["c", "a", "b"]);
1159 d.lmove(b"l", b"l", End::Left, End::Right).expect("ok");
1160 assert_eq!(all(&mut d, b"l"), ["a", "b", "c"]);
1161 }
1162
1163 #[test]
1164 fn lmove_from_a_key_that_is_not_there_does_nothing() {
1165 let mut d = db();
1166 assert_eq!(
1167 d.lmove(b"nope", b"dst", End::Left, End::Left).expect("ok"),
1168 None
1169 );
1170 assert_eq!(d.kind_of(b"dst"), None);
1171 }
1172
1173 #[test]
1177 fn lmove_stops_allocating_once_its_buffer_is_grown() {
1178 let mut d = db();
1179 rpush(&mut d, b"q", &[b"a", b"b", b"c"]);
1180 d.lmove(b"q", b"q", End::Right, End::Left).expect("ok");
1183 let (_, allocs) = crate::tally::counted(|| {
1184 for _ in 0..100 {
1185 d.lmove(b"q", b"q", End::Right, End::Left).expect("ok");
1186 }
1187 });
1188 assert_eq!(allocs, 0, "lmove allocated {allocs} times in a hundred");
1189 assert_eq!(all(&mut d, b"q"), ["b", "c", "a"]);
1190 }
1191
1192 #[test]
1196 fn lrem_does_not_allocate_to_remove_a_handful() {
1197 let mut d = db();
1198 let many: Vec<&[u8]> = (0..100).map(|_| b"gone".as_slice()).collect();
1202 rpush(&mut d, b"l", &many);
1203 rpush(&mut d, b"l", &[b"keep"]);
1204 let (_, allocs) = crate::tally::counted(|| {
1205 for _ in 0..100 {
1206 assert_eq!(d.lrem(b"l", 1, b"gone").expect("a list"), 1);
1207 }
1208 });
1209 assert_eq!(allocs, 0, "lrem allocated {allocs} times in a hundred");
1210 assert_eq!(all(&mut d, b"l"), ["keep"]);
1211 }
1212
1213 #[test]
1215 fn lrem_with_more_hits_than_fit_inline_still_removes_all_of_them() {
1216 let mut d = db();
1217 let many: Vec<&[u8]> = (0..40).map(|_| b"x".as_slice()).collect();
1218 rpush(&mut d, b"l", &many);
1219 rpush(&mut d, b"l", &[b"keep"]);
1220 assert_eq!(d.lrem(b"l", 0, b"x").expect("a list"), 40);
1221 assert_eq!(all(&mut d, b"l"), ["keep"]);
1222 }
1223
1224 #[test]
1225 fn lmove_checks_the_destination_before_taking_anything() {
1226 let mut d = db();
1227 rpush(&mut d, b"src", &[b"a"]);
1228 d.set_plain(b"dst", b"a string").expect("room");
1229 let e = d
1230 .lmove(b"src", b"dst", End::Left, End::Left)
1231 .expect_err("the destination is a string");
1232 assert_eq!(e.code(), Code::WrongType);
1233 assert_eq!(all(&mut d, b"src"), ["a"]);
1234 }
1235
1236 #[test]
1237 fn every_command_says_wrongtype_against_a_string() {
1238 let mut d = db();
1239 d.set_plain(b"s", b"a string").expect("room");
1240 assert_eq!(
1241 d.push(b"s", End::Left, [b"x".as_slice()].into_iter())
1242 .expect_err("a string")
1243 .code(),
1244 Code::WrongType
1245 );
1246 assert_eq!(d.llen(b"s").expect_err("a string").code(), Code::WrongType);
1247 assert_eq!(
1248 d.pop(b"s", End::Left).expect_err("a string").code(),
1249 Code::WrongType
1250 );
1251 assert_eq!(
1252 d.lset(b"s", 0, b"x").expect_err("a string").code(),
1253 Code::WrongType
1254 );
1255 assert_eq!(
1256 d.ltrim(b"s", 0, -1).expect_err("a string").code(),
1257 Code::WrongType
1258 );
1259 }
1260
1261 #[test]
1262 fn a_list_is_a_list_to_the_rest_of_the_keyspace() {
1263 let mut d = db();
1264 rpush(&mut d, b"l", &[b"a"]);
1265 assert_eq!(d.kind_of(b"l").map(|k| k.name()), Some("list"));
1266 assert_eq!(d.encoding_name(b"l"), Some(Encoding::Listpack.name()));
1267 assert!(d.exists(b"l"));
1268 assert!(d.drop_key(b"l"));
1269 assert_eq!(d.kind_of(b"l"), None);
1270 }
1271
1272 #[test]
1273 fn a_list_can_be_given_a_deadline_and_reaped() {
1274 let mut d = Keyspace::with_clock(Clock::fixed(1_000));
1275 rpush(&mut d, b"l", &[b"a", b"b"]);
1276 assert!(d.set_expiry(b"l", Some(1_500)));
1277 assert_eq!(all(&mut d, b"l"), ["a", "b"]);
1278 d.clock().advance(1_000);
1279 assert_eq!(d.llen(b"l").expect("gone"), 0);
1280 assert_eq!(d.kind_of(b"l"), None);
1281 }
1282
1283 #[test]
1284 fn a_big_list_is_chunked_and_still_answers_the_same() {
1285 let mut d = db();
1286 let value = vec![b'x'; 400];
1287 for i in 0..40 {
1288 let mut v = value.clone();
1289 v.extend_from_slice(format!("{i}").as_bytes());
1290 d.push(b"l", End::Right, [v.as_slice()].into_iter())
1291 .expect("a list");
1292 }
1293 assert_eq!(d.encoding_name(b"l"), Some(Encoding::Quicklist.name()));
1294 assert_eq!(d.llen(b"l").expect("a list"), 40);
1295 let last = d.lindex(b"l", -1).expect("ok").expect("in range").to_vec();
1296 assert!(last.ends_with(b"39"));
1297 d.ltrim(b"l", 0, 0).expect("ok");
1298 assert_eq!(d.llen(b"l").expect("a list"), 1);
1299 assert_eq!(d.encoding_name(b"l"), Some(Encoding::Listpack.name()));
1300 }
1301}