sp_im/conslist.rs
1// adapted from https://github.com/bodil/im-rs/blob/10.2.0/src/conslist.rs
2
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7//! A cons list.
8//!
9//! The cons list is perhaps the most basic immutable data structure:
10//! a singly linked list built out of 'cons cells,' which are cells
11//! containing two values, the left hand value being the head of the
12//! list and the right hand value being a reference to the rest of the
13//! list, or a `Nil` value denoting the end of the list.
14//!
15//! Structure can be shared between lists (and is reference counted),
16//! and append to the front of a list is O(1). Cons cells keep track
17//! of the length of the list at the current position, as an extra
18//! optimisation, so getting the length of a list is also O(1).
19//! Otherwise, operations are generally O(n).
20
21use crate::shared::Shared;
22use alloc::{
23 borrow::Borrow,
24 fmt::{
25 Debug,
26 Error,
27 Formatter,
28 },
29 sync::Arc,
30 vec::Vec,
31};
32
33use core::{
34 cmp::Ordering,
35 hash::{
36 Hash,
37 Hasher,
38 },
39 iter::{
40 FromIterator,
41 Iterator,
42 Sum,
43 },
44 ops::{
45 Add,
46 Deref,
47 },
48};
49
50use self::ConsListNode::{
51 Cons,
52 Nil,
53};
54
55/// Construct a list from a sequence of elements.
56///
57/// # Examples
58///
59/// Here are some different ways of constructing a list of
60/// three numbers 1, 2 and 3:
61///
62/// ```
63/// # #[macro_use] extern crate sp_im;
64/// # use sp_im::conslist::{ConsList, cons};
65/// # fn main() {
66/// assert_eq!(conslist![1, 2, 3], ConsList::from(vec![1, 2, 3]));
67///
68/// assert_eq!(conslist![1, 2, 3], cons(1, cons(2, cons(3, ConsList::new()))));
69/// # }
70/// ```
71#[macro_export]
72macro_rules! conslist {
73 () => { $crate::conslist::ConsList::new() };
74
75 ( $($x:expr),* ) => {{
76 let mut l = $crate::conslist::ConsList::new();
77 $(
78 l = l.cons($x);
79 )*
80 l.reverse()
81 }};
82}
83
84/// Prepend a value to a list.
85///
86/// Constructs a list with the value `car` prepended to the front of
87/// the list `cdr`.
88///
89/// This is just a shorthand for `list.cons(item)`, but I find it much
90/// easier to read `cons(1, cons(2, ConsList::new()))` than
91/// `ConsList::new().cons(2).cons(1)`, given that the resulting list
92/// will be `[1, 2]`.
93///
94/// # Examples
95///
96/// ```
97/// # #[macro_use] extern crate sp_im;
98/// # use sp_im::conslist::{ConsList, cons};
99/// # fn main() {
100/// assert_eq!(cons(1, cons(2, cons(3, ConsList::new()))), conslist![1, 2, 3]);
101/// # }
102/// ```
103///
104/// # Historical Anecdote
105///
106/// The words `car` and `cdr` come from Lisp, and were the original
107/// names of the functions to get the left and the right hands of a
108/// cons cell, respectively. Cons cells in Lisp were simply containers
109/// for two values: the car and the cdr (pronounced 'cudder'), and,
110/// Lisp being an untyped language, had no restrictions on cons cells
111/// forming proper lists, but this is how they were most commonly
112/// used: forming singly linked lists by having the left hand side
113/// contain a value, and the right hand side a pointer to the rest of
114/// the list.
115///
116/// `cons` is short for 'construct', which is the easy one. `car`
117/// means 'contents of address register' and `cdr` means 'contents of
118/// decrement register.' These were the registers on the CPU of the
119/// IBM 704 computer (on which Lisp was originally implemented) used
120/// to hold the respective values.
121///
122/// Lisp also commonly provided pre-composed sequences of the `car`
123/// and `cdr` functions, such as `cadr`, the `car` of the `cdr`, ie.
124/// the second element of a list, and `cddr`, the list with the two
125/// first elements dropped. Pronunciation goes like this: `cadr` is,
126/// obviously, 'cadder', while `cddr` is 'cududder', and `caddr` (the
127/// `car` of the `cdr` of the `cdr`) is 'cadudder'. It can get a
128/// little subtle for the untrained ear.
129#[inline]
130pub fn cons<A, RA, RD>(car: RA, cdr: RD) -> ConsList<A>
131where
132 RA: Shared<A>,
133 RD: Borrow<ConsList<A>>, {
134 cdr.borrow().cons(car)
135}
136
137/// An immutable proper cons lists.
138///
139/// The cons list is perhaps the most basic immutable data structure:
140/// a singly linked list built out of 'cons cells,' which are cells
141/// containing two values, the left hand value being the head of the
142/// list and the right hand value being a reference to the rest of the
143/// list, or a `Nil` value denoting the end of the list.
144///
145/// Structure can be shared between lists (and is reference counted),
146/// and append to the front of a list is O(1). Cons cells keep track
147/// of the length of the list at the current position, as an extra
148/// optimisation, so getting the length of a list is also O(1).
149/// Otherwise, operations are generally O(n).
150pub struct ConsList<A>(Arc<ConsListNode<A>>);
151
152#[doc(hidden)]
153pub enum ConsListNode<A> {
154 Cons(usize, Arc<A>, ConsList<A>),
155 Nil,
156}
157
158impl<A> ConsList<A> {
159 /// Construct an empty list.
160 pub fn new() -> ConsList<A> { ConsList(Arc::new(Nil)) }
161
162 /// Construct a list with a single element.
163 pub fn singleton<R>(v: R) -> ConsList<A>
164 where R: Shared<A> {
165 ConsList(Arc::new(Cons(1, v.shared(), conslist![])))
166 }
167
168 /// Test whether a list is empty.
169 ///
170 /// Time: O(1)
171 pub fn is_empty(&self) -> bool {
172 match *self.0 {
173 Nil => true,
174 _ => false,
175 }
176 }
177
178 /// Construct a list with a new value prepended to the front of
179 /// the current list.
180 ///
181 /// Time: O(1)
182 pub fn cons<R>(&self, car: R) -> ConsList<A>
183 where R: Shared<A> {
184 ConsList(Arc::new(Cons(self.len() + 1, car.shared(), self.clone())))
185 }
186
187 /// Get the first element of a list.
188 ///
189 /// If the list is empty, `None` is returned.
190 ///
191 /// Time: O(1)
192 pub fn head(&self) -> Option<Arc<A>> {
193 match *self.0 {
194 Cons(_, ref a, _) => Some(a.clone()),
195 _ => None,
196 }
197 }
198
199 /// Get the tail of a list.
200 ///
201 /// The tail means all elements in the list after the first item
202 /// (the head). If the list only has one element, the result is an
203 /// empty list. If the list is empty, the result is `None`.
204 ///
205 /// Time: O(1)
206 pub fn tail(&self) -> Option<ConsList<A>> {
207 match *self.0 {
208 Cons(_, _, ref d) => Some(d.clone()),
209 Nil => None,
210 }
211 }
212
213 /// Get the head and the tail of a list.
214 ///
215 /// This function performs both the [`head`][head] function and
216 /// the [`tail`][tail] function in one go, returning a tuple of
217 /// the head and the tail, or [`None`][None] if the list is empty.
218 ///
219 /// # Examples
220 ///
221 /// This can be useful when pattern matching your way through a
222 /// list:
223 ///
224 /// ```
225 /// # #[macro_use] extern crate sp_im;
226 /// # use sp_im::conslist::{ConsList, cons};
227 /// # use std::fmt::Debug;
228 /// fn walk_through_list<A>(list: &ConsList<A>)
229 /// where A: Debug {
230 /// match list.uncons() {
231 /// None => (),
232 /// Some((ref head, ref tail)) => {
233 /// print!("{:?}", head);
234 /// walk_through_list(tail)
235 /// }
236 /// }
237 /// }
238 /// # fn main() {
239 /// # }
240 /// ```
241 ///
242 /// Time: O(1)
243 ///
244 /// [head]: #method.head
245 /// [tail]: #method.tail
246 /// [None]: https://doc.rust-lang.org/core/option/enum.Option.html#variant.None
247 pub fn uncons(&self) -> Option<(Arc<A>, ConsList<A>)> {
248 match *self.0 {
249 Nil => None,
250 Cons(_, ref a, ref d) => Some((a.clone(), d.clone())),
251 }
252 }
253
254 /// Get the two first elements and the tail of a list.
255 ///
256 /// This function performs both the [`head`][head] function twice and
257 /// the [`tail`][tail] function in one go, returning a tuple of
258 /// the double head and the tail, or [`None`][None] if the list is empty.
259 ///
260 /// # Examples
261 ///
262 /// This can be useful when pattern matching your way through a
263 /// list:
264 ///
265 /// ```
266 /// # #[macro_use] extern crate sp_im;
267 /// # use sp_im::conslist::{ConsList, cons};
268 /// # use std::fmt::Debug;
269 /// fn walk_through_list<A>(list: &ConsList<A>)
270 /// where A: Debug {
271 /// match list.uncons2() {
272 /// None => (),
273 /// Some((ref head, ref head2, ref tail)) => {
274 /// print!("{:?} {:?}", head, head2);
275 /// walk_through_list(tail)
276 /// }
277 /// }
278 /// }
279 /// # fn main() {
280 /// # }
281 /// ```
282 ///
283 /// Time: O(1)
284 ///
285 /// [head]: #method.head
286 /// [tail]: #method.tail
287 /// [None]: https://doc.rust-lang.org/core/option/enum.Option.html#variant.None
288 pub fn uncons2(&self) -> Option<(Arc<A>, Arc<A>, ConsList<A>)> {
289 self.uncons().and_then(|(a1, d)| d.uncons().map(|(a2, d)| (a1, a2, d)))
290 }
291
292 /// Get the length of a list.
293 ///
294 /// This operation is instant, because cons cells store the length
295 /// of the list they're the head of.
296 ///
297 /// Time: O(1)
298 ///
299 /// # Examples
300 ///
301 /// ```
302 /// # #[macro_use] extern crate sp_im;
303 /// # fn main() {
304 /// assert_eq!(5, conslist![1, 2, 3, 4, 5].len());
305 /// # }
306 /// ```
307 pub fn len(&self) -> usize {
308 match *self.0 {
309 Nil => 0,
310 Cons(l, ..) => l,
311 }
312 }
313
314 /// Append the list `right` to the end of the current list.
315 ///
316 /// Time: O(n)
317 ///
318 /// # Examples
319 ///
320 /// ```
321 /// # #[macro_use] extern crate sp_im;
322 /// # use sp_im::conslist::ConsList;
323 /// # fn main() {
324 /// assert_eq!(conslist![1, 2, 3].append(conslist![7, 8, 9]), conslist![
325 /// 1, 2, 3, 7, 8, 9
326 /// ]);
327 /// # }
328 /// ```
329 pub fn append<R>(&self, right: R) -> Self
330 where R: Borrow<Self> {
331 match *self.0 {
332 Nil => right.borrow().clone(),
333 Cons(_, ref a, ref d) => cons(a.clone(), &d.append(right)),
334 }
335 }
336
337 /// Construct a list which is the reverse of the current list.
338 ///
339 /// Time: O(n)
340 ///
341 /// # Examples
342 ///
343 /// ```
344 /// # #[macro_use] extern crate sp_im;
345 /// # use sp_im::conslist::ConsList;
346 /// # fn main() {
347 /// assert_eq!(conslist![1, 2, 3, 4, 5].reverse(), conslist![5, 4, 3, 2, 1]);
348 /// # }
349 /// ```
350 pub fn reverse(&self) -> ConsList<A> {
351 let mut out = ConsList::new();
352 for i in self.iter() {
353 out = out.cons(i);
354 }
355 out
356 }
357
358 /// Get an iterator over a list.
359 pub fn iter(&self) -> Iter<A> { Iter { current: self.clone() } }
360
361 /// Sort a list using a comparator function.
362 ///
363 /// Time: O(n log n)
364 pub fn sort_by<F>(&self, cmp: F) -> ConsList<A>
365 where F: Fn(&A, &A) -> Ordering {
366 fn merge<A>(
367 la: &ConsList<A>,
368 lb: &ConsList<A>,
369 cmp: &dyn Fn(&A, &A) -> Ordering,
370 ) -> ConsList<A> {
371 match (la.uncons(), lb.uncons()) {
372 (Some((ref a, _)), Some((ref b, ref lb1)))
373 if cmp(a, b) == Ordering::Greater =>
374 {
375 cons(b.clone(), &merge(la, lb1, cmp))
376 }
377 (Some((a, la1)), Some((..))) => cons(a.clone(), &merge(&la1, lb, cmp)),
378 (None, _) => lb.clone(),
379 (_, None) => la.clone(),
380 }
381 }
382
383 fn merge_pairs<A>(
384 l: &ConsList<ConsList<A>>,
385 cmp: &dyn Fn(&A, &A) -> Ordering,
386 ) -> ConsList<ConsList<A>> {
387 match l.uncons2() {
388 Some((a, b, rest)) => {
389 cons(merge(&a, &b, cmp), &merge_pairs(&rest, cmp))
390 }
391 _ => l.clone(),
392 }
393 }
394
395 fn merge_all<A>(
396 l: &ConsList<ConsList<A>>,
397 cmp: &dyn Fn(&A, &A) -> Ordering,
398 ) -> ConsList<A> {
399 match l.uncons() {
400 None => conslist![],
401 Some((ref a, ref d)) if d.is_empty() => a.deref().clone(),
402 _ => merge_all(&merge_pairs(l, cmp), cmp),
403 }
404 }
405
406 fn ascending<A>(
407 a: &Arc<A>,
408 f: &dyn Fn(ConsList<A>) -> ConsList<A>,
409 l: &ConsList<A>,
410 cmp: &dyn Fn(&A, &A) -> Ordering,
411 ) -> ConsList<ConsList<A>> {
412 match l.uncons() {
413 Some((ref b, ref lb)) if cmp(a, b) != Ordering::Greater => {
414 ascending(&b.clone(), &|ys| f(cons(a.clone(), &ys)), lb, cmp)
415 }
416 _ => cons(f(ConsList::singleton(a.clone())), &sequences(l, cmp)),
417 }
418 }
419
420 fn descending<A>(
421 a: &Arc<A>,
422 la: &ConsList<A>,
423 lb: &ConsList<A>,
424 cmp: &dyn Fn(&A, &A) -> Ordering,
425 ) -> ConsList<ConsList<A>> {
426 match lb.uncons() {
427 Some((ref b, ref bs)) if cmp(a, b) == Ordering::Greater => {
428 descending(&b.clone(), &cons(a.clone(), la), bs, cmp)
429 }
430 _ => cons(cons(a.clone(), la), &sequences(lb, cmp)),
431 }
432 }
433
434 fn sequences<A>(
435 l: &ConsList<A>,
436 cmp: &dyn Fn(&A, &A) -> Ordering,
437 ) -> ConsList<ConsList<A>> {
438 match l.uncons2() {
439 Some((ref a, ref b, ref xs)) if cmp(a, b) == Ordering::Greater => {
440 descending(&b.clone(), &ConsList::singleton(a.clone()), xs, cmp)
441 }
442 Some((ref a, ref b, ref xs)) => {
443 ascending(&b.clone(), &|l| cons(a.clone(), l), xs, cmp)
444 }
445 None => conslist![l.clone()],
446 }
447 }
448
449 merge_all(&sequences(self, &cmp), &cmp)
450 }
451
452 /// Compare the Arc pointers of two ConsList
453 pub fn ptr_eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.0, &other.0) }
454
455 /// Insert an item into a sorted list.
456 ///
457 /// Constructs a new list with the new item inserted before the
458 /// first item in the list which is larger than the new item,
459 /// as determined by the `Ord` trait.
460 ///
461 /// Time: O(n)
462 ///
463 /// # Examples
464 ///
465 /// ```
466 /// # #[macro_use] extern crate sp_im;
467 /// # fn main() {
468 /// assert_eq!(conslist![2, 4, 6].insert(5).insert(1).insert(3), conslist![
469 /// 1, 2, 3, 4, 5, 6
470 /// ]);
471 /// # }
472 /// ```
473 pub fn insert<T>(&self, item: T) -> ConsList<A>
474 where
475 A: Ord,
476 T: Shared<A>, {
477 self.insert_ref(item.shared())
478 }
479
480 fn insert_ref(&self, item: Arc<A>) -> ConsList<A>
481 where A: Ord {
482 match *self.0 {
483 Nil => ConsList(Arc::new(Cons(0, item, ConsList::new()))),
484 Cons(_, ref a, ref d) => {
485 if a.deref() > item.deref() {
486 self.cons(item)
487 }
488 else {
489 d.insert_ref(item).cons(a.clone())
490 }
491 }
492 }
493 }
494
495 /// Sort a list.
496 ///
497 /// Time: O(n log n)
498 ///
499 /// # Examples
500 ///
501 /// ```
502 /// # #[macro_use] extern crate sp_im;
503 /// # use sp_im::conslist::ConsList;
504 /// # use core::iter::FromIterator;
505 /// # fn main() {
506 /// assert_eq!(
507 /// conslist![2, 8, 1, 6, 3, 7, 5, 4].sort(),
508 /// ConsList::from_iter(1..9)
509 /// );
510 /// # }
511 /// ```
512 pub fn sort(&self) -> ConsList<A>
513 where A: Ord {
514 self.sort_by(Ord::cmp)
515 }
516}
517
518impl<A> ConsList<A> where A: Ord {}
519
520// Core traits
521
522impl<A> Clone for ConsList<A> {
523 /// Clone a list.
524 ///
525 /// Cons cells use `Arc` behind the scenes, so this is no more
526 /// expensive than cloning an `Arc` reference.
527 ///
528 /// Time: O(1)
529 fn clone(&self) -> Self {
530 match *self {
531 ConsList(ref node) => ConsList(node.clone()),
532 }
533 }
534}
535
536impl<A> Default for ConsList<A> {
537 /// `Default` for lists is the empty list.
538 fn default() -> Self { ConsList::new() }
539}
540
541#[cfg(not(has_specialisation))]
542impl<A> PartialEq for ConsList<A>
543where A: PartialEq
544{
545 /// Test if two lists are equal.
546 ///
547 /// This could potentially be an expensive operation, as we need to walk
548 /// both lists to test for equality. We can very quickly determine equality
549 /// if the lists have different lengths (can't be equal). Otherwise, we walk
550 /// the lists to compare values.
551 ///
552 /// Time: O(n)
553 fn eq(&self, other: &ConsList<A>) -> bool {
554 self.len() == other.len() && self.iter().eq(other.iter())
555 }
556}
557
558#[cfg(has_specialisation)]
559impl<A> PartialEq for ConsList<A>
560where A: PartialEq
561{
562 /// Test if two lists are equal.
563 ///
564 /// This could potentially be an expensive operation, as we need to walk
565 /// both lists to test for equality. We can very quickly determine equality
566 /// if the lists have different lengths (can't be equal). Otherwise, we walk
567 /// the lists to compare values.
568 ///
569 /// If `A` implements `Eq`, we have an additional shortcut available to us: if
570 /// both lists refer to the same cons cell, as determined by `Arc::ptr_eq`,
571 /// they have to be equal.
572 ///
573 /// Time: O(n)
574 default fn eq(&self, other: &ConsList<A>) -> bool {
575 self.len() == other.len() && self.iter().eq(other.iter())
576 }
577}
578
579#[cfg(has_specialisation)]
580impl<A> PartialEq for ConsList<A>
581where A: Eq
582{
583 /// Test if two lists are equal.
584 ///
585 /// This could potentially be an expensive operation, as we need to walk
586 /// both lists to test for equality. We can very quickly determine equality
587 /// if the lists have different lengths (can't be equal). Otherwise, we walk
588 /// the lists to compare values.
589 ///
590 /// If `A` implements `Eq`, we have an additional shortcut available to us: if
591 /// both lists refer to the same cons cell, as determined by `Arc::ptr_eq`,
592 /// they have to be equal.
593 ///
594 /// Time: O(n)
595 fn eq(&self, other: &ConsList<A>) -> bool {
596 Arc::ptr_eq(&self.0, &other.0)
597 || (self.len() == other.len() && self.iter().eq(other.iter()))
598 }
599}
600
601impl<A> Eq for ConsList<A> where A: Eq {}
602
603impl<A> Hash for ConsList<A>
604where A: Hash
605{
606 fn hash<H>(&self, state: &mut H)
607 where H: Hasher {
608 for i in self.iter() {
609 i.hash(state);
610 }
611 }
612}
613
614impl<'a, A> Add for &'a ConsList<A> {
615 type Output = ConsList<A>;
616
617 fn add(self, other: Self) -> Self::Output { self.append(other) }
618}
619
620impl<A> Add for ConsList<A> {
621 type Output = Self;
622
623 fn add(self, other: Self) -> Self::Output { self.append(&other) }
624}
625
626impl<A> Debug for ConsList<A>
627where A: Debug
628{
629 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
630 fn items<A>(l: &ConsList<A>, f: &mut Formatter<'_>) -> Result<(), Error>
631 where A: Debug {
632 match *l.0 {
633 Nil => Ok(()),
634 Cons(_, ref a, ref d) => {
635 write!(f, ", {:?}", a)?;
636 items(d, f)
637 }
638 }
639 }
640 write!(f, "[")?;
641 match *self.0 {
642 Nil => Ok(()),
643 Cons(_, ref a, ref d) => {
644 write!(f, "{:?}", a)?;
645 items(d, f)
646 }
647 }?;
648 write!(f, "]")
649 }
650}
651
652// Iterators
653
654/// An iterator for ConsList
655pub struct Iter<A> {
656 #[doc(hidden)]
657 current: ConsList<A>,
658}
659
660impl<A> Iterator for Iter<A> {
661 type Item = Arc<A>;
662
663 fn next(&mut self) -> Option<Self::Item> {
664 match self.current.uncons() {
665 None => None,
666 Some((ref a, ref d)) => {
667 self.current = d.clone();
668 Some(a.clone())
669 }
670 }
671 }
672
673 fn size_hint(&self) -> (usize, Option<usize>) {
674 let l = self.current.len();
675 (l, Some(l))
676 }
677}
678
679impl<A> ExactSizeIterator for Iter<A> {}
680
681impl<A> IntoIterator for ConsList<A> {
682 type IntoIter = Iter<A>;
683 type Item = Arc<A>;
684
685 fn into_iter(self) -> Iter<A> { self.iter() }
686}
687
688impl<A> Sum for ConsList<A> {
689 fn sum<I>(it: I) -> Self
690 where I: Iterator<Item = Self> {
691 it.fold(Self::new(), |a, b| a.append(b))
692 }
693}
694
695impl<A, T> FromIterator<T> for ConsList<A>
696where T: Shared<A>
697{
698 fn from_iter<I>(source: I) -> Self
699 where I: IntoIterator<Item = T> {
700 source.into_iter().fold(conslist![], |l, v| l.cons(v)).reverse()
701 }
702}
703
704// Conversions
705
706impl<'a, A, R> From<&'a [R]> for ConsList<A>
707where &'a R: Shared<A>
708{
709 fn from(slice: &'a [R]) -> Self {
710 slice.into_iter().map(|a| a.shared()).collect()
711 }
712}
713
714impl<A, R> From<Vec<R>> for ConsList<A>
715where R: Shared<A>
716{
717 fn from(vec: Vec<R>) -> Self { vec.into_iter().map(|a| a.shared()).collect() }
718}
719
720impl<'a, A, R> From<&'a Vec<R>> for ConsList<A>
721where &'a R: Shared<A>
722{
723 fn from(vec: &'a Vec<R>) -> Self {
724 vec.into_iter().map(|a| a.shared()).collect()
725 }
726}
727
728// QuickCheck
729
730// #[cfg(any(test))]
731// use arbitrary::{Arbitrary};
732#[cfg(any(test))]
733use quickcheck::{
734 Arbitrary,
735 Gen,
736};
737
738#[cfg(any(test, feature = "quickcheck"))]
739impl<A: Arbitrary + Sync> Arbitrary for ConsList<A> {
740 fn arbitrary(g: &mut Gen) -> Self { ConsList::from(Vec::<A>::arbitrary(g)) }
741}
742
743// Proptest
744
745//#[cfg(any(test, feature = "proptest"))]
746// pub mod proptest {
747// use super::*;
748// use ::proptest::strategy::{BoxedStrategy, Strategy, ValueTree};
749// use core::ops::Range;
750
751// /// A strategy for a cons list of a given size.
752// ///
753// /// # Examples
754// ///
755// /// ```rust,ignore
756// /// proptest! {
757// /// #[test]
758// /// fn proptest_a_conslist(ref l in conslist(".*", 10..100)) {
759// /// assert!(l.len() < 100);
760// /// assert!(l.len() >= 10);
761// /// }
762// /// }
763// /// ```
764// pub fn conslist<A: Strategy + 'static>(
765// element: A,
766// size: Range<usize>,
767// ) -> BoxedStrategy<ConsList<<A::Value as ValueTree>::Value>> {
768// ::proptest::collection::vec(element, size.clone())
769// .prop_map(ConsList::from)
770// .boxed()
771// }
772//}
773
774// Tests
775
776#[cfg(test)]
777mod test {
778 // use super::{proptest::*, *};
779 use super::*;
780 use crate::test::is_sorted;
781 // use ::proptest::*;
782 use quickcheck::quickcheck;
783 use alloc::string::String;
784
785 #[test]
786 fn exact_size_iterator() {
787 assert_eq!(10, ConsList::from_iter(1..11).iter().len());
788 }
789
790 #[test]
791 fn collect_from_iterator() {
792 let o: ConsList<i32> = vec![5, 6, 7].iter().cloned().collect();
793 assert_eq!(o, conslist![5, 6, 7]);
794 }
795
796 #[test]
797 fn disequality() {
798 let l = ConsList::from_iter(1..6);
799 assert_ne!(l, cons(0, &l));
800 assert_ne!(l, conslist![1, 2, 3, 4, 5, 6]);
801 }
802
803 #[test]
804 fn equality_of_empty_lists() {
805 let l1 = ConsList::<String>::new();
806 let l2 = ConsList::<String>::new();
807 assert_eq!(l1, l2);
808 }
809
810 quickcheck! {
811 fn length(vec: Vec<i32>) -> bool {
812 let list = ConsList::from(vec.clone());
813 vec.len() == list.len()
814 }
815
816 fn equality(vec: Vec<i32>) -> bool {
817 let list1 = ConsList::from(vec.clone());
818 let list2 = ConsList::from(vec.clone());
819 list1 == list2
820 }
821
822 fn order(vec: Vec<i32>) -> bool {
823 let list = ConsList::from(vec.clone());
824 list.iter().map(|a| *a).eq(vec.into_iter())
825 }
826
827 fn reverse_a_list(l: ConsList<i32>) -> bool {
828 let vec: Vec<i32> = l.iter().map(|v| *v).collect();
829 let rev = ConsList::from_iter(vec.into_iter().rev());
830 l.reverse() == rev
831 }
832
833 fn append_two_lists(xs: ConsList<i32>, ys: ConsList<i32>) -> bool {
834 let extended = ConsList::from_iter(
835 xs.iter().map(|v| *v).chain(ys.iter().map(|v| *v))
836 );
837 xs.append(&ys) == extended
838 }
839
840 fn sort_a_list(l: ConsList<i32>) -> bool {
841 let sorted = l.sort();
842 l.len() == sorted.len() && is_sorted(sorted)
843 }
844 }
845}