1pub mod err;
4
5use std::alloc::{alloc, dealloc, Layout};
6
7use err::Error;
8
9struct IdBlock {
10 next: *mut IdBlock,
11 prev: *mut IdBlock,
12 low: usize,
13 high: usize
14}
15
16impl IdBlock {
17 fn count(&self) -> usize {
18 self.high - self.low + 1
19 }
20}
21
22pub struct IdHeap {
25 low: usize,
27
28 high: usize,
30
31 blocks: *mut IdBlock
36}
37
38unsafe impl Send for IdHeap {}
39
40fn mkblock(low: usize, high: usize) -> *mut IdBlock {
42 let layout = Layout::new::<IdBlock>();
43 let blk = unsafe { alloc(layout) };
44 let blk = blk as *mut IdBlock;
45
46 unsafe {
47 (*blk).next = std::ptr::null_mut();
48 (*blk).prev = std::ptr::null_mut();
49 (*blk).low = low;
50 (*blk).high = high;
51 }
52
53 blk
54}
55
56impl IdHeap {
57 pub fn new(low: usize, high: usize) -> Result<Self, Error> {
62 if high < low {
63 #[cfg(feature = "hardfail")]
64 panic!("minimum id bound much be lower than the maximum id bound");
65
66 #[cfg(not(feature = "hardfail"))]
67 return Err(Error::invalid_param(
68 "Lower id bound must be lower than the higher id bound"
69 ));
70 }
71
72 let idblk = mkblock(low, high);
73 Ok(Self {
74 low,
75 high,
76 blocks: idblk
77 })
78 }
79
80 pub fn from_strlist(
87 spec: &str,
88 low: usize,
89 high: usize
90 ) -> Result<Self, Error> {
91 let mut head: *mut IdBlock = std::ptr::null_mut();
92 let mut tail: *mut IdBlock = std::ptr::null_mut();
93
94 if !spec.is_empty() {
95 for blkspec in spec.split(',') {
96 let range: Vec<&str> = blkspec.split('-').collect();
97
98 let blk = if range.len() == 1 {
99 let id = match range[0].parse::<usize>() {
100 Ok(id) => id,
101 Err(_e) => {
102 release_chain(head);
103 return Err(Error::bad_format("Not a number in block spec"));
104 }
105 };
106
107 mkblock(id, id)
108 } else if range.len() == 2 {
109 let low = match range[0].parse::<usize>() {
110 Ok(id) => id,
111 Err(_e) => {
112 release_chain(head);
113 return Err(Error::bad_format("Not a number in block spec"));
114 }
115 };
116 let high = match range[1].parse::<usize>() {
117 Ok(id) => id,
118 Err(_e) => {
119 release_chain(head);
120 return Err(Error::bad_format("Not a number in block spec"));
121 }
122 };
123
124 mkblock(low, high)
125 } else {
126 release_chain(head);
127 return Err(Error::bad_format("invalid block spec"));
128 };
129
130 unsafe {
134 if (*blk).low > (*blk).high {
135 release_chain(head);
136 release_node(blk);
137 return Err(Error::bad_format("Low bound higher than high bound"));
138 }
139
140 if (*blk).low < low || (*blk).high > high {
141 release_chain(head);
142 release_node(blk);
143 return Err(Error::bad_format("Out of bounds"));
144 }
145 }
146
147 if head == std::ptr::null_mut() {
148 head = blk;
149 tail = blk;
150 } else {
151 unsafe {
152 if (*tail).high >= (*blk).low {
156 return Err(Error::bad_format("Overlapping spans"));
157 }
158 let d = (*blk).low - (*tail).high;
159 if d < 2 {
160 return Err(Error::bad_format("Contiguous spans"));
161 }
162
163 (*tail).next = blk;
164 (*blk).prev = tail;
165
166 tail = blk;
167 }
168 }
169 }
170 }
171
172 Ok(Self {
173 low,
174 high,
175 blocks: head
176 })
177 }
178
179
180 pub fn from_slice(
181 slice: &[(usize, usize)],
182 low: usize,
183 high: usize
184 ) -> Result<Self, Error> {
185 let mut head: *mut IdBlock = std::ptr::null_mut();
186 let mut tail: *mut IdBlock = std::ptr::null_mut();
187
188 if !slice.is_empty() {
189 for (l, h) in slice {
190 let blk = if l == h {
191 mkblock(*l, *l)
192 } else if *l > *h {
193 release_chain(head);
194 return Err(Error::bad_format("Low bound higher than high bound"));
195 } else {
196 mkblock(*l, *h)
197 };
198
199 unsafe {
200 if (*blk).low < low || (*blk).high > high {
201 release_chain(head);
202 release_node(blk);
203 return Err(Error::bad_format("Out of bounds"));
204 }
205 }
206
207 if head == std::ptr::null_mut() {
208 head = blk;
209 tail = blk;
210 } else {
211 unsafe {
212 if (*tail).high >= (*blk).low {
216 return Err(Error::bad_format("Overlapping spans"));
217 }
218 let d = (*blk).low - (*tail).high;
219 if d < 2 {
220 return Err(Error::bad_format("Contiguous spans"));
221 }
222
223 (*tail).next = blk;
224 (*blk).prev = tail;
225
226 tail = blk;
227 }
228 }
229 }
230 }
231
232 Ok(Self {
233 low,
234 high,
235 blocks: head
236 })
237 }
238
239
240 pub fn capacity(&self) -> usize {
242 self.high - self.low + 1
243 }
244
245 pub fn count(&self) -> usize {
247 let mut ret = 0;
248
249 let mut idblk = self.blocks;
250 unsafe {
251 while idblk != std::ptr::null_mut() {
252 ret += (*idblk).count();
253 idblk = (*idblk).next;
254 }
255 }
256
257 ret
258 }
259
260 pub fn allocated(&self) -> usize {
262 self.capacity() - self.count()
263 }
264
265 pub fn is_empty(&self) -> bool {
266 self.blocks == std::ptr::null_mut()
267 }
268
269
270 pub fn make_strlist(&self) -> String {
273 let mut ret = Vec::new();
274
275 let mut n = self.blocks;
276 while n != std::ptr::null_mut() {
277 unsafe {
278 if (*n).low == (*n).high {
279 ret.push(format!("{}", (*n).low));
280 } else {
281 ret.push(format!("{}-{}", (*n).low, (*n).high));
282 }
283
284 n = (*n).next;
285 }
286 }
287
288 ret.join(",")
289 }
290
291
292 pub fn alloc(&mut self) -> Option<usize> {
301 if self.blocks == std::ptr::null_mut() {
302 return None;
303 }
304
305 let idblk = self.blocks;
306
307 let id = unsafe { (*idblk).low };
308
309 unsafe {
310 if (*idblk).low != (*idblk).high {
311 (*idblk).low += 1;
313 } else {
314 self.blocks = (*self.blocks).next;
316
317 let layout = Layout::new::<IdBlock>();
319 dealloc(idblk as *mut u8, layout);
320 }
321 }
322
323 Some(id)
324 }
325
326
327 pub fn alloc_id(&mut self, id: usize) -> Result<usize, Error> {
338 if id < self.low || id > self.high {
342 #[cfg(feature = "hardfail")]
343 panic!("id out of bounds");
344
345 #[cfg(not(feature = "hardfail"))]
346 return Err(Error::OutOfBounds);
347 }
348
349 let mut idblk = self.blocks;
353 unsafe {
354 while idblk != std::ptr::null_mut() {
358 if id > (*idblk).high {
362 idblk = (*idblk).next;
363 continue;
364 }
365
366 if id < (*idblk).low {
369 return Err(Error::Unavailable);
370 }
371
372 if (*idblk).low == (*idblk).high {
382 self.free_node(idblk);
384 return Ok(id);
385 }
386
387 if (*idblk).low == id {
388 (*idblk).low += 1;
389 return Ok(id);
390 }
391
392 if (*idblk).high == id {
393 (*idblk).high -= 1;
394 return Ok(id);
395 }
396
397 let newblock = mkblock((*idblk).low, id - 1);
401
402 (*idblk).low = id + 1;
403
404 self.insert_node(idblk, newblock);
405
406 return Ok(id);
407 }
408 }
409
410 Err(Error::Unavailable)
411 }
412
413
414 pub fn release(&mut self, id: usize) -> Result<(), Error> {
416 if id < self.low || id > self.high {
420 #[cfg(feature = "hardfail")]
421 panic!("id out of bounds");
422
423 #[cfg(not(feature = "hardfail"))]
424 return Err(Error::OutOfBounds);
425 }
426
427 let mut idblk = self.blocks;
428 let mut last = std::ptr::null_mut();
429 unsafe {
430 while idblk != std::ptr::null_mut() {
434 if id + 1 == (*idblk).low {
435 (*idblk).low -= 1;
437
438 if (*idblk).prev != std::ptr::null_mut() {
440 if (*(*idblk).prev).high + 1 == (*idblk).low {
442 (*(*idblk).prev).high = (*idblk).high;
445
446 self.free_node(idblk);
448 }
449 }
450
451 return Ok(());
452 }
453
454 if id == (*idblk).high + 1 {
455 (*idblk).high += 1;
457
458 if (*idblk).next != std::ptr::null_mut() {
461 if (*(*idblk).next).low == (*idblk).high + 1 {
463 (*(*idblk).next).low = (*idblk).low;
466
467 self.free_node(idblk);
469 }
470 }
471
472 return Ok(());
473 }
474
475 if id < (*idblk).low {
476 break;
478 }
479
480 if id >= (*idblk).low && id <= (*idblk).high {
485 #[cfg(feature = "hardfail")]
486 panic!("Attempted to release an unallocated id");
487
488 #[cfg(not(feature = "hardfail"))]
489 return Err(Error::invalid_param(""));
490 }
491
492 last = idblk;
494
495 idblk = (*idblk).next;
497 }
498
499 let mut newblock = mkblock(id, id);
511 if self.blocks == std::ptr::null_mut() {
512 self.blocks = newblock;
514 } else if idblk != std::ptr::null_mut() {
515 self.insert_node(idblk, newblock);
516 } else if last != std::ptr::null_mut() {
517 (*last).next = newblock;
520 (*newblock).prev = last;
521 }
522 }
523
524 Ok(())
525 }
526}
527
528
529impl IdHeap {
531 unsafe fn insert_node(
533 &mut self,
534 idblk: *mut IdBlock,
535 newblock: *mut IdBlock
536 ) {
537 (*newblock).next = idblk;
542 (*newblock).prev = (*idblk).prev;
543
544 (*(*newblock).next).prev = newblock;
547
548 if (*newblock).prev != std::ptr::null_mut() {
551 (*(*newblock).prev).next = newblock;
552 } else {
553 self.blocks = newblock;
555 }
556 }
557
558
559 unsafe fn free_node(&mut self, idblk: *mut IdBlock) {
563 if idblk == self.blocks {
564 self.blocks = (*idblk).next;
566 }
567
568 if (*idblk).prev != std::ptr::null_mut() {
572 (*(*idblk).prev).next = (*idblk).next;
581 } else if (*idblk).next != std::ptr::null_mut() {
582 (*(*idblk).next).prev = std::ptr::null_mut();
591 }
592
593 if (*idblk).next != std::ptr::null_mut() {
594 (*(*idblk).next).prev = (*idblk).prev;
604 } else if (*idblk).prev != std::ptr::null_mut() {
605 (*(*idblk).prev).next = std::ptr::null_mut();
608 }
609
610 let layout = Layout::new::<IdBlock>();
611 dealloc(idblk as *mut u8, layout);
612 }
613
614
615 #[allow(dead_code)]
617 fn get_blocks_list(&self) -> Vec<(usize, usize)> {
618 let mut ret = Vec::new();
619 let mut idblk = self.blocks;
620 unsafe {
621 while idblk != std::ptr::null_mut() {
622 ret.push(((*idblk).low, (*idblk).high));
623 idblk = (*idblk).next;
624 }
625 }
626 ret
627 }
628}
629
630impl Drop for IdHeap {
631 fn drop(&mut self) {
632 let layout = Layout::new::<IdBlock>();
633 let mut idblk = self.blocks;
634 while idblk != std::ptr::null_mut() {
635 unsafe {
636 let next = (*idblk).next;
637 dealloc(idblk as *mut u8, layout);
638 idblk = next;
639 }
640 }
641 }
642}
643
644
645fn release_chain(head: *mut IdBlock) {
646 let mut n = head;
647
648 while n != std::ptr::null_mut() {
649 let next = unsafe { (*n).next };
650
651 release_node(n);
652
653 n = next;
654 }
655}
656
657fn release_node(n: *mut IdBlock) {
658 let layout = Layout::new::<IdBlock>();
659 unsafe {
660 dealloc(n as *mut u8, layout);
661 }
662}
663
664
665#[cfg(test)]
666mod tests {
667 use super::*;
668
669 #[test]
670 fn single_id() {
671 let mut idh = IdHeap::new(1, 1).unwrap();
672 assert_eq!(idh.capacity(), 1);
673 assert_eq!(idh.count(), 1);
674 assert_eq!(idh.allocated(), 0);
675 let fb = idh.get_blocks_list();
676 assert_eq!(fb.as_slice(), [(1, 1)]);
677 assert_eq!(fb.is_empty(), false);
678
679 assert_eq!(idh.alloc(), Some(1));
680
681 assert_eq!(idh.capacity(), 1);
682 assert_eq!(idh.count(), 0);
683 assert_eq!(idh.allocated(), 1);
684 let fb = idh.get_blocks_list();
685 assert_eq!(fb.as_slice(), []);
686 assert_eq!(fb.is_empty(), true);
687
688 idh.release(1).unwrap();
689
690 assert_eq!(idh.capacity(), 1);
691 assert_eq!(idh.count(), 1);
692 assert_eq!(idh.allocated(), 0);
693 let fb = idh.get_blocks_list();
694 assert_eq!(fb.as_slice(), [(1, 1)]);
695 assert_eq!(fb.is_empty(), false);
696 }
697
698
699 #[test]
700 fn just_init() {
701 let mut idh = IdHeap::new(0, 9).unwrap();
702 assert_eq!(idh.capacity(), 10);
703 assert_eq!(idh.count(), 10);
704 assert_eq!(idh.allocated(), 0);
705 let fb = idh.get_blocks_list();
706 assert_eq!(fb.as_slice(), [(0, 9)]);
707
708 assert_eq!(idh.alloc(), Some(0));
709 }
710
711
712 #[test]
713 fn alloc_one() {
714 let mut idh = IdHeap::new(0, 9).unwrap();
715
716 assert_eq!(idh.alloc(), Some(0));
717
718 assert_eq!(idh.capacity(), 10);
719 assert_eq!(idh.count(), 9);
720 assert_eq!(idh.allocated(), 1);
721 let fb = idh.get_blocks_list();
722 assert_eq!(fb.as_slice(), [(1, 9)]);
723 }
724
725
726 #[test]
727 fn return_new_first_block() {
728 let mut idh = IdHeap::new(0, 9).unwrap();
729
730 assert_eq!(idh.alloc(), Some(0));
732 assert_eq!(idh.alloc(), Some(1));
733
734 idh.release(0).unwrap();
737
738 assert_eq!(idh.capacity(), 10);
739 assert_eq!(idh.count(), 9);
740 assert_eq!(idh.allocated(), 1);
741 let fb = idh.get_blocks_list();
742 assert_eq!(fb.as_slice(), [(0, 0), (2, 9)]);
743 }
744
745
746 #[test]
747 fn merge_front_and_back_add_tail() {
748 let mut idh = IdHeap::new(0, 2).unwrap();
749
750 assert_eq!(idh.alloc(), Some(0));
751 assert_eq!(idh.alloc(), Some(1));
752 assert_eq!(idh.alloc(), Some(2));
753
754 let fb = idh.get_blocks_list();
755 assert_eq!(fb.as_slice(), []);
756
757 idh.release(0).unwrap();
758
759 let fb = idh.get_blocks_list();
760 assert_eq!(fb.as_slice(), [(0, 0)]);
761
762 idh.release(2).unwrap();
764
765 let fb = idh.get_blocks_list();
766 assert_eq!(fb.as_slice(), [(0, 0), (2, 2)]);
767
768 idh.release(1).unwrap();
769
770 let fb = idh.get_blocks_list();
771 assert_eq!(fb.as_slice(), [(0, 2)]);
772 }
773
774
775 #[test]
776 fn merge_front_and_back_add_head() {
777 let mut idh = IdHeap::new(0, 2).unwrap();
778
779 assert_eq!(idh.alloc(), Some(0));
780 assert_eq!(idh.alloc(), Some(1));
781 assert_eq!(idh.alloc(), Some(2));
782
783 let fb = idh.get_blocks_list();
784 assert_eq!(fb.as_slice(), []);
785
786 idh.release(2).unwrap();
787
788 let fb = idh.get_blocks_list();
789 assert_eq!(fb.as_slice(), [(2, 2)]);
790
791 idh.release(0).unwrap();
793
794 let fb = idh.get_blocks_list();
795 assert_eq!(fb.as_slice(), [(0, 0), (2, 2)]);
796
797 idh.release(1).unwrap();
798
799 let fb = idh.get_blocks_list();
800 assert_eq!(fb.as_slice(), [(0, 2)]);
801 }
802
803
804 #[test]
805 fn alloc_id_head() {
806 let mut idh = IdHeap::new(1, 3).unwrap();
807
808 assert_eq!(idh.alloc_id(1).unwrap(), 1);
809
810 let fb = idh.get_blocks_list();
811 assert_eq!(fb.as_slice(), [(2, 3)]);
812
813 idh.release(1).unwrap();
815
816 let fb = idh.get_blocks_list();
818 assert_eq!(fb.as_slice(), [(1, 3)]);
819 }
820
821
822 #[test]
823 fn alloc_id_split() {
824 let mut idh = IdHeap::new(1, 3).unwrap();
826
827 assert_eq!(idh.alloc_id(2).unwrap(), 2);
829
830 let fb = idh.get_blocks_list();
832 assert_eq!(fb.as_slice(), [(1, 1), (3, 3)]);
833
834 idh.release(2).unwrap();
836
837 let fb = idh.get_blocks_list();
839 assert_eq!(fb.as_slice(), [(1, 3)]);
840 }
841
842
843 #[test]
844 fn alloc_id_tail() {
845 let mut idh = IdHeap::new(1, 3).unwrap();
846
847 assert_eq!(idh.alloc_id(3).unwrap(), 3);
848
849 let fb = idh.get_blocks_list();
850 assert_eq!(fb.as_slice(), [(1, 2)]);
851
852 idh.release(3).unwrap();
854
855 let fb = idh.get_blocks_list();
857 assert_eq!(fb.as_slice(), [(1, 3)]);
858 }
859
860
861 #[test]
862 fn from_strlist() {
863 let idh = IdHeap::from_strlist("", 0, 7).unwrap();
864 let fb = idh.get_blocks_list();
865 assert_eq!(fb.as_slice(), []);
866
867 let idh = IdHeap::from_strlist("0", 0, 7).unwrap();
868 let fb = idh.get_blocks_list();
869 assert_eq!(fb.as_slice(), [(0, 0)]);
870
871 let idh = IdHeap::from_strlist("0-2", 0, 7).unwrap();
872 let fb = idh.get_blocks_list();
873 assert_eq!(fb.as_slice(), [(0, 2)]);
874
875 let idh = IdHeap::from_strlist("0-2,6", 0, 7).unwrap();
876 let fb = idh.get_blocks_list();
877 assert_eq!(fb.as_slice(), [(0, 2), (6, 6)]);
878
879 let idh = IdHeap::from_strlist("0-1,3,5-7", 0, 7).unwrap();
880 let fb = idh.get_blocks_list();
881 assert_eq!(fb.as_slice(), [(0, 1), (3, 3), (5, 7)]);
882 }
883
884
885 #[test]
886 fn from_slice() {
887 let idh = IdHeap::from_slice(&[], 0, 7).unwrap();
888 let fb = idh.get_blocks_list();
889 assert_eq!(fb.as_slice(), []);
890
891 let idh = IdHeap::from_slice(&[(0, 0)], 0, 7).unwrap();
892 let fb = idh.get_blocks_list();
893 assert_eq!(fb.as_slice(), [(0, 0)]);
894
895 let idh = IdHeap::from_slice(&[(0, 2)], 0, 7).unwrap();
896 let fb = idh.get_blocks_list();
897 assert_eq!(fb.as_slice(), [(0, 2)]);
898
899 let idh = IdHeap::from_slice(&[(0, 2), (6, 6)], 0, 7).unwrap();
900 let fb = idh.get_blocks_list();
901 assert_eq!(fb.as_slice(), [(0, 2), (6, 6)]);
902
903 let idh = IdHeap::from_slice(&[(0, 1), (3, 3), (5, 7)], 0, 7).unwrap();
904 let fb = idh.get_blocks_list();
905 assert_eq!(fb.as_slice(), [(0, 1), (3, 3), (5, 7)]);
906 }
907
908
909 #[test]
910 fn from_strlist_fail() {
911 match IdHeap::from_strlist("1-0", 0, 7) {
912 Err(Error::BadFormat(s)) => {
913 assert_eq!(&s, "Low bound higher than high bound");
914 }
915 _ => panic!("test failed")
916 }
917
918 match IdHeap::from_strlist("a", 0, 7) {
919 Err(Error::BadFormat(s)) => {
920 assert_eq!(&s, "Not a number in block spec");
921 }
922 _ => panic!("test failed")
923 }
924
925 match IdHeap::from_strlist("a-4", 0, 7) {
926 Err(Error::BadFormat(s)) => {
927 assert_eq!(&s, "Not a number in block spec");
928 }
929 _ => panic!("test failed")
930 }
931
932 match IdHeap::from_strlist("0-a", 0, 7) {
933 Err(Error::BadFormat(s)) => {
934 assert_eq!(&s, "Not a number in block spec");
935 }
936 _ => panic!("test failed")
937 }
938
939 match IdHeap::from_strlist("0-2", 1, 7) {
940 Err(Error::BadFormat(s)) => {
941 assert_eq!(&s, "Out of bounds");
942 }
943 _ => panic!("test failed")
944 }
945
946 match IdHeap::from_strlist("4-8", 1, 7) {
947 Err(Error::BadFormat(s)) => {
948 assert_eq!(&s, "Out of bounds");
949 }
950 _ => panic!("test failed")
951 }
952
953 match IdHeap::from_strlist("0-5,4-7", 0, 7) {
956 Err(Error::BadFormat(s)) => {
957 assert_eq!(&s, "Overlapping spans");
958 }
959 _ => panic!("test failed")
960 }
961
962 match IdHeap::from_strlist("0-4,4-7", 0, 7) {
965 Err(Error::BadFormat(s)) => {
966 assert_eq!(&s, "Overlapping spans");
967 }
968 _ => panic!("test failed")
969 }
970
971 match IdHeap::from_strlist("0-4,5-7", 0, 7) {
974 Err(Error::BadFormat(s)) => {
975 assert_eq!(&s, "Contiguous spans");
976 }
977 _ => panic!("test failed")
978 }
979 }
980
981
982 #[test]
983 fn from_slice_fail() {
984 match IdHeap::from_slice(&[(1, 0)], 0, 7) {
985 Err(Error::BadFormat(s)) => {
986 assert_eq!(&s, "Low bound higher than high bound");
987 }
988 _ => panic!("test failed")
989 }
990
991 match IdHeap::from_slice(&[(0, 2)], 1, 7) {
992 Err(Error::BadFormat(s)) => {
993 assert_eq!(&s, "Out of bounds");
994 }
995 _ => panic!("test failed")
996 }
997
998 match IdHeap::from_slice(&[(4, 8)], 1, 7) {
999 Err(Error::BadFormat(s)) => {
1000 assert_eq!(&s, "Out of bounds");
1001 }
1002 _ => panic!("test failed")
1003 }
1004
1005 match IdHeap::from_slice(&[(0, 5), (4, 7)], 0, 7) {
1008 Err(Error::BadFormat(s)) => {
1009 assert_eq!(&s, "Overlapping spans");
1010 }
1011 _ => panic!("test failed")
1012 }
1013
1014 match IdHeap::from_slice(&[(0, 4), (4, 7)], 0, 7) {
1017 Err(Error::BadFormat(s)) => {
1018 assert_eq!(&s, "Overlapping spans");
1019 }
1020 _ => panic!("test failed")
1021 }
1022
1023 match IdHeap::from_slice(&[(0, 4), (5, 7)], 0, 7) {
1026 Err(Error::BadFormat(s)) => {
1027 assert_eq!(&s, "Contiguous spans");
1028 }
1029 _ => panic!("test failed")
1030 }
1031 }
1032
1033
1034 #[test]
1035 fn deserialize_serialize() {
1036 let input = "";
1037 let idh = IdHeap::from_strlist(input, 0, 7).unwrap();
1038 assert_eq!(input, idh.make_strlist());
1039
1040 let input = "0";
1041 let idh = IdHeap::from_strlist(input, 0, 7).unwrap();
1042 assert_eq!(input, idh.make_strlist());
1043
1044 let input = "0-2";
1045 let idh = IdHeap::from_strlist(input, 0, 7).unwrap();
1046 assert_eq!(input, idh.make_strlist());
1047
1048 let input = "0-2,4";
1049 let idh = IdHeap::from_strlist(input, 0, 7).unwrap();
1050 assert_eq!(input, idh.make_strlist());
1051
1052 let input = "0-2,4-6";
1053 let idh = IdHeap::from_strlist(input, 0, 7).unwrap();
1054 assert_eq!(input, idh.make_strlist());
1055
1056 let input = "0-1,3,5-7";
1057 let idh = IdHeap::from_strlist(input, 0, 7).unwrap();
1058 assert_eq!(input, idh.make_strlist());
1059
1060 let input = "0,2,4,6";
1061 let idh = IdHeap::from_strlist(input, 0, 7).unwrap();
1062 assert_eq!(input, idh.make_strlist());
1063 }
1064
1065
1066 #[test]
1067 fn send_to_thread() {
1068 let mut idh = IdHeap::new(0, 7).unwrap();
1069
1070 let handle = std::thread::spawn(|| {
1071 let id = idh.alloc().unwrap();
1072 (idh, id)
1073 });
1074
1075 let (mut idh, id) = handle.join().unwrap();
1076 idh.release(id).unwrap();
1077 }
1078}
1079
1080