Просмотр исходного кода

Implemented 'WithProducer' and 'WithIndexedProducer' traits

master
Bergmann89 5 лет назад
Родитель
Сommit
592aaeb54a
24 измененных файлов: 670 добавлений и 308 удалений
  1. +1
    -42
      asparit/src/core/iterator.rs
  2. +4
    -1
      asparit/src/core/mod.rs
  3. +46
    -0
      asparit/src/core/producer.rs
  4. +38
    -19
      asparit/src/iter/chain.rs
  5. +31
    -14
      asparit/src/iter/cloned.rs
  6. +31
    -14
      asparit/src/iter/copied.rs
  7. +9
    -1
      asparit/src/iter/filter.rs
  8. +10
    -1
      asparit/src/iter/filter_map.rs
  9. +20
    -1
      asparit/src/iter/flatten.rs
  10. +20
    -1
      asparit/src/iter/fold.rs
  11. +33
    -16
      asparit/src/iter/inspect.rs
  12. +36
    -19
      asparit/src/iter/intersperse.rs
  13. +35
    -16
      asparit/src/iter/map.rs
  14. +38
    -17
      asparit/src/iter/map_init.rs
  15. +38
    -17
      asparit/src/iter/map_with.rs
  16. +28
    -13
      asparit/src/iter/panic_fuse.rs
  17. +31
    -16
      asparit/src/iter/splits.rs
  18. +22
    -1
      asparit/src/iter/try_fold.rs
  19. +33
    -16
      asparit/src/iter/update.rs
  20. +30
    -13
      asparit/src/iter/while_some.rs
  21. +2
    -1
      asparit/src/lib.rs
  22. +22
    -14
      asparit/src/std/range.rs
  23. +55
    -27
      asparit/src/std/slice.rs
  24. +57
    -28
      asparit/src/std/vec.rs

+ 1
- 42
asparit/src/core/iterator.rs Просмотреть файл

@@ -1,10 +1,7 @@
use std::cmp::{Ord, Ordering};
use std::iter::IntoIterator;

use super::{
Consumer, Executor, FromParallelIterator, IndexedProducerCallback, IntoParallelIterator,
ProducerCallback, Reducer,
};
use super::{Consumer, Executor, FromParallelIterator, IntoParallelIterator, Reducer};

use crate::{
iter::{
@@ -83,25 +80,6 @@ pub trait ParallelIterator<'a>: Sized + Send {
D: Send + 'a,
R: Reducer<D> + Send + 'a;

/// Internal method used to define the behavior of this parallel
/// iterator. You should not need to call this directly.
///
/// This method converts the iterator into a producer P and then
/// invokes `callback.callback()` with P. Note that the type of
/// this producer is not defined as part of the API, since
/// `callback` must be defined generically for all producers. This
/// allows the producer type to contain references; it also means
/// that parallel iterators can adjust that type without causing a
/// breaking change.
///
/// See the [README] for more details on the internals of parallel
/// iterators.
///
/// [README]: README.md
fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>;

/// Internal method used to define the behavior of this parallel
/// iterator. You should not need to call this directly.
///
@@ -1776,25 +1754,6 @@ pub trait IndexedParallelIterator<'a>: ParallelIterator<'a> {
D: Send + 'a,
R: Reducer<D> + Send + 'a;

/// Internal method used to define the behavior of this parallel
/// iterator. You should not need to call this directly.
///
/// This method converts the iterator into a producer P and then
/// invokes `callback.callback()` with P. Note that the type of
/// this producer is not defined as part of the API, since
/// `callback` must be defined generically for all producers. This
/// allows the producer type to contain references; it also means
/// that parallel iterators can adjust that type without causing a
/// breaking change.
///
/// See the [README] for more details on the internals of parallel
/// iterators.
///
/// [README]: README.md
fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>;

/// Produces an exact count of how many items this iterator will
/// produce, presuming no panic occurs.
///


+ 4
- 1
asparit/src/core/mod.rs Просмотреть файл

@@ -20,6 +20,9 @@ pub use folder::Folder;
pub use from_iter::FromParallelIterator;
pub use into_iter::{IntoParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator};
pub use iterator::{IndexedParallelIterator, ParallelIterator};
pub use producer::{IndexedProducer, IndexedProducerCallback, Producer, ProducerCallback};
pub use producer::{
IndexedProducer, IndexedProducerCallback, Producer, ProducerCallback, WithIndexedProducer,
WithProducer,
};
pub use reducer::Reducer;
pub use setup::{Setup, WithSetup};

+ 46
- 0
asparit/src/core/producer.rs Просмотреть файл

@@ -91,6 +91,52 @@ pub trait IndexedProducer: WithSetup + Send + Sized {
}
}

pub trait WithProducer<'a> {
type Item: Send + 'a;

/// Internal method used to define the behavior of this parallel
/// iterator. You should not need to call this directly.
///
/// This method converts the iterator into a producer P and then
/// invokes `callback.callback()` with P. Note that the type of
/// this producer is not defined as part of the API, since
/// `callback` must be defined generically for all producers. This
/// allows the producer type to contain references; it also means
/// that parallel iterators can adjust that type without causing a
/// breaking change.
///
/// See the [README] for more details on the internals of parallel
/// iterators.
///
/// [README]: README.md
fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>;
}

pub trait WithIndexedProducer<'a> {
type Item: Send + 'a;

/// Internal method used to define the behavior of this parallel
/// iterator. You should not need to call this directly.
///
/// This method converts the iterator into a producer P and then
/// invokes `callback.callback()` with P. Note that the type of
/// this producer is not defined as part of the API, since
/// `callback` must be defined generically for all producers. This
/// allows the producer type to contain references; it also means
/// that parallel iterators can adjust that type without causing a
/// breaking change.
///
/// See the [README] for more details on the internals of parallel
/// iterators.
///
/// [README]: README.md
fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>;
}

