Skip to content

Functional system redesign #57

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
*.rlib
*.dll

.vscode

# Executables
*.exe

Expand Down
90 changes: 90 additions & 0 deletions src/functional.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//! Functional programming with generic sequences

use core::iter::FromIterator;

use super::ArrayLength;
use sequence::*;

/// Defines the relationship between one generic sequence and another,
/// for operations such as `map` and `zip`.
pub unsafe trait MappedGenericSequence<T, U>: GenericSequence<T>
where
Self::Length: ArrayLength<U>,
{
/// Mapped sequence type
type Mapped: GenericSequence<U, Length=Self::Length>;
}

unsafe impl<'a, T, U, S: MappedGenericSequence<T, U>> MappedGenericSequence<T, U> for &'a S
where
&'a S: GenericSequence<T>,
S: GenericSequence<T, Length=<&'a S as GenericSequence<T>>::Length>,
<S as GenericSequence<T>>::Length: ArrayLength<U>,
{
type Mapped = <S as MappedGenericSequence<T, U>>::Mapped;
}

unsafe impl<'a, T, U, S: MappedGenericSequence<T, U>> MappedGenericSequence<T, U> for &'a mut S
where
&'a mut S: GenericSequence<T>,
S: GenericSequence<T, Length=<&'a mut S as GenericSequence<T>>::Length>,
<S as GenericSequence<T>>::Length: ArrayLength<U>,
{
type Mapped = <S as MappedGenericSequence<T, U>>::Mapped;
}

/// Accessor type for a mapped generic sequence
pub type MappedSequence<S, T, U> = <<S as MappedGenericSequence<T, U>>::Mapped as GenericSequence<U>>::Sequence;

/// Defines functional programming methods for generic sequences
pub unsafe trait FunctionalSequence<T>: GenericSequence<T> {
/// Maps a `GenericSequence` to another `GenericSequence`.
///
/// If the mapping function panics, any already initialized elements in the new sequence
/// will be dropped, AND any unused elements in the source sequence will also be dropped.
fn map<U, F>(self, f: F) -> MappedSequence<Self, T, U>
where
Self: MappedGenericSequence<T, U>,
Self::Length: ArrayLength<U>,
F: FnMut(Self::Item) -> U,
{
FromIterator::from_iter(self.into_iter().map(f))
}

/// Combines two `GenericSequence` instances and iterates through both of them,
/// initializing a new `GenericSequence` with the result of the zipped mapping function.
///
/// If the mapping function panics, any already initialized elements in the new sequence
/// will be dropped, AND any unused elements in the source sequences will also be dropped.
#[inline]
fn zip<B, Rhs, U, F>(self, rhs: Rhs, f: F) -> MappedSequence<Self, T, U>
where
Self: MappedGenericSequence<T, U>,
Rhs: MappedGenericSequence<B, U, Mapped=MappedSequence<Self, T, U>>,
Self::Length: ArrayLength<B> + ArrayLength<U>,
Rhs: GenericSequence<B, Length=Self::Length>,
F: FnMut(Self::Item, Rhs::Item) -> U,
{
rhs.inverted_zip2(self, f)
}

/// Folds (or reduces) a sequence of data into a single value.
///
/// If the fold function panics, any unused elements will be dropped.
fn fold<U, F>(self, init: U, f: F) -> U
where
F: FnMut(U, Self::Item) -> U,
{
self.into_iter().fold(init, f)
}
}

unsafe impl<'a, T, S: GenericSequence<T>> FunctionalSequence<T> for &'a S
where
&'a S: GenericSequence<T>,
{}

unsafe impl<'a, T, S: GenericSequence<T>> FunctionalSequence<T> for &'a mut S
where
&'a mut S: GenericSequence<T>,
{}
7 changes: 5 additions & 2 deletions src/impls.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use super::{ArrayLength, GenericArray};
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use core::hash::{Hash, Hasher};

use super::{ArrayLength, GenericArray};
use sequence::*;
use functional::*;

impl<T: Default, N> Default for GenericArray<T, N>
where
N: ArrayLength<T>,
Expand All @@ -19,7 +22,7 @@ where
N: ArrayLength<T>,
{
fn clone(&self) -> GenericArray<T, N> {
self.map_ref(|x| x.clone())
self.map(|x| x.clone())
}
}

Expand Down
29 changes: 19 additions & 10 deletions src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pub struct GenericArrayIter<T, N: ArrayLength<T>> {
index_back: usize,
}

unsafe impl<T: Send, N: ArrayLength<T>> Send for GenericArrayIter<T, N> {}
unsafe impl<T: Sync, N: ArrayLength<T>> Sync for GenericArrayIter<T, N> {}

impl<T, N> IntoIterator for GenericArray<T, N>
where
N: ArrayLength<T>,
Expand All @@ -34,6 +37,7 @@ impl<T, N> Drop for GenericArrayIter<T, N>
where
N: ArrayLength<T>,
{
#[inline]
fn drop(&mut self) {
// Drop values that are still alive.
for p in &mut self.array[self.index..self.index_back] {
Expand All @@ -50,23 +54,28 @@ where
{
type Item = T;

#[inline]
fn next(&mut self) -> Option<T> {
if self.len() > 0 {
unsafe {
let p = self.array.get_unchecked(self.index);
self.index += 1;
Some(ptr::read(p))
}
if self.index < self.index_back {
let p = unsafe {
Some(ptr::read(self.array.get_unchecked(self.index)))
};

self.index += 1;

p
} else {
None
}
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}

#[inline]
fn count(self) -> usize {
self.len()
}
Expand Down Expand Up @@ -95,11 +104,11 @@ where
N: ArrayLength<T>,
{
fn next_back(&mut self) -> Option<T> {
if self.len() > 0 {
if self.index < self.index_back {
self.index_back -= 1;

unsafe {
let p = self.array.get_unchecked(self.index_back);
Some(ptr::read(p))
Some(ptr::read(self.array.get_unchecked(self.index_back)))
}
} else {
None
Expand All @@ -114,4 +123,4 @@ where
fn len(&self) -> usize {
self.index_back - self.index
}
}
}
Loading