#![deny(missing_docs)]
#![deny(warnings)]
#![doc(html_root_url = "https://docs.rs/rando/0.2.0")]
#![doc(test(attr(deny(warnings))))]
extern crate get_trait;
extern crate iter_trait;
extern crate len_trait;
extern crate rand;
extern crate smallvec;
#[cfg(test)]
#[macro_use]
extern crate quickcheck;
#[cfg(test)]
#[macro_use]
extern crate version_sync;
use get_trait::Get;
use iter_trait::HasMapData;
use len_trait::Len;
use rand::distributions::Distribution;
use rand::distributions::Range;
use smallvec::SmallVec;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::fmt::Debug;
use std::ops::Deref;
#[cfg(test)]
mod tests;
pub const DEFAULT_MEM_LEN: usize = 32;
type DefaultMemory<T> = SmallVec<[T; DEFAULT_MEM_LEN]>;
pub trait Rando: Get + Len + HasMapData
where
Self::Key: PartialEq,
{
#[inline]
fn rand_iter(&self) -> RandIter<Self>;
}
impl<T: ?Sized> Rando for T
where
T: Get + Len + HasMapData,
T::Key: PartialEq,
{
#[inline]
fn rand_iter(&self) -> RandIter<Self> {
RandIter {
collection: self,
rng: rand::thread_rng(),
range: Default::default(),
memory: Default::default(),
}
}
}
#[derive(Clone, Debug)]
pub struct RandIter<
'coll,
Collection: ?Sized,
Mem = DefaultMemory<<Collection as HasMapData>::Key>,
Rng = rand::ThreadRng,
> where
Collection: 'coll + Get + Len + HasMapData,
Mem: Memory<Collection::Key>,
Rng: rand::Rng,
{
collection: &'coll Collection,
rng: Rng,
range: Option<Range<usize>>,
memory: Mem,
}
impl<'coll, Collection: ?Sized, Mem, Rng> RandIter<'coll, Collection, Mem, Rng>
where
Collection: 'coll
+ Get
+ Len
+ HasMapData,
Mem: Memory<Collection::Key>,
Rng: rand::Rng,
{
#[inline]
pub fn with_rng<NewRng>(self, rng: NewRng) -> RandIter<'coll, Collection, Mem, NewRng>
where
NewRng: rand::Rng,
{
let RandIter {
collection,
rng: _,
range,
memory,
} = self;
RandIter {
collection,
rng,
range,
memory,
}
}
#[inline]
pub fn with_memory<NewMem>(self) -> RandIter<'coll, Collection, NewMem, Rng>
where
NewMem: Memory<Collection::Key>,
{
let RandIter {
collection,
rng,
range,
memory: _,
} = self;
RandIter {
collection,
rng,
range,
memory: Default::default(),
}
}
}
impl<'coll, Collection: ?Sized, Mem, Rng> Iterator
for RandIter<'coll, Collection, Mem, Rng>
where
Collection: Get + Len + HasMapData<Key = usize>,
Mem: Memory<Collection::Key>,
Rng: rand::Rng,
{
type Item = &'coll Collection::Value;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let k = choose_key(
self.collection,
&mut self.rng,
&mut self.range,
&mut self.memory,
)?;
let v = self.collection.get(&k).expect(
"`rando`: Internal error: \
`choose_key` chose an invalid key",
);
Some(v)
}
}
#[inline]
fn choose_key<'coll, Collection: ?Sized, Mem, Rng>(
collection: &'coll Collection,
rng: &mut Rng,
range: &mut Option<Range<usize>>,
keys_already_chosen: &mut Mem,
) -> Option<usize>
where
Collection: Get + Len + HasMapData<Key = usize>,
Mem: Memory<Collection::Key>,
Rng: rand::Rng,
{
if keys_already_chosen.len() == collection.len() {
return None;
}
if range.is_none() && collection.len() > 0 {
*range = Some(Range::new(0, collection.len()));
}
let range = match range {
&mut Some(ref r) => r,
&mut None => return None,
};
loop {
let k = range.sample(rng);
if !keys_already_chosen.contains(&k) {
keys_already_chosen.push(k);
return Some(k);
}
}
}
pub trait Memory<K>: Default {
#[inline]
fn len(&self) -> usize;
#[inline]
fn contains(&self, key: &K) -> bool;
#[inline]
fn push(&mut self, key: K);
}
impl<K, A> Memory<K> for SmallVec<A>
where
K: PartialEq,
A: smallvec::Array<Item = K>,
{
#[inline]
fn len(&self) -> usize {
self.deref().len()
}
#[inline]
fn contains(&self, key: &K) -> bool {
self.deref().contains(key)
}
#[inline]
fn push(&mut self, key: K) {
SmallVec::push(self, key)
}
}
impl<K> Memory<K> for Vec<K>
where
K: PartialEq,
{
#[inline]
fn len(&self) -> usize {
self.deref().len()
}
#[inline]
fn contains(&self, key: &K) -> bool {
self.deref().contains(key)
}
#[inline]
fn push(&mut self, key: K) {
Vec::push(self, key)
}
}
impl<K> Memory<K> for BTreeSet<K>
where
K: Ord,
{
#[inline]
fn len(&self) -> usize {
BTreeSet::len(self)
}
#[inline]
fn contains(&self, key: &K) -> bool {
BTreeSet::contains(self, key)
}
#[inline]
fn push(&mut self, key: K) {
BTreeSet::insert(self, key);
}
}
#[inline]
pub fn assert_eq_up_to_order<I1, I2, Item>(i1: I1, i2: I2)
where
I1: IntoIterator<Item = Item>,
I2: IntoIterator<Item = Item>,
Item: Ord + Debug,
{
let mut counts_1 = BTreeMap::<Item, usize>::new();
let mut counts_2 = BTreeMap::<Item, usize>::new();
#[inline]
fn count<I, Item>(it: I, counts: &mut BTreeMap<Item, usize>)
where
I: IntoIterator<Item = Item>,
Item: Ord,
{
for item in it {
*counts.entry(item).or_insert(0) += 1;
}
}
count(i1, &mut counts_1);
count(i2, &mut counts_2);
assert_eq!(counts_1, counts_2);
}