/// The `ProducerCallback` trait is a kind of generic closure,
/// [analogous to `FnOnce`][FnOnce]. See [the corresponding section in
/// the plumbing README][r] for more details.


+ 38
- 19
asparit/src/iter/chain.rs Просмотреть файл

@@ -2,7 +2,8 @@ use std::iter::{DoubleEndedIterator, ExactSizeIterator, Iterator};

use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

/* Chain */
@@ -52,16 +53,6 @@ where
E::join(left, right, reducer)
}

fn with_producer<CB>(self, base: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.iterator_1.with_producer(ChainCallback1 {
base,
iterator_2: self.iterator_2,
})
}

fn len_hint_opt(&self) -> Option<usize> {
let len_1 = self.iterator_1.len_hint_opt();
let len_2 = self.iterator_2.len_hint_opt();
@@ -98,18 +89,46 @@ where
E::join(left, right, reducer)
}

fn with_producer_indexed<CB>(self, base: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.iterator_1.len_hint() + self.iterator_2.len_hint()
}
}

impl<'a, X1, X2, T> WithProducer<'a> for Chain<X1, X2>
where
X1: ParallelIterator<'a, Item = T> + WithProducer<'a, Item = T>,
X2: ParallelIterator<'a, Item = T> + WithProducer<'a, Item = T>,
T: Send + 'a,
{
type Item = T;

fn with_producer<CB>(self, base: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
self.iterator_1.with_producer_indexed(ChainCallback1 {
self.iterator_1.with_producer(ChainCallback1 {
base,
iterator_2: self.iterator_2,
})
}
}

fn len_hint(&self) -> usize {
self.iterator_1.len_hint() + self.iterator_2.len_hint()
impl<'a, X1, X2, T> WithIndexedProducer<'a> for Chain<X1, X2>
where
X1: IndexedParallelIterator<'a, Item = T> + WithIndexedProducer<'a, Item = T>,
X2: IndexedParallelIterator<'a, Item = T> + WithIndexedProducer<'a, Item = T>,
T: Send + 'a,
{
type Item = T;

fn with_indexed_producer<CB>(self, base: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
self.iterator_1.with_indexed_producer(ChainCallback1 {
base,
iterator_2: self.iterator_2,
})
}
}

@@ -123,7 +142,7 @@ struct ChainCallback1<CB, X2> {
impl<'a, CB, X2, T> ProducerCallback<'a, T> for ChainCallback1<CB, X2>
where
CB: ProducerCallback<'a, T>,
X2: ParallelIterator<'a, Item = T>,
X2: ParallelIterator<'a, Item = T> + WithProducer<'a, Item = T>,
T: Send + 'a,
{
type Output = CB::Output;
@@ -142,7 +161,7 @@ where
impl<'a, CB, X2, T> IndexedProducerCallback<'a, T> for ChainCallback1<CB, X2>
where
CB: IndexedProducerCallback<'a, T>,
X2: IndexedParallelIterator<'a, Item = T>,
X2: IndexedParallelIterator<'a, Item = T> + WithIndexedProducer<'a, Item = T>,
T: Send + 'a,
{
type Output = CB::Output;
@@ -154,7 +173,7 @@ where
let base = self.base;

self.iterator_2
.with_producer_indexed(ChainCallback2 { base, producer_1 })
.with_indexed_producer(ChainCallback2 { base, producer_1 })
}
}



+ 31
- 14
asparit/src/iter/cloned.rs Просмотреть файл

@@ -1,6 +1,7 @@
use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

/* Cloned */
@@ -32,13 +33,6 @@ where
self.base.drive(executor, ClonedConsumer { base: consumer })
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(ClonedCallback { base: callback })
}

fn len_hint_opt(&self) -> Option<usize> {
self.base.len_hint_opt()
}
@@ -60,16 +54,39 @@ where
.drive_indexed(executor, ClonedConsumer { base: consumer })
}

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.base.len_hint()
}
}

