Browse Source

added README

master
Avril 1 year ago
parent
commit
9cf85bd7fe
Signed by: flanchan GPG Key ID: 284488987C31F630
  1. 9
      Cargo.toml
  2. 49
      README.md
  3. 134
      src/lib.rs
  4. 0
      src/maybe.rs

9
Cargo.toml

@ -1,9 +1,16 @@
[package]
name = "ad-hoc-iter"
version = "0.1.0"
description = "Ad-hoc exact size owning iterator macro and other optional utils"
keywords = ["iterator", "macro", "iter"]
authors = ["Avril <flanchan@cumallover.me>"]
edition = "2018"
license = "mit"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["maybe-many"]
# Enable the `maybe` module
maybe-many = []
[dependencies]

49
README.md

@ -0,0 +1,49 @@
# Ad-hoc owning iterator types
This crate defines the macro `iter!` which produces ad-hoc iterator types that own their values and have compile-time known exact sizes.
# Usage
This macro can be used exactly like `vec!`, except it produces an `impl Iterator` that does not allocate.
This `impl Iterator` yields the values directly, **not references** to the values.
This can be useful for when you want a ad-hoc iterator of a non-copy type, as sized slices and arrays currently do not implement `IntoIterator` in a way that moves their values, instead they yield references, causing the need for cloning.
The `iter!` macro's iterator types move their values on calls to `next()` instead of returning references, and drop the non-consumed values when the iterator is dropped itself.
## Example
Concatenating a 'slice' of `String` without cloning.
``` rust
let whole: String = iter![String::from("Hell"),
String::from("o "),
String::from("world"),
String::from("!")]
.collect();
assert_eq!("Hello world!", &whole[..]);
```
## Functions
The iterator types also have a few associated functions.
### The length of the whole iterator
```rust
pub const fn len(&self) -> usize
```
### The rest of the iterator that has not been consumed.
```rust
pub fn rest(&self) -> &[T]
```
### The whole array.
All values that have not been consumed are initialised, values that have been consumed are uninitialised.
```rust
pub fn array(&self) -> &[MaybeUninit<T>; Self::LEN]
```
### How many items have since been consumed.
```rust
pub const fn consumed(&self) -> usize
```
# License
MIT

134
src/lib.rs

@ -1,12 +1,16 @@
//! Iterator types
//! Ad-hoc exact size owning iterator macro and other optional utils
//!
//! The macro can be used exactly as `vec!`.
pub mod either;
#[cfg(feature="maybe-many")] pub mod maybe;
/// 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.
/// It has the advantage over `vec![].into_iter()` as there are no heap allocations needed and size of the iterator is known at compile time.
///
/// # Example
/// ```
@ -14,9 +18,56 @@ pub mod either;
/// let sum: i32 = iter![1, 2].chain(3..=4).chain(iter![5, 6]).sum();
/// assert_eq!(sum, 21);
/// ```
/// # Functions
/// The iterators returned from this method have these associated functions:
///
/// ## The length of the whole iterator
/// ```
/// pub const fn len(&self) -> usize
/// ```
///
/// ## The rest of the iterator that has not been consumed.
/// ```
/// pub fn rest(&self) -> &[T]
/// ```
///
/// ## The whole array.
/// All values that have not been consumed are initialised, values that have been consumed are uninitialised.
/// ```
/// pub fn array(&self) -> &[MaybeUninit<T>; Self::LEN]
/// ```
///
/// ## How many items have since been consumed.
/// ```
/// pub const fn consumed(&self) -> usize
/// ```
#[macro_export] macro_rules! iter {
(@) => (0usize);
(@ $x:tt $($xs:tt)* ) => (1usize + $crate::iter!(@ $($xs)*));
() => {
{
#[derive(Debug)]
struct Empty;
impl Iterator for Empty
{
type Item = std::convert::Infallible;
fn next(&mut self) -> Option<Self::Item>
{
None
}
fn size_hint(&self) -> (usize, Option<usize>)
{
(0, Some(0))
}
}
impl ::std::iter::FusedIterator for Empty{}
impl ::std::iter::ExactSizeIterator for Empty{}
Empty
}
};
($($value:expr),*) => {
{
@ -25,7 +76,53 @@ pub mod either;
struct Arr<T>([MaybeUninit<T>; $crate::iter!(@ $($value)*)], usize);
impl<T> Arr<T>
{
#![allow(dead_code)]
/// The length of the whole iterator
const LEN: usize = $crate::iter!(@ $($value)*);
/// The length of the whole iterator
// This exists as an associated function because this type is opaque.
#[inline] pub const fn len(&self) -> usize
{
Self::LEN
}
/// Consume this iterator into the backing buffer.
///
/// # Safety
/// Non-consumed items are safe to `assume_init`. However, items that have already been consumed are uninitialised.
fn into_inner(self) -> [MaybeUninit<T>; $crate::iter!(@ $($value)*)]
{
//XXX: We will have to do something really unsafe for this to work on stable...
todo!()
}
/// The rest of the iterator that has not been consumed.
///
// # Safety
// All values in this slice are initialised.
#[inline] pub fn rest(&self) -> &[T]
{
let slice = &self.0[self.1..];
//std::mem::MaybeUninit::slice_get_ref(&self.0[self.1..]) //nightly only...
unsafe { &*(slice as *const [std::mem::MaybeUninit<T>] as *const [T]) }
}
/// The whole array.
///
/// # Safety
/// All values that have not been consumed are initialised, values that have been consumed are uninitialised.
#[inline] pub fn array(&self) -> &[MaybeUninit<T>; $crate::iter!(@ $($value)*)]
{
&self.0
}
/// How many items have since been consumed.
pub const fn consumed(&self) -> usize
{
self.1
}
}
impl<T> Iterator for Arr<T>
{
@ -84,15 +181,42 @@ mod tests
}
macro_rules! string {
($val:literal) => (String::from($val));
}
#[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[..]);
}
#[test]
fn empty()
{
let empty: Vec<_> = iter![].collect();
assert_eq!(empty.len(), 0);
}
#[test]
fn assoc()
{
let mut iter = iter![1,2,3,4];
assert_eq!(iter.len(), 4);
iter.next();
assert_eq!(iter.consumed(), 1);
assert_eq!(iter.rest(), &[2,3,4]);
let mut iter = iter![string!("Hell"), string!("o "), string!("world"), string!("!")];
iter.next();
iter.next();
assert_eq!(iter.rest().iter().map(|x| x.as_str()).collect::<Vec<_>>().as_slice(), &["world", "!"]);
}
}

0
src/either.rs → src/maybe.rs

Loading…
Cancel
Save