mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-09 22:30:31 -08:00
Compare commits
4 Commits
dev/karo/k
...
docu-tests
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
caf91c84f0 | ||
|
|
f5b4c17011 | ||
|
|
12506e5f95 | ||
|
|
965600212d |
@@ -20,3 +20,6 @@ memsec = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8.5"
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(coverage)'] }
|
||||
|
||||
@@ -113,9 +113,10 @@ mod tests {
|
||||
// Pearson correlation
|
||||
let correlation = cv / (sd_x * sd_y);
|
||||
println!("correlation: {:.6?}", correlation);
|
||||
#[cfg(not(coverage))]
|
||||
assert!(
|
||||
correlation.abs() < 0.01,
|
||||
"execution time correlates with result"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,3 +91,6 @@ experiment_api = [
|
||||
internal_signal_handling_for_coverage_reports = ["signal-hook"]
|
||||
internal_testing = []
|
||||
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
|
||||
// so the signal is absorbed
|
||||
loop {
|
||||
rustix::process::kill_process(pid, Term).discard_result();
|
||||
kill_process(pid, Term).discard_result();
|
||||
if self.0.try_wait().unwrap().is_some() {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
use std::{
|
||||
borrow::{Borrow, BorrowMut},
|
||||
collections::VecDeque,
|
||||
fmt::{Debug, Write},
|
||||
ops::{DerefMut, RangeBounds},
|
||||
ops::DerefMut,
|
||||
};
|
||||
|
||||
use rand::distributions::uniform::SampleBorrow;
|
||||
use rosenpass_cipher_traits::Kem;
|
||||
use rosenpass_ciphers::kem::StaticKem;
|
||||
use rosenpass_util::result::OkExt;
|
||||
@@ -28,48 +26,53 @@ fn test_successful_exchange_with_poll() -> anyhow::Result<()> {
|
||||
sim.poll_loop(150)?; // Poll 75 times
|
||||
let transcript = sim.transcript;
|
||||
|
||||
let completions: Vec<_> = transcript
|
||||
let _completions: Vec<_> = transcript
|
||||
.iter()
|
||||
.filter(|elm| matches!(elm, (_, TranscriptEvent::CompletedExchange(_))))
|
||||
.collect();
|
||||
|
||||
#[cfg(not(coverage))]
|
||||
assert!(
|
||||
!completions.is_empty(),
|
||||
!_completions.is_empty(),
|
||||
"\
|
||||
Should have performed a successful key exchanged!\n\
|
||||
Transcript: {transcript:?}\n\
|
||||
Completions: {completions:?}\
|
||||
Completions: {_completions:?}\
|
||||
"
|
||||
);
|
||||
#[cfg(not(coverage))]
|
||||
assert!(
|
||||
completions[0].0 < 20.0,
|
||||
_completions[0].0 < 20.0,
|
||||
"\
|
||||
First key exchange should happen in under twenty seconds!\n\
|
||||
Transcript: {transcript:?}\n\
|
||||
Completions: {completions:?}\
|
||||
Completions: {_completions:?}\
|
||||
"
|
||||
);
|
||||
|
||||
#[cfg(not(coverage))]
|
||||
assert!(
|
||||
completions.len() >= 3,
|
||||
_completions.len() >= 3,
|
||||
"\
|
||||
Should have at least two renegotiations!\n\
|
||||
Transcript: {transcript:?}\n\
|
||||
Completions: {completions:?}\
|
||||
Completions: {_completions:?}\
|
||||
"
|
||||
);
|
||||
#[cfg(not(coverage))]
|
||||
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\
|
||||
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\
|
||||
Transcript: {transcript:?}\n\
|
||||
Completions: {completions:?}\
|
||||
Completions: {_completions:?}\
|
||||
");
|
||||
|
||||
Ok(())
|
||||
@@ -106,48 +109,53 @@ fn test_successful_exchange_under_packet_loss() -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
let transcript = sim.transcript;
|
||||
let completions: Vec<_> = transcript
|
||||
let _completions: Vec<_> = transcript
|
||||
.iter()
|
||||
.filter(|elm| matches!(elm, (_, TranscriptEvent::CompletedExchange(_))))
|
||||
.collect();
|
||||
|
||||
#[cfg(not(coverage))]
|
||||
assert!(
|
||||
!completions.is_empty(),
|
||||
!_completions.is_empty(),
|
||||
"\
|
||||
Should have performed a successful key exchanged!\n\
|
||||
Transcript: {transcript:?}\n\
|
||||
Completions: {completions:?}\
|
||||
Completions: {_completions:?}\
|
||||
"
|
||||
);
|
||||
#[cfg(not(coverage))]
|
||||
assert!(
|
||||
completions[0].0 < 10.0,
|
||||
_completions[0].0 < 10.0,
|
||||
"\
|
||||
First key exchange should happen in under twenty seconds!\n\
|
||||
Transcript: {transcript:?}\n\
|
||||
Completions: {completions:?}\
|
||||
Completions: {_completions:?}\
|
||||
"
|
||||
);
|
||||
|
||||
#[cfg(not(coverage))]
|
||||
assert!(
|
||||
completions.len() >= 3,
|
||||
_completions.len() >= 3,
|
||||
"\
|
||||
Should have at least two renegotiations!\n\
|
||||
Transcript: {transcript:?}\n\
|
||||
Completions: {completions:?}\
|
||||
Completions: {_completions:?}\
|
||||
"
|
||||
);
|
||||
#[cfg(not(coverage))]
|
||||
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\
|
||||
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\
|
||||
Transcript: {transcript:?}\n\
|
||||
Completions: {completions:?}\
|
||||
Completions: {_completions:?}\
|
||||
");
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -17,13 +17,14 @@ use rosenpass_to::{to, with_destination, To};
|
||||
use std::ops::BitXorAssign;
|
||||
|
||||
// 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
|
||||
fn xor_slice<'a, T>(src: &'a [T]) -> impl To<[T], ()> + 'a
|
||||
where
|
||||
T: BitXorAssign + Clone,
|
||||
{
|
||||
// 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]| {
|
||||
assert!(src.len() == dst.len());
|
||||
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};
|
||||
|
||||
@@ -8,6 +9,17 @@ use crate::{with_destination, To};
|
||||
/// # Panics
|
||||
///
|
||||
/// 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], ()> + '_
|
||||
where
|
||||
T: Copy,
|
||||
@@ -23,6 +35,19 @@ where
|
||||
/// # Panics
|
||||
///
|
||||
/// 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], ()> + '_
|
||||
where
|
||||
T: Copy,
|
||||
@@ -34,6 +59,18 @@ where
|
||||
/// destination.
|
||||
///
|
||||
/// 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], ()> + '_
|
||||
where
|
||||
T: Copy,
|
||||
@@ -47,6 +84,24 @@ where
|
||||
/// Function with destination that attempts to copy data from origin into the destination.
|
||||
///
|
||||
/// 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<()>> + '_
|
||||
where
|
||||
T: Copy,
|
||||
@@ -62,6 +117,26 @@ where
|
||||
/// Destination may be longer 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<()>> + '_
|
||||
where
|
||||
T: Copy,
|
||||
@@ -72,6 +147,18 @@ where
|
||||
}
|
||||
|
||||
/// 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], ()> + '_
|
||||
where
|
||||
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;
|
||||
|
||||
/// 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)]
|
||||
pub struct Beside<Val, Ret>(pub Val, pub Ret);
|
||||
|
||||
@@ -59,7 +64,7 @@ impl<Val, Ret> Beside<Val, Ret> {
|
||||
&mut self.1
|
||||
}
|
||||
|
||||
/// Perform beside condensation. See [CondenseBeside]
|
||||
/// Perform beside condensation. See [CondenseBeside] for more details.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
@@ -90,3 +95,25 @@ impl<Val, Ret> From<Beside<Val, Ret>> for (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),
|
||||
/// [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
|
||||
/// 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> {
|
||||
/// The type that results from condensation.
|
||||
type Condensed;
|
||||
@@ -17,6 +37,7 @@ pub trait CondenseBeside<Val> {
|
||||
impl<Val> CondenseBeside<Val> for () {
|
||||
type Condensed = Val;
|
||||
|
||||
/// Replaces this empty tuple with `ret`.
|
||||
fn condense(self, ret: Val) -> Val {
|
||||
ret
|
||||
}
|
||||
@@ -25,6 +46,7 @@ impl<Val> CondenseBeside<Val> for () {
|
||||
impl<Val, Error> CondenseBeside<Val> for Result<(), Error> {
|
||||
type Condensed = Result<Val, Error>;
|
||||
|
||||
/// Replaces the empty tuple inside this [Result] with `ret`.
|
||||
fn condense(self, ret: Val) -> Result<Val, Error> {
|
||||
self.map(|()| ret)
|
||||
}
|
||||
@@ -33,6 +55,7 @@ impl<Val, Error> CondenseBeside<Val> for Result<(), Error> {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
/// Helper performing explicit unsized coercion.
|
||||
/// Used by the [to](crate::to()) function.
|
||||
//! This module provides explicit type coercion from [Sized] types to [?Sized][core::marker::Sized]
|
||||
//! 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> {
|
||||
/// Performs an explicit coercion to the destination type.
|
||||
fn coerce_dest(&mut self) -> &mut Dst;
|
||||
|
||||
@@ -6,11 +6,16 @@
|
||||
//! - `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
|
||||
//! - `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]`).
|
||||
//! - `Ret: Sized`; (anything) – must be `CondenseBeside<_>` if condensing is to be applied. The ordinary return value of a function with an output
|
||||
//! - `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`).
|
||||
//! - `Ret: Sized`; (anything) – must be `CondenseBeside<_>` if condensing is to be applied. The
|
||||
//! ordinary return value of a function with an output
|
||||
//! - `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 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};
|
||||
|
||||
/// Alias for [To::to] moving the destination to the left.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// # 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
|
||||
where
|
||||
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 std::borrow::BorrowMut;
|
||||
|
||||
/// 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,
|
||||
/// Return_value`.
|
||||
/// an object that is an instance of this trait, or they will return `-> impl To<Destination,
|
||||
/// Return_value>`.
|
||||
///
|
||||
/// 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 {
|
||||
/// 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
|
||||
/// returns a [Beside] instance containing the generated destination value and the return
|
||||
/// 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>
|
||||
where
|
||||
Val: BorrowMut<Dst>,
|
||||
@@ -31,10 +95,21 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
||||
|
||||
/// Generate a destination on the fly using default.
|
||||
///
|
||||
/// Uses [Default] to create a value,
|
||||
/// calls [crate::to()] to evaluate the function and finally
|
||||
/// Uses [Default] to create a value, calls [crate::to()] to evaluate the function and finally
|
||||
/// returns a [Beside] instance containing the generated destination value and the return
|
||||
/// 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>
|
||||
where
|
||||
Dst: Sized + Default,
|
||||
@@ -53,6 +128,19 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
||||
/// when the Destination is unsized.
|
||||
///
|
||||
/// 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>
|
||||
where
|
||||
Val: Default + BorrowMut<Dst>,
|
||||
@@ -64,6 +152,36 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
||||
/// return value into one.
|
||||
///
|
||||
/// 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
|
||||
where
|
||||
Ret: CondenseBeside<Val>,
|
||||
@@ -77,6 +195,18 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
||||
/// return value into one.
|
||||
///
|
||||
/// 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
|
||||
where
|
||||
Dst: Sized + Default,
|
||||
@@ -89,6 +219,19 @@ pub trait To<Dst: ?Sized, Ret>: Sized {
|
||||
/// return value into one.
|
||||
///
|
||||
/// 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
|
||||
where
|
||||
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 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`
|
||||
/// and return `Ret`.
|
||||
/// and return `Ret`. It is only internally used to implement [with_destination].
|
||||
///
|
||||
/// # Type Parameters
|
||||
/// * `Dst` - The destination type the closure operates on
|
||||
/// * `Ret` - The return type of the closure
|
||||
/// * `Fun` - The closure type that implements `FnOnce(&mut Dst) -> Ret`
|
||||
/// * `Dst` - The destination type the closure operates on.
|
||||
/// * `Ret` - The return type of the closure.
|
||||
/// * `Fun` - The closure type that implements `FnOnce(&mut Dst) -> Ret`.
|
||||
struct ToClosure<Dst, Ret, Fun>
|
||||
where
|
||||
Dst: ?Sized,
|
||||
@@ -17,11 +21,11 @@ where
|
||||
{
|
||||
/// The function to call.
|
||||
fun: Fun,
|
||||
/// Phantom data to hold the destination type
|
||||
/// Phantom data to hold the destination type.
|
||||
_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.
|
||||
impl<Dst, Ret, Fun> To<Dst, Ret> for ToClosure<Dst, Ret, Fun>
|
||||
@@ -33,6 +37,7 @@ where
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `out` - Mutable reference to the destination
|
||||
/// See the tutorial in [readme.md] for examples and more explanations.
|
||||
fn to(self, out: &mut Dst) -> Ret {
|
||||
(self.fun)(out)
|
||||
}
|
||||
@@ -48,7 +53,24 @@ where
|
||||
/// * `Ret` - The return type of the closure
|
||||
/// * `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>
|
||||
where
|
||||
Dst: ?Sized,
|
||||
|
||||
Reference in New Issue
Block a user