impl<'a, X, T> WithProducer<'a> for Cloned<X>
where
X: WithProducer<'a, Item = &'a T>,
T: Clone + Send + Sync + 'a,
{
type Item = T;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(ClonedCallback { base: callback })
}
}

impl<'a, X, T> WithIndexedProducer<'a> for Cloned<X>
where
X: WithIndexedProducer<'a, Item = &'a T>,
T: Clone + Send + Sync + 'a,
{
type Item = T;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
self.base
.with_producer_indexed(ClonedCallback { base: callback })
}

fn len_hint(&self) -> usize {
self.base.len_hint()
.with_indexed_producer(ClonedCallback { base: callback })
}
}



+ 31
- 14
asparit/src/iter/copied.rs Просмотреть файл

@@ -1,6 +1,7 @@
use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

/* Copied */
@@ -32,13 +33,6 @@ where
self.base.drive(executor, CopiedConsumer { base: consumer })
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(CopiedCallback { base: callback })
}

fn len_hint_opt(&self) -> Option<usize> {
self.base.len_hint_opt()
}
@@ -60,16 +54,39 @@ where
.drive_indexed(executor, CopiedConsumer { base: consumer })
}

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.base.len_hint()
}
}

impl<'a, X, T> WithProducer<'a> for Copied<X>
where
X: WithProducer<'a, Item = &'a T>,
T: Copy + Send + Sync + 'a,
{
type Item = T;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(CopiedCallback { base: callback })
}
}

impl<'a, X, T> WithIndexedProducer<'a> for Copied<X>
where
X: WithIndexedProducer<'a, Item = &'a T>,
T: Copy + Send + Sync + 'a,
{
type Item = T;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
self.base
.with_producer_indexed(CopiedCallback { base: callback })
}

fn len_hint(&self) -> usize {
self.base.len_hint()
.with_indexed_producer(CopiedCallback { base: callback })
}
}



+ 9
- 1
asparit/src/iter/filter.rs Просмотреть файл

@@ -1,6 +1,6 @@
use crate::{
Consumer, Executor, Folder, ParallelIterator, Producer, ProducerCallback, Reducer, Setup,
WithSetup,
WithProducer, WithSetup,
};

/* Filter */
@@ -38,6 +38,14 @@ where
},
)
}
}

impl<'a, X, O> WithProducer<'a> for Filter<X, O>
where
X: WithProducer<'a>,
O: Fn(&X::Item) -> bool + Clone + Send + 'a,
{
type Item = X::Item;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where


+ 10
- 1
asparit/src/iter/filter_map.rs Просмотреть файл

@@ -1,6 +1,6 @@
use crate::{
Consumer, Executor, Folder, ParallelIterator, Producer, ProducerCallback, Reducer, Setup,
WithSetup,
WithProducer, WithSetup,
};

/* FilterMap */
@@ -39,6 +39,15 @@ where
},
)
}
}

impl<'a, X, O, S> WithProducer<'a> for FilterMap<X, O>
where
X: WithProducer<'a>,
O: Fn(X::Item) -> Option<S> + Clone + Send + 'a,
S: Send + 'a,
{
type Item = S;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where


+ 20
- 1
asparit/src/iter/flatten.rs Просмотреть файл

@@ -2,7 +2,7 @@ use std::iter::IntoIterator;

use crate::{
Consumer, Executor, Folder, ParallelIterator, Producer, ProducerCallback, Reducer, Setup,
WithSetup,
WithProducer, WithSetup,
};

/* FlattenIter */
@@ -40,6 +40,15 @@ where
},
)
}
}

impl<'a, X, SI> WithProducer<'a> for FlattenIter<X>
where
X: WithProducer<'a, Item = SI>,
SI: IntoIterator + Send + 'a,
SI::Item: Send + 'a,
{
type Item = SI::Item;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
@@ -89,6 +98,16 @@ where
},
)
}
}

impl<'a, X, O, SI> WithProducer<'a> for FlatMapIter<X, O>
where
X: WithProducer<'a>,
O: Fn(X::Item) -> SI + Clone + Send + 'a,
SI: IntoIterator + 'a,
SI::Item: Send + 'a,
{
type Item = SI::Item;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where


+ 20
- 1
asparit/src/iter/fold.rs Просмотреть файл

@@ -1,6 +1,6 @@
use crate::{
Consumer, Executor, Folder, ParallelIterator, Producer, ProducerCallback, Reducer, Setup,
WithSetup,
WithProducer, WithSetup,
};

/* Fold */
@@ -46,6 +46,16 @@ where
},
)
}
}

