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}