commit
ccb0bde71f
@ -0,0 +1,3 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
*~
|
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "ad-hoc-iter"
|
||||
version = "0.1.0"
|
||||
authors = ["Avril <flanchan@cumallover.me>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
@ -0,0 +1,147 @@
|
||||
//! Iterator types that can be 0, 1, or more.
|
||||
//!
|
||||
//! This exists to prevent needless heap allocations.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
/// An iterator that can yield `0,1,2+` items
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MaybeMany<T,U>
|
||||
{
|
||||
None,
|
||||
One(T),
|
||||
Many(U),
|
||||
}
|
||||
|
||||
impl<T,U> MaybeMany<T,U>
|
||||
{
|
||||
/// Try to guess the size.
|
||||
///
|
||||
/// * `None` => `Some(0)`
|
||||
/// * `One(_)` => `Some(1)`
|
||||
/// * `Many(_) => `None`
|
||||
#[inline] pub const fn size_hint(&self) -> Option<usize>
|
||||
{
|
||||
match self {
|
||||
Self::None => Some(0),
|
||||
Self::One(_) => Some(1),
|
||||
Self::Many(_) => None
|
||||
}
|
||||
}
|
||||
/// Is this an empty instance
|
||||
#[inline] pub const fn is_none(&self) -> bool
|
||||
{
|
||||
if let Self::None = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
/// Is this a single value instance?
|
||||
#[inline] pub const fn is_single(&self) -> bool
|
||||
{
|
||||
if let Self::One(_) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
/// Is this a 2+ value instance?
|
||||
#[inline] pub const fn is_many(&self) -> bool
|
||||
{
|
||||
if let Self::Many(_) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
/// Map the single value with this function
|
||||
#[inline] pub fn map_many<F, A>(self, fun: F) -> MaybeMany<T, A>
|
||||
where F: FnOnce(U) -> A,
|
||||
A: IntoIterator<Item=T>
|
||||
{
|
||||
match self {
|
||||
Self::One(t) => MaybeMany::One(t),
|
||||
Self::Many(m) => MaybeMany::Many(fun(m)),
|
||||
Self::None => MaybeMany::None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Map the single value with this function
|
||||
#[inline] fn map_one<F>(self, fun: F) -> MaybeMany<T,U>
|
||||
where F: FnOnce(T) -> T
|
||||
{
|
||||
match self {
|
||||
Self::One(t) => MaybeMany::One(fun(t)),
|
||||
Self::Many(m) => MaybeMany::Many(m),
|
||||
Self::None => MaybeMany::None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Map both the single and many results
|
||||
fn map<Fo, Fm, A,B>(self, one: Fo, many: Fm) -> MaybeMany<A,B>
|
||||
where Fo: FnOnce(T) -> A,
|
||||
Fm: FnOnce(U) -> B,
|
||||
B: IntoIterator<Item=A>
|
||||
{
|
||||
match self {
|
||||
Self::One(o) => MaybeMany::One(one(o)),
|
||||
Self::Many(m) => MaybeMany::Many(many(m)),
|
||||
Self::None => MaybeMany::None,
|
||||
}
|
||||
}
|
||||
/// Take the value from this instance and replace it with nothing.
|
||||
#[inline] pub fn take(&mut self) -> Self
|
||||
{
|
||||
std::mem::replace(self, Self::None)
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator for `MaybeMany` instances.
|
||||
#[non_exhaustive] #[derive(Debug, Clone)]
|
||||
pub enum MaybeManyIter<T,U>
|
||||
{
|
||||
None,
|
||||
One(std::iter::Once<T>),
|
||||
Many(std::iter::Fuse<U>),
|
||||
}
|
||||
|
||||
impl<T,U> Iterator for MaybeManyIter<T,U>
|
||||
where U: Iterator<Item=T>
|
||||
{
|
||||
type Item = T;
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
match self {
|
||||
Self::None => None,
|
||||
Self::One(one) => one.next(),
|
||||
Self::Many(many) => many.next(),
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match self {
|
||||
Self::None => (0, Some(0)),
|
||||
Self::One(_) => (1, Some(1)),
|
||||
Self::Many(many) => many.size_hint(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T,U: Iterator<Item=T>> std::iter::FusedIterator for MaybeManyIter<T,U>{}
|
||||
impl<T,U: Iterator<Item=T>> std::iter::ExactSizeIterator for MaybeManyIter<T,U>
|
||||
where U: ExactSizeIterator{}
|
||||
|
||||
impl<T, U: IntoIterator<Item=T>> IntoIterator for MaybeMany<T, U>
|
||||
{
|
||||
type Item= T;
|
||||
type IntoIter = MaybeManyIter<T, <U as IntoIterator>::IntoIter>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter
|
||||
{
|
||||
match self {
|
||||
Self::None => MaybeManyIter::None,
|
||||
Self::One(one) => MaybeManyIter::One(std::iter::once(one)),
|
||||
Self::Many(many) => MaybeManyIter::Many(many.into_iter().fuse())
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
//! Iterator types
|
||||
|
||||
pub mod either;
|
||||
|
||||
/// A bespoke iterator type with an exact size over elements.
|
||||
///
|
||||
/// This has an advantage over using simple inline slices (e.g `[1,2,3]`) as they currently cannot implement `IntoIterator` properly, and will always yield references.
|
||||
/// This can be a hinderance when you want an ad-hoc iterator of non-`Copy` items.
|
||||
/// The iterator types created from this macro consume the values.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use ad_hoc_iter::iter;
|
||||
/// let sum: i32 = iter![1, 2].chain(3..=4).chain(iter![5, 6]).sum();
|
||||
/// assert_eq!(sum, 21);
|
||||
/// ```
|
||||
#[macro_export] macro_rules! iter {
|
||||
(@) => (0usize);
|
||||
(@ $x:tt $($xs:tt)* ) => (1usize + $crate::iter!(@ $($xs)*));
|
||||
|
||||
($($value:expr),*) => {
|
||||
{
|
||||
use ::std::mem::MaybeUninit;
|
||||
use ::std::ops::Drop;
|
||||
struct Arr<T>([MaybeUninit<T>; $crate::iter!(@ $($value)*)], usize);
|
||||
impl<T> Arr<T>
|
||||
{
|
||||
const LEN: usize = $crate::iter!(@ $($value)*);
|
||||
}
|
||||
impl<T> Iterator for Arr<T>
|
||||
{
|
||||
type Item = T;
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
if self.1 >= self.0.len() {
|
||||
None
|
||||
} else {
|
||||
//take one
|
||||
let one = unsafe {
|
||||
::std::mem::replace(&mut self.0[self.1], MaybeUninit::uninit()).assume_init()
|
||||
};
|
||||
self.1+=1;
|
||||
Some(one)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline] fn size_hint(&self) -> (usize, Option<usize>)
|
||||
{
|
||||
(Self::LEN, Some(Self::LEN))
|
||||
}
|
||||
}
|
||||
impl<T> ::std::iter::FusedIterator for Arr<T>{}
|
||||
impl<T> ::std::iter::ExactSizeIterator for Arr<T>{}
|
||||
|
||||
impl<T> Drop for Arr<T>
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
if ::std::mem::needs_drop::<T>() {
|
||||
for idx in self.1..self.0.len() {
|
||||
unsafe {
|
||||
::std::mem::replace(&mut self.0[idx], MaybeUninit::uninit()).assume_init();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Arr([$(MaybeUninit::new($value)),*], 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests
|
||||
{
|
||||
#[test]
|
||||
fn iter_over()
|
||||
{
|
||||
const EXPECT: usize = 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1;
|
||||
let iter = iter![10,9,8,7,6,5,4,3,2,1];
|
||||
|
||||
assert_eq!(iter.len(), 10);
|
||||
assert_eq!(iter.sum::<usize>(), EXPECT);
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_copy()
|
||||
{
|
||||
macro_rules! string {
|
||||
($val:literal) => (String::from($val));
|
||||
}
|
||||
|
||||
const EXPECT: &str = "Hello world!";
|
||||
let whole: String = iter![string!("Hell"), string!("o "), string!("world"), string!("!")].collect();
|
||||
assert_eq!(EXPECT, &whole[..]);
|
||||
}
|
||||
}
|
Loading…
Reference in new issue