impl<'a, X, S, O, U> WithProducer<'a> for Fold<X, S, O>
where
X: WithProducer<'a>,
S: Fn() -> U + Clone + Send + 'a,
O: Fn(U, X::Item) -> U + Clone + Send + 'a,
U: Send + 'a,
{
type Item = U;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
@@ -107,6 +117,15 @@ where
},
)
}
}

impl<'a, X, U, O> WithProducer<'a> for FoldWith<X, U, O>
where
X: WithProducer<'a>,
U: Clone + Send + 'a,
O: Fn(U, X::Item) -> U + Clone + Send + 'a,
{
type Item = U;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where


+ 33
- 16
asparit/src/iter/inspect.rs Просмотреть файл

@@ -1,6 +1,7 @@
use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

/* Inspect */
@@ -39,16 +40,6 @@ where
)
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(InspectCallback {
base: callback,
operation: self.operation,
})
}

fn len_hint_opt(&self) -> Option<usize> {
self.base.len_hint_opt()
}
@@ -75,18 +66,44 @@ where
)
}

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.base.len_hint()
}
}

impl<'a, X, O> WithProducer<'a> for Inspect<X, O>
where
X: WithProducer<'a>,
O: Fn(&X::Item) + Clone + Send + 'a,
{
type Item = X::Item;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer_indexed(InspectCallback {
self.base.with_producer(InspectCallback {
base: callback,
operation: self.operation,
})
}
}

fn len_hint(&self) -> usize {
self.base.len_hint()
impl<'a, X, O> WithIndexedProducer<'a> for Inspect<X, O>
where
X: WithIndexedProducer<'a>,
O: Fn(&X::Item) + Clone + Send + 'a,
{
type Item = X::Item;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
self.base.with_indexed_producer(InspectCallback {
base: callback,
operation: self.operation,
})
}
}



+ 36
- 19
asparit/src/iter/intersperse.rs Просмотреть файл

@@ -2,7 +2,8 @@ use std::iter::{once, DoubleEndedIterator, ExactSizeIterator, Fuse, Iterator};

use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

/* Intersperse */
@@ -42,15 +43,6 @@ where
)
}

fn with_producer<CB>(self, base: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
let item = self.item;

self.base.with_producer(IntersperseCallback { base, item })
}

fn len_hint_opt(&self) -> Option<usize> {
match self.base.len_hint_opt()? {
0 => Some(0),
@@ -81,21 +73,46 @@ where
)
}

fn with_producer_indexed<CB>(self, base: CB) -> CB::Output
fn len_hint(&self) -> usize {
match self.base.len_hint() {
0 => 0,
len => len - 1,
}
}
}

impl<'a, X, I> WithProducer<'a> for Intersperse<X, I>
where
X: WithProducer<'a, Item = I>,
I: Clone + Send + 'a,
{
type Item = X::Item;

fn with_producer<CB>(self, base: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
let item = self.item;

self.base.with_producer(IntersperseCallback { base, item })
}
}

impl<'a, X, I> WithIndexedProducer<'a> for Intersperse<X, I>
where
X: WithIndexedProducer<'a, Item = I>,
I: Clone + Send + 'a,
{
type Item = X::Item;

fn with_indexed_producer<CB>(self, base: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
let item = self.item;

self.base
.with_producer_indexed(IntersperseCallback { base, item })
}

fn len_hint(&self) -> usize {
match self.base.len_hint() {
0 => 0,
len => len - 1,
}
.with_indexed_producer(IntersperseCallback { base, item })
}
}



+ 35
- 16
asparit/src/iter/map.rs Просмотреть файл

@@ -1,6 +1,7 @@
use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

/* Map */
@@ -36,16 +37,6 @@ where
self.base.drive(executor, consumer)
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(MapCallback {
callback,
operation: self.operation,
})
}

fn len_hint_opt(&self) -> Option<usize> {
self.base.len_hint_opt()
}
@@ -69,18 +60,46 @@ where
self.base.drive_indexed(executor, consumer)
}

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.base.len_hint()
}
}

