mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-15 00:40:37 -08:00
Compare commits
4 Commits
dev/karo/c
...
docu-tests
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
caf91c84f0 | ||
|
|
f5b4c17011 | ||
|
|
12506e5f95 | ||
|
|
965600212d |
@@ -20,3 +20,6 @@ memsec = { workspace = true }
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(coverage)'] }
|
||||||
|
|||||||
@@ -113,9 +113,10 @@ mod tests {
|
|||||||
// Pearson correlation
|
// Pearson correlation
|
||||||
let correlation = cv / (sd_x * sd_y);
|
let correlation = cv / (sd_x * sd_y);
|
||||||
println!("correlation: {:.6?}", correlation);
|
println!("correlation: {:.6?}", correlation);
|
||||||
|
#[cfg(not(coverage))]
|
||||||
assert!(
|
assert!(
|
||||||
correlation.abs() < 0.01,
|
correlation.abs() < 0.01,
|
||||||
"execution time correlates with result"
|
"execution time correlates with result"
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,3 +91,6 @@ experiment_api = [
|
|||||||
internal_signal_handling_for_coverage_reports = ["signal-hook"]
|
internal_signal_handling_for_coverage_reports = ["signal-hook"]
|
||||||
internal_testing = []
|
internal_testing = []
|
||||||
internal_bin_gen_ipc_msg_types = ["hex", "heck"]
|
internal_bin_gen_ipc_msg_types = ["hex", "heck"]
|
||||||
|
|
||||||
|
[lints.rust]
|
||||||
|
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(coverage)'] }
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ impl Drop for KillChild {
|
|||||||
// system is a bit broken; there is probably a few functions that just restart on EINTR
|
// system is a bit broken; there is probably a few functions that just restart on EINTR
|
||||||
// so the signal is absorbed
|
// so the signal is absorbed
|
||||||
loop {
|
loop {
|
||||||
rustix::process::kill_process(pid, Term).discard_result();
|
kill_process(pid, Term).discard_result();
|
||||||
if self.0.try_wait().unwrap().is_some() {
|
if self.0.try_wait().unwrap().is_some() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
use std::{
|
use std::{
|
||||||
borrow::{Borrow, BorrowMut},
|
borrow::{Borrow, BorrowMut},
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
fmt::{Debug, Write},
|
ops::DerefMut,
|
||||||
ops::{DerefMut, RangeBounds},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use rand::distributions::uniform::SampleBorrow;
|
|
||||||
use rosenpass_cipher_traits::Kem;
|
use rosenpass_cipher_traits::Kem;
|
||||||
use rosenpass_ciphers::kem::StaticKem;
|
use rosenpass_ciphers::kem::StaticKem;
|
||||||
use rosenpass_util::result::OkExt;
|
use rosenpass_util::result::OkExt;
|
||||||
@@ -28,48 +26,53 @@ fn test_successful_exchange_with_poll() -> anyhow::Result<()> {
|
|||||||
sim.poll_loop(150)?; // Poll 75 times
|
sim.poll_loop(150)?; // Poll 75 times
|
||||||
let transcript = sim.transcript;
|
let transcript = sim.transcript;
|
||||||
|
|
||||||
let completions: Vec<_> = transcript
|
let _completions: Vec<_> = transcript
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|elm| matches!(elm, (_, TranscriptEvent::CompletedExchange(_))))
|
.filter(|elm| matches!(elm, (_, TranscriptEvent::CompletedExchange(_))))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
#[cfg(not(coverage))]
|
||||||
assert!(
|
assert!(
|
||||||
!completions.is_empty(),
|
!_completions.is_empty(),
|
||||||
"\
|
"\
|
||||||
Should have performed a successful key exchanged!\n\
|
Should have performed a successful key exchanged!\n\
|
||||||
Transcript: {transcript:?}\n\
|
Transcript: {transcript:?}\n\
|
||||||
Completions: {completions:?}\
|
Completions: {_completions:?}\
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
#[cfg(not(coverage))]
|
||||||
assert!(
|
assert!(
|
||||||
completions[0].0 < 20.0,
|
_completions[0].0 < 20.0,
|
||||||
"\
|
"\
|
||||||
First key exchange should happen in under twenty seconds!\n\
|
First key exchange should happen in under twenty seconds!\n\
|
||||||
Transcript: {transcript:?}\n\
|
Transcript: {transcript:?}\n\
|
||||||
Completions: {completions:?}\
|
Completions: {_completions:?}\
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(not(coverage))]
|
||||||
assert!(
|
assert!(
|
||||||
completions.len() >= 3,
|
_completions.len() >= 3,
|
||||||
"\
|
"\
|
||||||
Should have at least two renegotiations!\n\
|
Should have at least two renegotiations!\n\
|
||||||
Transcript: {transcript:?}\n\
|
Transcript: {transcript:?}\n\
|
||||||
Completions: {completions:?}\
|
Completions: {_completions:?}\
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
#[cfg(not(coverage))]
|
||||||
assert!(
|
assert!(
|
||||||
(110.0..175.0).contains(&completions[1].0),
|
(110.0..175.0).contains(&_completions[1].0),
|
||||||
"\
|
"\
|
||||||
First renegotiation should happen in between two and three minutes!\n\
|
First renegotiation should happen in between two and three minutes!\n\
|
||||||
Transcript: {transcript:?}\n\
|
Transcript: {transcript:?}\n\
|
||||||
Completions: {completions:?}\
|
Completions: {_completions:?}\
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
assert!((110.0..175.0).contains(&(completions[2].0 - completions[1].0)), "\
|
#[cfg(not(coverage))]
|
||||||
|
assert!((110.0..175.0).contains(&(_completions[2].0 - _completions[1].0)), "\
|
||||||
First renegotiation should happen in between two and three minutes after the first renegotiation!\n\
|
First renegotiation should happen in between two and three minutes after the first renegotiation!\n\
|
||||||
Transcript: {transcript:?}\n\
|
Transcript: {transcript:?}\n\
|
||||||
Completions: {completions:?}\
|
Completions: {_completions:?}\
|
||||||
");
|
");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -106,48 +109,53 @@ fn test_successful_exchange_under_packet_loss() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let transcript = sim.transcript;
|
let transcript = sim.transcript;
|
||||||
let completions: Vec<_> = transcript
|
let _completions: Vec<_> = transcript
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|elm| matches!(elm, (_, TranscriptEvent::CompletedExchange(_))))
|
.filter(|elm| matches!(elm, (_, TranscriptEvent::CompletedExchange(_))))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
#[cfg(not(coverage))]
|
||||||
assert!(
|
assert!(
|
||||||
!completions.is_empty(),
|
!_completions.is_empty(),
|
||||||
"\
|
"\
|
||||||
Should have performed a successful key exchanged!\n\
|
Should have performed a successful key exchanged!\n\
|
||||||
Transcript: {transcript:?}\n\
|
Transcript: {transcript:?}\n\
|
||||||
Completions: {completions:?}\
|
Completions: {_completions:?}\
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
#[cfg(not(coverage))]
|
||||||
assert!(
|
assert!(
|
||||||
completions[0].0 < 10.0,
|
_completions[0].0 < 10.0,
|
||||||
"\
|
"\
|
||||||
First key exchange should happen in under twenty seconds!\n\
|
First key exchange should happen in under twenty seconds!\n\
|
||||||
Transcript: {transcript:?}\n\
|
Transcript: {transcript:?}\n\
|
||||||
Completions: {completions:?}\
|
Completions: {_completions:?}\
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[cfg(not(coverage))]
|
||||||
assert!(
|
assert!(
|
||||||
completions.len() >= 3,
|
_completions.len() >= 3,
|
||||||
"\
|
"\
|
||||||
Should have at least two renegotiations!\n\
|
Should have at least two renegotiations!\n\
|
||||||
Transcript: {transcript:?}\n\
|
Transcript: {transcript:?}\n\
|
||||||
Completions: {completions:?}\
|
Completions: {_completions:?}\
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
#[cfg(not(coverage))]
|
||||||
assert!(
|
assert!(
|
||||||
(110.0..175.0).contains(&completions[1].0),
|
(110.0..175.0).contains(&_completions[1].0),
|
||||||
"\
|
"\
|
||||||
First renegotiation should happen in between two and three minutes!\n\
|
First renegotiation should happen in between two and three minutes!\n\
|
||||||
Transcript: {transcript:?}\n\
|
Transcript: {transcript:?}\n\
|
||||||
Completions: {completions:?}\
|
Completions: {_completions:?}\
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
assert!((110.0..175.0).contains(&(completions[2].0 - completions[1].0)), "\
|
#[cfg(not(coverage))]
|
||||||
|
assert!((110.0..175.0).contains(&(_completions[2].0 - _completions[1].0)), "\
|
||||||
First renegotiation should happen in between two and three minutes after the first renegotiation!\n\
|
First renegotiation should happen in between two and three minutes after the first renegotiation!\n\
|
||||||
Transcript: {transcript:?}\n\
|
Transcript: {transcript:?}\n\
|
||||||
Completions: {completions:?}\
|
Completions: {_completions:?}\
|
||||||
");
|
");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -17,13 +17,14 @@ use rosenpass_to::{to, with_destination, To};
|
|||||||
use std::ops::BitXorAssign;
|
use std::ops::BitXorAssign;
|
||||||
|
|
||||||
// Destination functions return some value that implements the To trait.
|
// Destination functions return some value that implements the To trait.
|
||||||
// Unfortunately dealing with lifetimes is a bit more finicky than it would#
|
// Unfortunately dealing with lifetimes is a bit more finicky than it would
|
||||||
// be without destination parameters
|
// be without destination parameters
|
||||||
fn xor_slice<'a, T>(src: &'a [T]) -> impl To<[T], ()> + 'a
|
fn xor_slice<'a, T>(src: &'a [T]) -> impl To<[T], ()> + 'a
|
||||||
where
|
where
|
||||||
T: BitXorAssign + Clone,
|
T: BitXorAssign + Clone,
|
||||||
{
|
{
|
||||||
// Custom implementations of the to trait can be created, but the easiest
|
// Custom implementations of the to trait can be created, but the easiest
|
||||||
|
// way to create them is to use the provided helper functions like with_destination.
|
||||||
with_destination(move |dst: &mut [T]| {
|
with_destination(move |dst: &mut [T]| {
|
||||||
assert!(src.len() == dst.len());
|
assert!(src.len() == dst.len());
|
||||||
for (d, s) in dst.iter_mut().zip(src.iter()) {
|
for (d, s) in dst.iter_mut().zip(src.iter()) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//! Functions with destination copying data between slices and arrays.
|
//! Functions that make it easy to copy data between arrays and slices using functions with
|
||||||
|
//! destinations. See the specific functions for examples and more explanations.
|
||||||
|
|
||||||
use crate::{with_destination, To};
|
use crate::{with_destination, To};
|
||||||
|
|
||||||
@@ -8,6 +9,17 @@ use crate::{with_destination, To};
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This function will panic if the two slices have different lengths.
|
/// This function will panic if the two slices have different lengths.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
/// # use crate::rosenpass_to::ops::copy_slice;
|
||||||
|
/// let to_function = copy_slice(&[0; 16]);
|
||||||
|
/// let mut dst = [255; 16];
|
||||||
|
/// to_function.to(&mut dst);
|
||||||
|
/// // After the operation `dst` will hold the same data as the original slice.
|
||||||
|
/// assert!(dst.iter().all(|b| *b == 0));
|
||||||
|
/// ```
|
||||||
pub fn copy_slice<T>(origin: &[T]) -> impl To<[T], ()> + '_
|
pub fn copy_slice<T>(origin: &[T]) -> impl To<[T], ()> + '_
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
@@ -23,6 +35,19 @@ where
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This function will panic if destination is shorter than origin.
|
/// This function will panic if destination is shorter than origin.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
/// # use crate::rosenpass_to::ops::copy_slice_least_src;
|
||||||
|
/// let to_function = copy_slice_least_src(&[0; 16]);
|
||||||
|
/// let mut dst = [255; 32];
|
||||||
|
/// to_function.to(&mut dst);
|
||||||
|
/// // After the operation the first half of `dst` will hold the same data as the original slice.
|
||||||
|
/// assert!(dst[0..16].iter().all(|b| *b == 0));
|
||||||
|
/// // The second half will have remained the same
|
||||||
|
/// assert!(dst[16..32].iter().all(|b| *b == 255));
|
||||||
|
/// ```
|
||||||
pub fn copy_slice_least_src<T>(origin: &[T]) -> impl To<[T], ()> + '_
|
pub fn copy_slice_least_src<T>(origin: &[T]) -> impl To<[T], ()> + '_
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
@@ -34,6 +59,18 @@ where
|
|||||||
/// destination.
|
/// destination.
|
||||||
///
|
///
|
||||||
/// Copies as much data as is present in the shorter slice.
|
/// Copies as much data as is present in the shorter slice.
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
/// # use crate::rosenpass_to::ops::copy_slice_least;
|
||||||
|
/// let to_function = copy_slice_least(&[0; 16]);
|
||||||
|
/// let mut dst = [255; 32];
|
||||||
|
/// to_function.to(&mut dst);
|
||||||
|
/// // After the operation the first half of `dst` will hold the same data as the original slice.
|
||||||
|
/// assert!(dst[0..16].iter().all(|b| *b == 0));
|
||||||
|
/// // The second half will have remained the same.
|
||||||
|
/// assert!(dst[16..32].iter().all(|b| *b == 255));
|
||||||
|
/// ```
|
||||||
pub fn copy_slice_least<T>(origin: &[T]) -> impl To<[T], ()> + '_
|
pub fn copy_slice_least<T>(origin: &[T]) -> impl To<[T], ()> + '_
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
@@ -47,6 +84,24 @@ where
|
|||||||
/// Function with destination that attempts to copy data from origin into the destination.
|
/// Function with destination that attempts to copy data from origin into the destination.
|
||||||
///
|
///
|
||||||
/// Will return None if the slices are of different lengths.
|
/// Will return None if the slices are of different lengths.
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
/// # use crate::rosenpass_to::ops::try_copy_slice;
|
||||||
|
/// let to_function = try_copy_slice(&[0; 16]);
|
||||||
|
/// let mut dst = [255; 32];
|
||||||
|
/// let result = to_function.to(&mut dst);
|
||||||
|
/// // This will return None because the slices do not have the same length.
|
||||||
|
/// assert!(result.is_none());
|
||||||
|
///
|
||||||
|
/// let to_function = try_copy_slice(&[0; 16]);
|
||||||
|
/// let mut dst = [255; 16];
|
||||||
|
/// let result = to_function.to(&mut dst);
|
||||||
|
/// // This time it works:
|
||||||
|
/// assert!(result.is_some());
|
||||||
|
/// // After the operation `dst` will hold the same data as the original slice.
|
||||||
|
/// assert!(dst.iter().all(|b| *b == 0));
|
||||||
|
/// ```
|
||||||
pub fn try_copy_slice<T>(origin: &[T]) -> impl To<[T], Option<()>> + '_
|
pub fn try_copy_slice<T>(origin: &[T]) -> impl To<[T], Option<()>> + '_
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
@@ -62,6 +117,26 @@ where
|
|||||||
/// Destination may be longer than origin.
|
/// Destination may be longer than origin.
|
||||||
///
|
///
|
||||||
/// Will return None if the destination is shorter than origin.
|
/// Will return None if the destination is shorter than origin.
|
||||||
|
/// # Example
|
||||||
|
/// ```rust
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
/// # use crate::rosenpass_to::ops::try_copy_slice_least_src;
|
||||||
|
/// let to_function = try_copy_slice_least_src(&[0; 16]);
|
||||||
|
/// let mut dst = [255; 15];
|
||||||
|
/// let result = to_function.to(&mut dst);
|
||||||
|
/// // This will return None because the destination is to short.
|
||||||
|
/// assert!(result.is_none());
|
||||||
|
///
|
||||||
|
/// let to_function = try_copy_slice_least_src(&[0; 16]);
|
||||||
|
/// let mut dst = [255; 32];
|
||||||
|
/// let result = to_function.to(&mut dst);
|
||||||
|
/// // This time it works:
|
||||||
|
/// assert!(result.is_some());
|
||||||
|
/// // After the operation, the first half of `dst` will hold the same data as the original slice.
|
||||||
|
/// assert!(dst[0..16].iter().all(|b| *b == 0));
|
||||||
|
/// // The second half will have remained the same.
|
||||||
|
/// assert!(dst[16..32].iter().all(|b| *b == 255));
|
||||||
|
/// ```
|
||||||
pub fn try_copy_slice_least_src<T>(origin: &[T]) -> impl To<[T], Option<()>> + '_
|
pub fn try_copy_slice_least_src<T>(origin: &[T]) -> impl To<[T], Option<()>> + '_
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
@@ -72,6 +147,18 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Function with destination that copies all data between two array references.
|
/// Function with destination that copies all data between two array references.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```rust
|
||||||
|
/// use rosenpass_to::ops::copy_array;
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
/// let my_arr: [u8; 32] = [0; 32];
|
||||||
|
/// let to_function = copy_array(&my_arr);
|
||||||
|
/// let mut dst = [255; 32];
|
||||||
|
/// to_function.to(&mut dst);
|
||||||
|
/// // After the operation `dst` will hold the same data as the original slice.
|
||||||
|
/// assert!(dst.iter().all(|b| *b == 0));
|
||||||
|
/// ```
|
||||||
pub fn copy_array<T, const N: usize>(origin: &[T; N]) -> impl To<[T; N], ()> + '_
|
pub fn copy_array<T, const N: usize>(origin: &[T; N]) -> impl To<[T; N], ()> + '_
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
//! This module provides the [Beside] struct. In the context of functions with targets,
|
||||||
|
//! [Beside] structures the destination value and the return value unmistakably and offers useful
|
||||||
|
//! helper functions to work with them.
|
||||||
|
|
||||||
use crate::CondenseBeside;
|
use crate::CondenseBeside;
|
||||||
|
|
||||||
/// Named tuple holding the return value and the output from a function with destinations.
|
/// Named tuple holding the return value and the destination from a function with destinations.
|
||||||
|
/// See the respective functions for usage examples.
|
||||||
#[derive(Debug, PartialEq, Eq, Default, PartialOrd, Ord, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Default, PartialOrd, Ord, Copy, Clone)]
|
||||||
pub struct Beside<Val, Ret>(pub Val, pub Ret);
|
pub struct Beside<Val, Ret>(pub Val, pub Ret);
|
||||||
|
|
||||||
@@ -59,7 +64,7 @@ impl<Val, Ret> Beside<Val, Ret> {
|
|||||||
&mut self.1
|
&mut self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform beside condensation. See [CondenseBeside]
|
/// Perform beside condensation. See [CondenseBeside] for more details.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
@@ -90,3 +95,25 @@ impl<Val, Ret> From<Beside<Val, Ret>> for (Val, Ret) {
|
|||||||
(val, ret)
|
(val, ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::Beside;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_tuple() {
|
||||||
|
let tuple = (21u8, 42u16);
|
||||||
|
let beside: Beside<u8, u16> = Beside::from(tuple);
|
||||||
|
assert_eq!(beside.dest(), &21u8);
|
||||||
|
assert_eq!(beside.ret(), &42u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_beside() {
|
||||||
|
let beside: Beside<u8, u16> = Beside(21u8, 42u16);
|
||||||
|
type U8u16 = (u8, u16);
|
||||||
|
let tuple = U8u16::from(beside);
|
||||||
|
assert_eq!(tuple.0, 21u8);
|
||||||
|
assert_eq!(tuple.1, 42u16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
/// Beside condensation.
|
//! This module provides condensation for values that stand side by side,
|
||||||
|
//! which is often useful when working with destination parameters. See [CondenseBeside]
|
||||||
|
//! for more details.
|
||||||
|
|
||||||
|
/// Condenses two values that stand beside each other into one value.
|
||||||
|
/// For example, a blanked implementation for [Result<(), Error>](Result) is provided. If
|
||||||
|
/// `condense(val)` is called on such an object, a [Result<Val, Error>](Result) will
|
||||||
|
/// be returned, if `val` is of type `Val`.
|
||||||
///
|
///
|
||||||
/// This trait can be used to enable the use of [to_this(|| ...)](crate::To::to_this),
|
/// This trait can be used to enable the use of [to_this(|| ...)](crate::To::to_this),
|
||||||
/// [to_value()](crate::To::to_value), and [collect::<...>()](crate::To::collect) with custom
|
/// [to_value()](crate::To::to_value), and [collect::<...>()](crate::To::collect) with custom
|
||||||
@@ -6,6 +13,19 @@
|
|||||||
///
|
///
|
||||||
/// The function [Beside::condense()](crate::Beside::condense) is a shorthand for using the
|
/// The function [Beside::condense()](crate::Beside::condense) is a shorthand for using the
|
||||||
/// condense trait.
|
/// condense trait.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// As an example implementation, we take a look at the blanket implementation for [Option]
|
||||||
|
/// ```ignore
|
||||||
|
/// impl<Val> CondenseBeside<Val> for Option<()> {
|
||||||
|
/// type Condensed = Option<Val>;
|
||||||
|
///
|
||||||
|
/// /// Replaces the empty tuple inside this [Option] with `ret`.
|
||||||
|
/// fn condense(self, ret: Val) -> Option<Val> {
|
||||||
|
/// self.map(|()| ret)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub trait CondenseBeside<Val> {
|
pub trait CondenseBeside<Val> {
|
||||||
/// The type that results from condensation.
|
/// The type that results from condensation.
|
||||||
type Condensed;
|
type Condensed;
|
||||||
@@ -17,6 +37,7 @@ pub trait CondenseBeside<Val> {
|
|||||||
impl<Val> CondenseBeside<Val> for () {
|
impl<Val> CondenseBeside<Val> for () {
|
||||||
type Condensed = Val;
|
type Condensed = Val;
|
||||||
|
|
||||||
|
/// Replaces this empty tuple with `ret`.
|
||||||
fn condense(self, ret: Val) -> Val {
|
fn condense(self, ret: Val) -> Val {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
@@ -25,6 +46,7 @@ impl<Val> CondenseBeside<Val> for () {
|
|||||||
impl<Val, Error> CondenseBeside<Val> for Result<(), Error> {
|
impl<Val, Error> CondenseBeside<Val> for Result<(), Error> {
|
||||||
type Condensed = Result<Val, Error>;
|
type Condensed = Result<Val, Error>;
|
||||||
|
|
||||||
|
/// Replaces the empty tuple inside this [Result] with `ret`.
|
||||||
fn condense(self, ret: Val) -> Result<Val, Error> {
|
fn condense(self, ret: Val) -> Result<Val, Error> {
|
||||||
self.map(|()| ret)
|
self.map(|()| ret)
|
||||||
}
|
}
|
||||||
@@ -33,6 +55,7 @@ impl<Val, Error> CondenseBeside<Val> for Result<(), Error> {
|
|||||||
impl<Val> CondenseBeside<Val> for Option<()> {
|
impl<Val> CondenseBeside<Val> for Option<()> {
|
||||||
type Condensed = Option<Val>;
|
type Condensed = Option<Val>;
|
||||||
|
|
||||||
|
/// Replaces the empty tuple inside this [Option] with `ret`.
|
||||||
fn condense(self, ret: Val) -> Option<Val> {
|
fn condense(self, ret: Val) -> Option<Val> {
|
||||||
self.map(|()| ret)
|
self.map(|()| ret)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,28 @@
|
|||||||
/// Helper performing explicit unsized coercion.
|
//! This module provides explicit type coercion from [Sized] types to [?Sized][core::marker::Sized]
|
||||||
/// Used by the [to](crate::to()) function.
|
//! types. See [DstCoercion] for more details.
|
||||||
|
|
||||||
|
/// Helper Trait for performing explicit coercion from [Sized] types to
|
||||||
|
/// [?Sized][core::marker::Sized] types. It's used by the [to](crate::to()) function.
|
||||||
|
///
|
||||||
|
/// We provide blanket implementations for any [Sized] type and for any array of [Sized] types.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// It can be used as follows:
|
||||||
|
/// ```
|
||||||
|
/// # use rosenpass_to::DstCoercion;
|
||||||
|
/// // Consider a sized type like this example:
|
||||||
|
/// struct SizedStruct {
|
||||||
|
/// x: u32
|
||||||
|
/// }
|
||||||
|
/// // Then we can coerce it to be unsized:
|
||||||
|
/// let mut sized = SizedStruct { x: 42 };
|
||||||
|
/// assert_eq!(42, sized.coerce_dest().x);
|
||||||
|
///
|
||||||
|
/// // Analogously, we can coerce arrays to slices:
|
||||||
|
/// let mut sized_array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
/// let un_sized: &[i32] = sized_array.coerce_dest();
|
||||||
|
/// assert_eq!(un_sized, un_sized);
|
||||||
|
/// ```
|
||||||
pub trait DstCoercion<Dst: ?Sized> {
|
pub trait DstCoercion<Dst: ?Sized> {
|
||||||
/// Performs an explicit coercion to the destination type.
|
/// Performs an explicit coercion to the destination type.
|
||||||
fn coerce_dest(&mut self) -> &mut Dst;
|
fn coerce_dest(&mut self) -> &mut Dst;
|
||||||
|
|||||||
@@ -6,11 +6,16 @@
|
|||||||
//! - `Dst: ?Sized`; (e.g. [u8]) – The target to write to
|
//! - `Dst: ?Sized`; (e.g. [u8]) – The target to write to
|
||||||
//! - `Out: Sized = &mut Dst`; (e.g. &mut [u8]) – A reference to the target to write to
|
//! - `Out: Sized = &mut Dst`; (e.g. &mut [u8]) – A reference to the target to write to
|
||||||
//! - `Coercable: ?Sized + DstCoercion<Dst>`; (e.g. `[u8]`, `[u8; 16]`) – Some value that
|
//! - `Coercable: ?Sized + DstCoercion<Dst>`; (e.g. `[u8]`, `[u8; 16]`) – Some value that
|
||||||
//! destination coercion can be applied to. Usually either `Dst` itself (e.g. `[u8]` or some sized variant of
|
//! destination coercion can be applied to. Usually either `Dst` itself (e.g. `[u8]` or
|
||||||
|
//! some sized variant of
|
||||||
//! `Dst` (e.g. `[u8; 64]`).
|
//! `Dst` (e.g. `[u8; 64]`).
|
||||||
//! - `Ret: Sized`; (anything) – must be `CondenseBeside<_>` if condensing is to be applied. The ordinary return value of a function with an output
|
//! - `Ret: Sized`; (anything) – must be `CondenseBeside<_>` if condensing is to be applied. The
|
||||||
//! - `Val: Sized + BorrowMut<Dst>`; (e.g. [u8; 16]) – Some owned storage that can be borrowed as `Dst`
|
//! ordinary return value of a function with an output
|
||||||
//! - `Condensed: Sized = CondenseBeside<Val>::Condensed`; (e.g. [u8; 16], Result<[u8; 16]>) – The combiation of Val and Ret after condensing was applied (`Beside<Val, Ret>::condense()`/`Ret::condense(v)` for all `v : Val`).
|
//! - `Val: Sized + BorrowMut<Dst>`; (e.g. [u8; 16]) – Some owned storage that can be borrowed as
|
||||||
|
//! `Dst`
|
||||||
|
//! - `Condensed: Sized = CondenseBeside<Val>::Condensed`; (e.g. [u8; 16], Result<[u8; 16]>)
|
||||||
|
//! – The combiation of Val and Ret after condensing was applied
|
||||||
|
//! (`Beside<Val, Ret>::condense()`/`Ret::condense(v)` for all `v : Val`).
|
||||||
|
|
||||||
pub mod beside;
|
pub mod beside;
|
||||||
pub mod condense;
|
pub mod condense;
|
||||||
|
|||||||
@@ -1,9 +1,23 @@
|
|||||||
|
//! This module provides the [To::to] function which allows to use functions with destination in
|
||||||
|
//! a manner akin to that of a variable assignment. See [To::to] for more details.
|
||||||
|
|
||||||
use crate::{DstCoercion, To};
|
use crate::{DstCoercion, To};
|
||||||
|
|
||||||
/// Alias for [To::to] moving the destination to the left.
|
/// Alias for [To::to] moving the destination to the left.
|
||||||
///
|
///
|
||||||
/// This provides similar haptics to the let assignment syntax is rust, which also keeps
|
/// This provides similar haptics to the let assignment syntax is rust, which also keeps
|
||||||
/// the variable to assign to on the left and the generating function on the right.
|
/// the variable to assign to on the left and the generating function on the right.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```rust
|
||||||
|
/// // Using the to function to have data flowing from the right to the left,
|
||||||
|
/// // performing something akin to a variable assignment.
|
||||||
|
/// use rosenpass_to::ops::copy_slice_least;
|
||||||
|
/// # use rosenpass_to::to;
|
||||||
|
/// let mut dst = b" ".to_vec();
|
||||||
|
/// to(&mut dst[..], copy_slice_least(b"Hello World"));
|
||||||
|
/// assert_eq!(&dst[..], b"Hello World");
|
||||||
|
/// ```
|
||||||
pub fn to<Coercable, Src, Dst, Ret>(dst: &mut Coercable, src: Src) -> Ret
|
pub fn to<Coercable, Src, Dst, Ret>(dst: &mut Coercable, src: Src) -> Ret
|
||||||
where
|
where
|
||||||
Coercable: ?Sized + DstCoercion<Dst>,
|
Coercable: ?Sized + DstCoercion<Dst>,
|
||||||
|
|||||||
@@ -1,12 +1,46 @@
|
|||||||
|
//! Module that contains the [To] crate which is the container used to
|
||||||
|
//! implement the core functionality of this crate.
|
||||||
|
|
||||||
use crate::{Beside, CondenseBeside};
|
use crate::{Beside, CondenseBeside};
|
||||||
use std::borrow::BorrowMut;
|
use std::borrow::BorrowMut;
|
||||||
|
|
||||||
/// The To trait is the core of the to crate; most functions with destinations will either return
|
/// The To trait is the core of the to crate; most functions with destinations will either return
|
||||||
/// an object that is an instance of this trait or they will return `-> impl To<Destination,
|
/// an object that is an instance of this trait, or they will return `-> impl To<Destination,
|
||||||
/// Return_value`.
|
/// Return_value>`.
|
||||||
///
|
///
|
||||||
/// A quick way to implement a function with destination is to use the
|
/// A quick way to implement a function with destination is to use the
|
||||||
/// [with_destination(|param: &mut Type| ...)] higher order function.
|
/// [with_destination(|param: &mut Type| ...)](crate::with_destination) higher order function.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Below, we provide a very simple example for how the Trait can be implemented. More examples for
|
||||||
|
/// how this Trait is best implemented can be found in the overall [crate documentation](crate).
|
||||||
|
/// ```
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
///
|
||||||
|
/// // This is a simple wrapper around a String that can be written into a byte array using to.
|
||||||
|
/// struct StringToBytes {
|
||||||
|
/// inner: String
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl To<[u8], Result<(), String>> for StringToBytes {
|
||||||
|
/// fn to(self, out: &mut [u8]) -> Result<(), String> {
|
||||||
|
/// let bytes = self.inner.as_bytes();
|
||||||
|
/// if bytes.len() > out.len() {
|
||||||
|
/// return Err("out is to short".to_string());
|
||||||
|
/// }
|
||||||
|
/// for i in 0..bytes.len() {
|
||||||
|
/// (*out)[i] = bytes[i];
|
||||||
|
/// }
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let string_to_bytes = StringToBytes { inner: "my message".to_string() };
|
||||||
|
/// let mut buffer: [u8; 10] = [0; 10];
|
||||||
|
/// let result = string_to_bytes.to(&mut buffer);
|
||||||
|
/// assert_eq!(buffer, [109, 121, 32, 109, 101, 115, 115, 97, 103, 101]);
|
||||||
|
/// assert!(result.is_ok());
|
||||||
|
/// ```
|
||||||
pub trait To<Dst: ?Sized, Ret>: Sized {
|
pub trait To<Dst: ?Sized, Ret>: Sized {
|
||||||
/// Writes self to the destination `out` and returns a value of type `Ret`.
|
/// Writes self to the destination `out` and returns a value of type `Ret`.
|
||||||
///
|
///
|
||||||
@@ -19,6 +53,36 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
|||||||
/// calls [crate::to()] to evaluate the function and finally
|
/// calls [crate::to()] to evaluate the function and finally
|
||||||
/// returns a [Beside] instance containing the generated destination value and the return
|
/// returns a [Beside] instance containing the generated destination value and the return
|
||||||
/// value.
|
/// value.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Below, we rewrite the example for the overall [To]-Trait and simplify it by using
|
||||||
|
/// [self.to_this_beside]. We refer to the overall [crate documentation](crate)
|
||||||
|
/// for more examples and general explanations.
|
||||||
|
/// ```
|
||||||
|
/// # use rosenpass_to::To;
|
||||||
|
/// use rosenpass_to::Beside;
|
||||||
|
/// # struct StringToBytes {
|
||||||
|
/// # inner: String
|
||||||
|
/// # }
|
||||||
|
///
|
||||||
|
/// # impl To<[u8], Result<(), String>> for StringToBytes {
|
||||||
|
/// # fn to(self, out: &mut [u8]) -> Result<(), String> {
|
||||||
|
/// # let bytes = self.inner.as_bytes();
|
||||||
|
/// # if bytes.len() > out.len() {
|
||||||
|
/// # return Err("out is to short".to_string());
|
||||||
|
/// # }
|
||||||
|
/// # for i in 0..bytes.len() {
|
||||||
|
/// # (*out)[i] = bytes[i];
|
||||||
|
/// # }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// // StringToBytes is taken from the overall Trait example.
|
||||||
|
/// let string_to_bytes = StringToBytes { inner: "my message".to_string() };
|
||||||
|
/// let Beside(dst, result) = string_to_bytes.to_this_beside(|| [0; 10]);
|
||||||
|
/// assert_eq!(dst, [109, 121, 32, 109, 101, 115, 115, 97, 103, 101]);
|
||||||
|
/// assert!(result.is_ok());
|
||||||
|
/// ```
|
||||||
fn to_this_beside<Val, Fun>(self, fun: Fun) -> Beside<Val, Ret>
|
fn to_this_beside<Val, Fun>(self, fun: Fun) -> Beside<Val, Ret>
|
||||||
where
|
where
|
||||||
Val: BorrowMut<Dst>,
|
Val: BorrowMut<Dst>,
|
||||||
@@ -31,10 +95,21 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
|||||||
|
|
||||||
/// Generate a destination on the fly using default.
|
/// Generate a destination on the fly using default.
|
||||||
///
|
///
|
||||||
/// Uses [Default] to create a value,
|
/// Uses [Default] to create a value, calls [crate::to()] to evaluate the function and finally
|
||||||
/// calls [crate::to()] to evaluate the function and finally
|
|
||||||
/// returns a [Beside] instance containing the generated destination value and the return
|
/// returns a [Beside] instance containing the generated destination value and the return
|
||||||
/// value.
|
/// value.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Below, we provide a simple example for the usage of [to_value_beside](To::to_value_beside).
|
||||||
|
/// We refer to the overall [crate documentation](crate) for more examples and general
|
||||||
|
/// explanations.
|
||||||
|
/// ```
|
||||||
|
/// use rosenpass_to::Beside;
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
/// use rosenpass_to::ops::*;
|
||||||
|
/// let Beside(dst, ret) = copy_array(&[42u8; 16]).to_value_beside();
|
||||||
|
/// assert_eq!(dst, [42u8; 16]);
|
||||||
|
/// ```
|
||||||
fn to_value_beside(self) -> Beside<Dst, Ret>
|
fn to_value_beside(self) -> Beside<Dst, Ret>
|
||||||
where
|
where
|
||||||
Dst: Sized + Default,
|
Dst: Sized + Default,
|
||||||
@@ -53,6 +128,19 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
|||||||
/// when the Destination is unsized.
|
/// when the Destination is unsized.
|
||||||
///
|
///
|
||||||
/// This could be the case when the destination is an `[u8]` for instance.
|
/// This could be the case when the destination is an `[u8]` for instance.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Below, we provide a simple example for the usage of [collect_beside](To::collect_beside).
|
||||||
|
/// We refer to the overall [crate documentation](crate) for more examples and general
|
||||||
|
/// explanations.
|
||||||
|
/// ```
|
||||||
|
/// use rosenpass_to::Beside;
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
/// use rosenpass_to::ops::*;
|
||||||
|
///
|
||||||
|
/// let Beside(dst, ret) = copy_slice(&[42u8; 16]).collect_beside::<[u8; 16]>();
|
||||||
|
/// assert_eq!(dst, [42u8; 16]);
|
||||||
|
/// ```
|
||||||
fn collect_beside<Val>(self) -> Beside<Val, Ret>
|
fn collect_beside<Val>(self) -> Beside<Val, Ret>
|
||||||
where
|
where
|
||||||
Val: Default + BorrowMut<Dst>,
|
Val: Default + BorrowMut<Dst>,
|
||||||
@@ -64,6 +152,36 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
|||||||
/// return value into one.
|
/// return value into one.
|
||||||
///
|
///
|
||||||
/// This is like using [Self::to_this_beside] followed by calling [Beside::condense].
|
/// This is like using [Self::to_this_beside] followed by calling [Beside::condense].
|
||||||
|
/// # Example
|
||||||
|
/// Below, we rewrite the example for the overall [To]-Trait and simplify it by using
|
||||||
|
/// [Self::to_this]. We refer to the overall [crate documentation](crate)
|
||||||
|
/// for more examples and general explanations.
|
||||||
|
/// ```
|
||||||
|
/// # use rosenpass_to::To;
|
||||||
|
/// use rosenpass_to::Beside;
|
||||||
|
/// # struct StringToBytes {
|
||||||
|
/// # inner: String
|
||||||
|
/// # }
|
||||||
|
///
|
||||||
|
/// # impl To<[u8], Result<(), String>> for StringToBytes {
|
||||||
|
/// # fn to(self, out: &mut [u8]) -> Result<(), String> {
|
||||||
|
/// # let bytes = self.inner.as_bytes();
|
||||||
|
/// # if bytes.len() > out.len() {
|
||||||
|
/// # return Err("out is to short".to_string());
|
||||||
|
/// # }
|
||||||
|
/// # for i in 0..bytes.len() {
|
||||||
|
/// # (*out)[i] = bytes[i];
|
||||||
|
/// # }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// // StringToBytes is taken from the overall Trait example.
|
||||||
|
/// let string_to_bytes = StringToBytes { inner: "my message".to_string() };
|
||||||
|
/// let result = string_to_bytes.to_this_beside(|| [0; 10]).condense();
|
||||||
|
/// assert!(result.is_ok());
|
||||||
|
/// assert_eq!(result.unwrap(), [109, 121, 32, 109, 101, 115, 115, 97, 103, 101]);
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
fn to_this<Val, Fun>(self, fun: Fun) -> <Ret as CondenseBeside<Val>>::Condensed
|
fn to_this<Val, Fun>(self, fun: Fun) -> <Ret as CondenseBeside<Val>>::Condensed
|
||||||
where
|
where
|
||||||
Ret: CondenseBeside<Val>,
|
Ret: CondenseBeside<Val>,
|
||||||
@@ -77,6 +195,18 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
|||||||
/// return value into one.
|
/// return value into one.
|
||||||
///
|
///
|
||||||
/// This is like using [Self::to_value_beside] followed by calling [Beside::condense].
|
/// This is like using [Self::to_value_beside] followed by calling [Beside::condense].
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Below, we provide a simple example for the usage of [to_value](To::to_value).
|
||||||
|
/// We refer to the overall [crate documentation](crate) for more examples and general
|
||||||
|
/// explanations.
|
||||||
|
/// ```
|
||||||
|
/// use rosenpass_to::Beside;
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
/// use rosenpass_to::ops::*;
|
||||||
|
/// let dst = copy_array(&[42u8; 16]).to_value_beside().condense();
|
||||||
|
/// assert_eq!(dst, [42u8; 16]);
|
||||||
|
/// ```
|
||||||
fn to_value(self) -> <Ret as CondenseBeside<Dst>>::Condensed
|
fn to_value(self) -> <Ret as CondenseBeside<Dst>>::Condensed
|
||||||
where
|
where
|
||||||
Dst: Sized + Default,
|
Dst: Sized + Default,
|
||||||
@@ -89,6 +219,19 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
|||||||
/// return value into one.
|
/// return value into one.
|
||||||
///
|
///
|
||||||
/// This is like using [Self::collect_beside] followed by calling [Beside::condense].
|
/// This is like using [Self::collect_beside] followed by calling [Beside::condense].
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Below, we provide a simple example for the usage of [collect](To::collect).
|
||||||
|
/// We refer to the overall [crate documentation](crate) for more examples and general
|
||||||
|
/// explanations.
|
||||||
|
/// ```
|
||||||
|
/// use rosenpass_to::Beside;
|
||||||
|
/// use rosenpass_to::To;
|
||||||
|
/// use rosenpass_to::ops::*;
|
||||||
|
///
|
||||||
|
/// let dst = copy_slice(&[42u8; 16]).collect_beside::<[u8; 16]>().condense();
|
||||||
|
/// assert_eq!(dst, [42u8; 16]);
|
||||||
|
/// ```
|
||||||
fn collect<Val>(self) -> <Ret as CondenseBeside<Val>>::Condensed
|
fn collect<Val>(self) -> <Ret as CondenseBeside<Val>>::Condensed
|
||||||
where
|
where
|
||||||
Val: Default + BorrowMut<Dst>,
|
Val: Default + BorrowMut<Dst>,
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
|
//! The module provides the [with_destination] function, which makes it easy to create
|
||||||
|
//! a [To] from a lambda function. See [with_destination] and the [crate documentation](crate)
|
||||||
|
//! for more details and examples.
|
||||||
|
|
||||||
use crate::To;
|
use crate::To;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// A struct that wraps a closure and implements the `To` trait
|
/// A struct that wraps a closure and implements the `To` trait.
|
||||||
///
|
///
|
||||||
/// This allows passing closures that operate on a destination type `Dst`
|
/// This allows passing closures that operate on a destination type `Dst`
|
||||||
/// and return `Ret`.
|
/// and return `Ret`. It is only internally used to implement [with_destination].
|
||||||
///
|
///
|
||||||
/// # Type Parameters
|
/// # Type Parameters
|
||||||
/// * `Dst` - The destination type the closure operates on
|
/// * `Dst` - The destination type the closure operates on.
|
||||||
/// * `Ret` - The return type of the closure
|
/// * `Ret` - The return type of the closure.
|
||||||
/// * `Fun` - The closure type that implements `FnOnce(&mut Dst) -> Ret`
|
/// * `Fun` - The closure type that implements `FnOnce(&mut Dst) -> Ret`.
|
||||||
struct ToClosure<Dst, Ret, Fun>
|
struct ToClosure<Dst, Ret, Fun>
|
||||||
where
|
where
|
||||||
Dst: ?Sized,
|
Dst: ?Sized,
|
||||||
@@ -17,11 +21,11 @@ where
|
|||||||
{
|
{
|
||||||
/// The function to call.
|
/// The function to call.
|
||||||
fun: Fun,
|
fun: Fun,
|
||||||
/// Phantom data to hold the destination type
|
/// Phantom data to hold the destination type.
|
||||||
_val: PhantomData<Box<Dst>>,
|
_val: PhantomData<Box<Dst>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of the `To` trait for ToClosure
|
/// Implementation of the `To` trait for ToClosure.
|
||||||
///
|
///
|
||||||
/// This enables calling the wrapped closure with a destination reference.
|
/// This enables calling the wrapped closure with a destination reference.
|
||||||
impl<Dst, Ret, Fun> To<Dst, Ret> for ToClosure<Dst, Ret, Fun>
|
impl<Dst, Ret, Fun> To<Dst, Ret> for ToClosure<Dst, Ret, Fun>
|
||||||
@@ -33,6 +37,7 @@ where
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `out` - Mutable reference to the destination
|
/// * `out` - Mutable reference to the destination
|
||||||
|
/// See the tutorial in [readme.md] for examples and more explanations.
|
||||||
fn to(self, out: &mut Dst) -> Ret {
|
fn to(self, out: &mut Dst) -> Ret {
|
||||||
(self.fun)(out)
|
(self.fun)(out)
|
||||||
}
|
}
|
||||||
@@ -48,7 +53,24 @@ where
|
|||||||
/// * `Ret` - The return type of the closure
|
/// * `Ret` - The return type of the closure
|
||||||
/// * `Fun` - The closure type that implements `FnOnce(&mut Dst) -> Ret`
|
/// * `Fun` - The closure type that implements `FnOnce(&mut Dst) -> Ret`
|
||||||
///
|
///
|
||||||
/// See the tutorial in [readme.me]..
|
/// See the tutorial in the [crate documentation](crate) for more examples and more explanations.
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use rosenpass_to::with_destination;
|
||||||
|
/// use crate::rosenpass_to::To;
|
||||||
|
/// let my_origin_data: [u8; 16]= [2; 16];
|
||||||
|
/// let times_two = with_destination( move |dst: &mut [u8; 16]| {
|
||||||
|
/// for (dst, org) in dst.iter_mut().zip(my_origin_data.iter()) {
|
||||||
|
/// *dst = dst.clone() * org;
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
/// let mut dst: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||||
|
/// times_two.to(&mut dst);
|
||||||
|
/// for i in 0..16 {
|
||||||
|
/// assert_eq!(dst[i], (2 * i) as u8);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
pub fn with_destination<Dst, Ret, Fun>(fun: Fun) -> impl To<Dst, Ret>
|
pub fn with_destination<Dst, Ret, Fun>(fun: Fun) -> impl To<Dst, Ret>
|
||||||
where
|
where
|
||||||
Dst: ?Sized,
|
Dst: ?Sized,
|
||||||
|
|||||||
Reference in New Issue
Block a user