impl<'a, X, O, T> WithProducer<'a> for Map<X, O>
where
X: WithProducer<'a>,
O: Fn(X::Item) -> T + Clone + Send + 'a,
T: Send + 'a,
{
type Item = O::Output;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer_indexed(MapCallback {
self.base.with_producer(MapCallback {
callback,
operation: self.operation,
})
}
}

fn len_hint(&self) -> usize {
self.base.len_hint()
impl<'a, X, O, T> WithIndexedProducer<'a> for Map<X, O>
where
X: WithIndexedProducer<'a>,
O: Fn(X::Item) -> T + Clone + Send + 'a,
T: Send + 'a,
{
type Item = O::Output;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
self.base.with_indexed_producer(MapCallback {
callback,
operation: self.operation,
})
}
}



+ 38
- 17
asparit/src/iter/map_init.rs Просмотреть файл

@@ -1,6 +1,7 @@
use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

use super::map_with::{MapWithFolder, MapWithIter};
@@ -44,17 +45,6 @@ where
self.base.drive(executor, consumer)
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(MapInitCallback {
callback,
init: self.init,
operation: self.operation,
})
}

fn len_hint_opt(&self) -> Option<usize> {
self.base.len_hint_opt()
}
@@ -79,19 +69,50 @@ where
self.base.drive_indexed(executor, consumer)
}

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.base.len_hint()
}
}

impl<'a, X, S, O, T, U> WithProducer<'a> for MapInit<X, S, O>
where
X: WithProducer<'a>,
O: Fn(&mut U, X::Item) -> T + Clone + Send + 'a,
T: Send + 'a,
S: Fn() -> U + Clone + Send + 'a,
{
type Item = T;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer_indexed(MapInitCallback {
self.base.with_producer(MapInitCallback {
callback,
init: self.init,
operation: self.operation,
})
}
}

fn len_hint(&self) -> usize {
self.base.len_hint()
impl<'a, X, S, O, T, U> WithIndexedProducer<'a> for MapInit<X, S, O>
where
X: WithIndexedProducer<'a>,
O: Fn(&mut U, X::Item) -> T + Clone + Send + 'a,
T: Send + 'a,
S: Fn() -> U + Clone + Send + 'a,
{
type Item = T;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
self.base.with_indexed_producer(MapInitCallback {
callback,
init: self.init,
operation: self.operation,
})
}
}



+ 38
- 17
asparit/src/iter/map_with.rs Просмотреть файл

@@ -1,6 +1,7 @@
use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

/* MapWith */
@@ -42,17 +43,6 @@ where
self.base.drive(executor, consumer)
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(MapWithCallback {
callback,
item: self.item,
operation: self.operation,
})
}

fn len_hint_opt(&self) -> Option<usize> {
self.base.len_hint_opt()
}
@@ -77,19 +67,50 @@ where
self.base.drive_indexed(executor, consumer)
}

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.base.len_hint()
}
}

impl<'a, X, S, O, T> WithProducer<'a> for MapWith<X, S, O>
where
X: WithProducer<'a>,
O: Fn(&mut S, X::Item) -> T + Clone + Send + 'a,
T: Send + 'a,
S: Clone + Send + 'a,
{
type Item = T;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer_indexed(MapWithCallback {
self.base.with_producer(MapWithCallback {
callback,
item: self.item,
operation: self.operation,
})
}
}

fn len_hint(&self) -> usize {
self.base.len_hint()
impl<'a, X, S, O, T> WithIndexedProducer<'a> for MapWith<X, S, O>
where
X: WithIndexedProducer<'a>,
O: Fn(&mut S, X::Item) -> T + Clone + Send + 'a,
T: Send + 'a,
S: Clone + Send + 'a,
{
type Item = T;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
self.base.with_indexed_producer(MapWithCallback {
callback,
item: self.item,
operation: self.operation,
})
}
}



+ 28
- 13
asparit/src/iter/panic_fuse.rs Просмотреть файл

@@ -6,7 +6,8 @@ use std::thread::panicking;

use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

/* PanicFuse */
@@ -42,13 +43,6 @@ where
self.base.drive(executor, consumer)
}

fn with_producer<CB>(self, base: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(PanicFuseCallback { base })
}

fn len_hint_opt(&self) -> Option<usize> {
self.base.len_hint_opt()
}
@@ -73,15 +67,36 @@ where
self.base.drive_indexed(executor, consumer)
}

fn with_producer_indexed<CB>(self, base: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.base.len_hint()
}
}

impl<'a, X> WithProducer<'a> for PanicFuse<X>
where
X: WithProducer<'a>,
{
type Item = X::Item;

fn with_producer<CB>(self, base: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer_indexed(PanicFuseCallback { base })
self.base.with_producer(PanicFuseCallback { base })
}
}

fn len_hint(&self) -> usize {
self.base.len_hint()
impl<'a, X> WithIndexedProducer<'a> for PanicFuse<X>
where
X: WithIndexedProducer<'a>,
{
type Item = X::Item;

fn with_indexed_producer<CB>(self, base: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
self.base.with_indexed_producer(PanicFuseCallback { base })
}
}



+ 31
- 16
asparit/src/iter/splits.rs Просмотреть файл

@@ -1,6 +1,7 @@
use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

pub struct Splits<X> {
@@ -33,15 +34,6 @@ where
self.base.drive(executor, consumer)
}

fn with_producer<CB>(self, base: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
let splits = self.splits;

self.base.with_producer(SplitsCallback { base, splits })
}

fn len_hint_opt(&self) -> Option<usize> {
self.base.len_hint_opt()
}
@@ -64,18 +56,41 @@ where
self.base.drive_indexed(executor, consumer)
}

fn with_producer_indexed<CB>(self, base: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.base.len_hint()
}
}

impl<'a, X> WithProducer<'a> for Splits<X>
where
X: WithProducer<'a>,
{
type Item = X::Item;

fn with_producer<CB>(self, base: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
let splits = self.splits;

self.base.with_producer(SplitsCallback { base, splits })
}
}

impl<'a, X> WithIndexedProducer<'a> for Splits<X>
where
X: WithIndexedProducer<'a>,
{
type Item = X::Item;

fn with_indexed_producer<CB>(self, base: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
let splits = self.splits;

self.base
.with_producer_indexed(SplitsCallback { base, splits })
}

fn len_hint(&self) -> usize {
self.base.len_hint()
.with_indexed_producer(SplitsCallback { base, splits })
}
}



+ 22
- 1
asparit/src/iter/try_fold.rs Просмотреть файл

@@ -2,7 +2,7 @@ use std::marker::PhantomData;

use crate::{
misc::Try, Consumer, Executor, Folder, ParallelIterator, Producer, ProducerCallback, Reducer,
Setup, WithSetup,
Setup, WithProducer, WithSetup,
};

/* TryFold */
@@ -52,6 +52,17 @@ where
},
)
}
}

impl<'a, X, S, O, U, T> WithProducer<'a> for TryFold<X, S, O, T>
where
X: WithProducer<'a>,
S: Fn() -> U + Clone + Send + 'a,
O: Fn(U, X::Item) -> T + Clone + Send + 'a,
U: Send,
T: Try<Ok = U> + Send + 'a,
{
type Item = T;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
@@ -119,6 +130,16 @@ where
},
)
}
}

impl<'a, X, U, O, T> WithProducer<'a> for TryFoldWith<X, U, O, T>
where
X: WithProducer<'a>,
U: Clone + Send + 'a,
O: Fn(U, X::Item) -> T + Clone + Send + 'a,
T: Try<Ok = U> + Send + 'a,
{
type Item = T;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where


+ 33
- 16
asparit/src/iter/update.rs Просмотреть файл

@@ -1,6 +1,7 @@
use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

/* Update */
@@ -39,16 +40,6 @@ where
)
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(UpdateCallback {
base: callback,
operation: self.operation,
})
}

fn len_hint_opt(&self) -> Option<usize> {
self.base.len_hint_opt()
}
@@ -75,18 +66,44 @@ where
)
}

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.base.len_hint()
}
}

impl<'a, X, O> WithProducer<'a> for Update<X, O>
where
X: WithProducer<'a>,
O: Fn(&mut X::Item) + Clone + Send + 'a,
{
type Item = X::Item;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer_indexed(UpdateCallback {
self.base.with_producer(UpdateCallback {
base: callback,
operation: self.operation,
})
}
}

fn len_hint(&self) -> usize {
self.base.len_hint()
impl<'a, X, O> WithIndexedProducer<'a> for Update<X, O>
where
X: WithIndexedProducer<'a>,
O: Fn(&mut X::Item) + Clone + Send + 'a,
{
type Item = X::Item;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
self.base.with_indexed_producer(UpdateCallback {
base: callback,
operation: self.operation,
})
}
}



+ 30
- 13
asparit/src/iter/while_some.rs Просмотреть файл

@@ -6,7 +6,8 @@ use std::sync::{

use crate::{
Consumer, Executor, Folder, IndexedParallelIterator, IndexedProducer, IndexedProducerCallback,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};

/* WhileSome */
@@ -43,13 +44,6 @@ where
self.base.drive(executor, consumer)
}

fn with_producer<CB>(self, base: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer(WhileSomeCallback { base })
}

fn len_hint_opt(&self) -> Option<usize> {
self.base.len_hint_opt()
}
@@ -75,15 +69,38 @@ where
self.base.drive_indexed(executor, consumer)
}

fn with_producer_indexed<CB>(self, base: CB) -> CB::Output
fn len_hint(&self) -> usize {
self.base.len_hint()
}
}

impl<'a, X, T> WithProducer<'a> for WhileSome<X>
where
X: WithProducer<'a, Item = Option<T>>,
T: Send + 'a,
{
type Item = T;

fn with_producer<CB>(self, base: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
self.base.with_producer_indexed(WhileSomeCallback { base })
self.base.with_producer(WhileSomeCallback { base })
}
}

fn len_hint(&self) -> usize {
self.base.len_hint()
impl<'a, X, T> WithIndexedProducer<'a> for WhileSome<X>
where
X: WithIndexedProducer<'a, Item = Option<T>>,
T: Send + 'a,
{
type Item = T;

fn with_indexed_producer<CB>(self, base: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
self.base.with_indexed_producer(WhileSomeCallback { base })
}
}



+ 2
- 1
asparit/src/lib.rs Просмотреть файл

@@ -8,6 +8,7 @@ pub use self::core::{
Consumer, Driver, Executor, ExecutorCallback, Folder, IndexedParallelIterator, IndexedProducer,
IndexedProducerCallback, IntoParallelIterator, IntoParallelRefIterator,
IntoParallelRefMutIterator, ParallelDrainFull, ParallelDrainRange, ParallelExtend,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithSetup,
ParallelIterator, Producer, ProducerCallback, Reducer, Setup, WithIndexedProducer,
WithProducer, WithSetup,
};
pub use self::executor::{DefaultExecutor, SequentialExecutor};

+ 22
- 14
asparit/src/std/range.rs Просмотреть файл

@@ -3,7 +3,7 @@ use std::ops::Range;
use crate::{
Consumer, Executor, ExecutorCallback, IndexedParallelIterator, IndexedProducer,
IndexedProducerCallback, IntoParallelIterator, ParallelIterator, Producer, ProducerCallback,
Reducer, WithSetup,
Reducer, WithIndexedProducer, WithProducer, WithSetup,
};

/// Parallel iterator over a range, implemented for all integer types.
@@ -105,13 +105,6 @@ macro_rules! unindexed_parallel_iterator_impl {
}
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
callback.callback(IterProducer { range: self.range })
}

fn len_hint_opt(&self) -> Option<usize> {
let len = self.range.length();

@@ -123,6 +116,17 @@ macro_rules! unindexed_parallel_iterator_impl {
}
}

impl<'a> WithProducer<'a> for Iter<$t> {
type Item = $t;

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
callback.callback(IterProducer { range: self.range })
}
}

impl WithSetup for IterProducer<$t> {}

impl Producer for IterProducer<$t> {
@@ -163,19 +167,23 @@ macro_rules! indexed_parallel_iterator_impl {
D: Send + 'a,
R: Reducer<D> + Send + 'a,
{
self.with_producer_indexed(ExecutorCallback::new(executor, consumer))
self.with_indexed_producer(ExecutorCallback::new(executor, consumer))
}

fn len_hint(&self) -> usize {
self.range.length() as usize
}
}

impl<'a> WithIndexedProducer<'a> for Iter<$t> {
type Item = $t;

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
callback.callback(IterProducer { range: self.range })
}

fn len_hint(&self) -> usize {
self.range.length() as usize
}
}

impl IndexedProducer for IterProducer<$t> {


+ 55
- 27
asparit/src/std/slice.rs Просмотреть файл

@@ -1,7 +1,7 @@
use crate::{
Consumer, Executor, ExecutorCallback, IndexedParallelIterator, IndexedProducer,
IndexedProducerCallback, IntoParallelIterator, ParallelIterator, Producer, ProducerCallback,
Reducer, WithSetup,
Reducer, WithIndexedProducer, WithProducer, WithSetup,
};

impl<'a, T> IntoParallelIterator<'a> for &'a [T]
@@ -71,14 +71,7 @@ where
D: Send + 'a,
R: Reducer<D> + Send + 'a,
{
self.with_producer_indexed(ExecutorCallback::new(executor, consumer))
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
callback.callback(IterProducer { slice: self.slice })
self.with_indexed_producer(ExecutorCallback::new(executor, consumer))
}

fn len_hint_opt(&self) -> Option<usize> {
@@ -97,18 +90,39 @@ where
D: Send + 'a,
R: Reducer<D> + Send + 'a,
{
self.with_producer_indexed(ExecutorCallback::new(executor, consumer))
self.with_indexed_producer(ExecutorCallback::new(executor, consumer))
}

fn len_hint(&self) -> usize {
self.slice.len()
}
}

impl<'a, T> WithProducer<'a> for Iter<'a, T>
where
T: Send + Sync,
{
type Item = &'a T;

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
callback.callback(IterProducer { slice: self.slice })
}
}

fn len_hint(&self) -> usize {
self.slice.len()
impl<'a, T> WithIndexedProducer<'a> for Iter<'a, T>
where
T: Send + Sync,
{
type Item = &'a T;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
callback.callback(IterProducer { slice: self.slice })
}
}

@@ -187,14 +201,7 @@ where
D: Send + 'a,
R: Reducer<D> + Send + 'a,
{
self.with_producer_indexed(ExecutorCallback::new(executor, consumer))
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
callback.callback(IterMutProducer { slice: self.slice })
self.with_indexed_producer(ExecutorCallback::new(executor, consumer))
}

fn len_hint_opt(&self) -> Option<usize> {
@@ -213,18 +220,39 @@ where
D: Send + 'a,
R: Reducer<D> + Send + 'a,
{
self.with_producer_indexed(ExecutorCallback::new(executor, consumer))
self.with_indexed_producer(ExecutorCallback::new(executor, consumer))
}

fn len_hint(&self) -> usize {
self.slice.len()
}
}

impl<'a, T> WithProducer<'a> for IterMut<'a, T>
where
T: Send + Sync,
{
type Item = &'a mut T;

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
callback.callback(IterMutProducer { slice: self.slice })
}
}

fn len_hint(&self) -> usize {
self.slice.len()
impl<'a, T> WithIndexedProducer<'a> for IterMut<'a, T>
where
T: Send + Sync,
{
type Item = &'a mut T;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
callback.callback(IterMutProducer { slice: self.slice })
}
}



+ 57
- 28
asparit/src/std/vec.rs Просмотреть файл

@@ -9,12 +9,13 @@ use std::sync::Arc;
use crate::{
misc::simplify_range, Consumer, Executor, ExecutorCallback, Folder, IndexedParallelIterator,
IndexedProducer, IndexedProducerCallback, IntoParallelIterator, ParallelDrainRange,
ParallelExtend, ParallelIterator, Producer, ProducerCallback, Reducer, WithSetup,
ParallelExtend, ParallelIterator, Producer, ProducerCallback, Reducer, WithIndexedProducer,
WithProducer, WithSetup,
};

/// Parallel iterator that moves out of a vector.
#[derive(Debug, Clone)]
pub struct IntoIter<T: Send> {
pub struct IntoIter<T> {
vec: Vec<T>,
}

@@ -43,14 +44,7 @@ where
D: Send + 'a,
R: Reducer<D> + Send + 'a,
{
self.with_producer_indexed(ExecutorCallback::new(executor, consumer))
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
callback.callback(VecProducer::new(self.vec))
self.with_indexed_producer(ExecutorCallback::new(executor, consumer))
}

fn len_hint_opt(&self) -> Option<usize> {
@@ -69,18 +63,39 @@ where
D: Send + 'a,
R: Reducer<D> + Send + 'a,
{
self.with_producer_indexed(ExecutorCallback::new(executor, consumer))
self.with_indexed_producer(ExecutorCallback::new(executor, consumer))
}

fn len_hint(&self) -> usize {
self.vec.len()
}
}

impl<'a, T> WithProducer<'a> for IntoIter<T>
where
T: Send + 'a,
{
type Item = T;

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
callback.callback(VecProducer::new(self.vec))
}
}

fn len_hint(&self) -> usize {
self.vec.len()
impl<'a, T> WithIndexedProducer<'a> for IntoIter<T>
where
T: Send + 'a,
{
type Item = T;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
callback.callback(VecProducer::new(self.vec))
}
}

@@ -285,14 +300,7 @@ where
D: Send + 'a,
R: Reducer<D> + Send + 'a,
{
self.with_producer_indexed(ExecutorCallback::new(executor, consumer))
}

fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: ProducerCallback<'a, Self::Item>,
{
callback.callback(self.into_producer())
self.with_indexed_producer(ExecutorCallback::new(executor, consumer))
}

fn len_hint_opt(&self) -> Option<usize> {
@@ -311,18 +319,39 @@ where
D: Send + 'a,
R: Reducer<D> + Send + 'a,
{
self.with_producer_indexed(ExecutorCallback::new(executor, consumer))
self.with_indexed_producer(ExecutorCallback::new(executor, consumer))
}

fn len_hint(&self) -> usize {
self.range.len()
}
}

impl<'a, T> WithProducer<'a> for Drain<'a, T>
where
T: Send,
{
type Item = T;

fn with_producer_indexed<CB>(self, callback: CB) -> CB::Output
fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
CB: ProducerCallback<'a, Self::Item>,
{
callback.callback(self.into_producer())
}
}

fn len_hint(&self) -> usize {
self.range.len()
impl<'a, T> WithIndexedProducer<'a> for Drain<'a, T>
where
T: Send,
{
type Item = T;

fn with_indexed_producer<CB>(self, callback: CB) -> CB::Output
where
CB: IndexedProducerCallback<'a, Self::Item>,
{
callback.callback(self.into_producer())
}
}



Загрузка…
Отмена
Сохранить