Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"b343ee560e32d80f6ef606a52146164ff5bc8ac542a5f0061c5a91ae745a42d5","Cargo.toml":"e1411b0ffb2a7d409e1706baf31dd4536fdf8834bcc62ca6d4bb1105733fe7cd","Cargo.toml.orig":"70d9f6e252afd5d674437f0c5c1f87ab42c2f0e9cab978f56ec767db36f5fe88","LICENSE.txt":"8b4e95f5cf0dc40269c99f7b787203ffe04ded245ca2427422c196efa2b2f42a","README.md":"3a5f65cba4a285afee207a17ef158bd1348345e990ce02b14973774f5119c66f","src/conv.rs":"9c975b0607d3b81cec7c7c6a9b6b732f8a4dd1beb303a07ab165471b5e0dc37c","src/lib.rs":"402e6c0456861a2632c93f062b8af47fa0d701241a39d70cd0fe6732504f76b3","src/pipe.rs":"d969c608ef598742b34fb4b84b79085bb7f28d551f596dcdc14f8d5fab110261","src/tap.rs":"a69cc67fbf2607385948b2a7e465431bc0dd0d967841c433d89c9a5082ce262c"},"package":"55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"}
+5
View File
@@ -0,0 +1,5 @@
{
"git": {
"sha1": "f5315f0f5ca90ce6399daac76c1fe3ba645a4e4e"
}
}
+25
View File
@@ -0,0 +1,25 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "tap"
version = "1.0.1"
authors = ["Elliott Linder <elliott.darfink@gmail.com>", "myrrlyn <self@myrrlyn.dev>"]
include = ["Cargo.toml", "README.md", "LICENSE.txt", "src/**/*.rs"]
description = "Generic extensions for tapping values in Rust"
homepage = "https://github.com/myrrlyn/tap"
documentation = "https://docs.rs/tap"
readme = "README.md"
keywords = ["tap", "pipe", "functional", "tap_ok", "tap_some"]
categories = ["no-std", "rust-patterns"]
license = "MIT"
repository = "https://github.com/myrrlyn/tap"
+30
View File
@@ -0,0 +1,30 @@
[package]
authors = [
"Elliott Linder <elliott.darfink@gmail.com>",
"myrrlyn <self@myrrlyn.dev>",
]
categories = [
"no-std",
"rust-patterns",
]
description = "Generic extensions for tapping values in Rust"
documentation = "https://docs.rs/tap"
homepage = "https://github.com/myrrlyn/tap"
include = [
"Cargo.toml",
"README.md",
"LICENSE.txt",
"src/**/*.rs",
]
keywords = [
"tap",
"pipe",
"functional",
"tap_ok",
"tap_some",
]
license = "MIT"
name = "tap"
readme = "README.md"
repository = "https://github.com/myrrlyn/tap"
version = "1.0.1"
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Elliot Linder <darfink@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+203
View File
@@ -0,0 +1,203 @@
<div class="title-block" style="text-align: center;" align="center">
# `tap` <!-- omit in toc -->
## Suffix-Position Pipeline Behavior <!-- omit in toc -->
[![Crate][crate_img]][crate]
[![Documentation][docs_img]][docs]
[![License][license_img]][license_file]
[![Crate Downloads][downloads_img]][crate]
[![Crate Size][loc_img]][loc]
</div>
This crate provides extension methods on all types that allow transparent,
temporary, inspection/mutation (tapping), transformation (piping), or type
conversion. These methods make it convenient for you to insert debugging or
modification points into an expression without requiring you to change any other
portions of your code.
## Example Use
### Tapping
You can tap inside a method-chain expression for logging without requiring a
rebind. For instance, you may write a complex expression without any
intermediate debugging steps, and only later decide that you want them.
Ordinarily, this transform would look like this:
```rust
extern crate reqwest;
extern crate tracing;
// old
let body = reqwest::blocking::get("https://example.com")?
.text()?;
tracing::debug!("Response contents: {}", body);
// new, with debugging
let resp = reqwest::blocking::get("https://example.com")?;
tracing::debug!("Response status: {}", resp.status());
let body = resp.text()?;
tracing::debug!("Response contents: {}", body);
```
while with tapping, you can plug the logging statement directly into the overall
expression, without making any other changes:
```rust
extern crate reqwest;
extern crate tracing;
let body = reqwest::blocking::get("https://example.com")?
// The only change is the insertion of this line
.tap(|resp| tracing::debug!("Response status: {}", resp.status()))
.text()?;
tracing::debug!("Response contents: {}", body);
```
### Mutable Tapping
Some APIs are written to require mutable borrows, rather than value-to-value
transformations, which can require temporary rebinding in order to create
mutability in an otherwise-immutable context. For example, collecting data into
a vector, sorting the vector, and then freezing it, might look like this:
```rust
let mut collection = stream().collect::<Vec<_>>();
collection.sort();
// potential error site: inserting other mutations here
let collection = collection; // now immutable
```
But with a mutable tap, you can avoid the duplicate binding *and* guard against
future errors due to the presence of a mutable binding:
```rust
let collection = stream.collect::<Vec<_>>()
.tap_mut(|v| v.sort());
```
The `.tap_mut()` and related methods provide a mutable borrow to their argument,
and allow the final binding site to choose their own level of mutability without
exposing the intermediate permission.
### Piping
In addition to transparent inspection or modification points, you may also wish
to use suffix calls for subsequent operations. For example, the standard library
offers the free function `fs::read` to convert `Path`-like objects into
`Vec<u8>` of their filesystem contents. Ordinarily, free functions require use
as:
```rust
use std::fs;
let mut path = get_base_path();
path.push("logs");
path.push(&format!("{}.log", today()));
let contents = fs::read(path)?;
```
whereäs use of tapping (for path modification) and piping (for `fs::read`) could
be expressed like this:
```rust
use std::fs;
let contents = get_base_path()
.tap_mut(|p| p.push("logs"))
.tap_mut(|p| p.push(&format!("{}.log", today())))
.pipe(fs::read)?;
```
As a clearer example, consider the syntax required to apply multiple free
funtions without `let`-bindings looks like this:
```rust
let val = last(
third(
second(
first(original_value),
another_arg,
)
),
another_arg,
);
```
which requires reading the expression in alternating, inside-out, order, to
understand the full sequence of evaluation. With suffix calls, even free
functions can be written in a point-free style that maintains a clear temporal
and syntactic order:
```rust
let val = original_value
.pipe(first)
.pipe(|v| second(v, another_arg))
.pipe(third)
.pipe(|v| last(v, another_arg));
```
As piping is an ordinary method, not a syntax transformation, it still requires
that you write function-call expressions when using a function with multiple
arguments in the pipeline.
### Conversion
The `conv` module is the simplest: it provides two traits, `Conv` and `TryConv`,
which are sibling traits to `Into<T>` and `TryInto<T>`. Their methods,
`Conv::conv::<T>` and `TryConv::try_conv::<T>`, call the corresponding
trait implementation, and allow you to use `.into()`/`.try_into()` in
non-terminal method calls of an expression.
```rust
let bytes = "hello".into().into_bytes();
```
does not compile, because Rust cannot decide the type of `"hello".into()`.
Instead of rewriting the expression to use an intermediate `let` binding, you
can write it as
```rust
let bytes = "hello".conv::<String>().into_bytes();
```
## Full Functionality
The `Tap` and `Pipe` traits both provide a large number of methods, which use
different parts of the Rust languages facilities for well-typed value access.
Rather than repeat the API documentation here, you should view the module items
in the [documentation][docs].
As a summary, these traits provide methods that, upon receipt of a value,
- apply no transformation
- apply an `AsRef` or `AsMut` implementation
- apply a `Borrow` or `BorrowMut` implementation
- apply the `Deref` or `DerefMut` implementation
before executing their effect argument.
In addition, each `Tap` method `.tap_x` has a sibling method `.tap_x_dbg` that
performs the same work, but only in debug builds; in release builds, the method
call is stripped. This allows you to leave debugging taps in your source code,
without affecting your projects performance in true usage.
Lastly, the `tap` module also has traits `TapOptional` and `TapFallible` which
run taps on the variants of `Option` and `Result` enums, respectively, and do
nothing when the variant does not match the method name. `TapOptional::tap_some`
has no effect when called on a `None`, etc.
<!-- Badges -->
[crate]: https://crates.io/crates/tap "Crate Link"
[crate_img]: https://img.shields.io/crates/v/tap.svg?logo=rust "Crate Page"
[docs]: https://docs.rs/tap "Documentation"
[docs_img]: https://docs.rs/tap/badge.svg "Documentation Display"
[downloads_img]: https://img.shields.io/crates/dv/tap.svg?logo=rust "Crate Downloads"
[license_file]: https://github.com/myrrlyn/tap/blob/master/LICENSE.txt "License File"
[license_img]: https://img.shields.io/crates/l/tap.svg "License Display"
[loc]: https://github.com/myrrlyn/tap "Repository"
[loc_img]: https://tokei.rs/b1/github/myrrlyn/tap?category=code "Repository Size"
+87
View File
@@ -0,0 +1,87 @@
/*! # Method-Directed Type Conversion
The `std::convert` module provides traits for converting values from one type to
another. The first of these, [`From<T>`], provides an associated function
[`from(orig: T) -> Self`]. This function can only be called in prefix-position,
as it does not have a `self` receiver. The second, [`Into<T>`], provides a
method [`into(self) -> T`] which *can* be called in suffix-position; due to
intractable problems in the type solver, this method cannot have any *further*
method calls attached to it. It must be bound directly into a `let` or function
call.
The [`TryFrom<T>`] and [`TryInto<T>`] traits have the same properties, but
permit failure.
This module provides traits that place the conversion type parameter in the
method, rather than in the trait, so that users can write `.conv::<T>()` to
convert the preceding expression into `T`, without causing any failures in the
type solver. These traits are blanket-implemented on all types that have an
`Into<T>` implementation, which covers both the blanket implementation of `Into`
for types with `From`, and manual implementations of `Into`.
[`From<T>`]: https://doc.rust-lang.org/std/convert/trait.From.html
[`Into<T>`]: https://doc.rust-lang.org/std/convert/trait.Into.html
[`TryFrom<T>`]: https://doc.rust-lang.org/std/convert/trait.TryFrom.html
[`TryInto<T>`]: https://doc.rust-lang.org/std/convert/trait.TryInto.html
[`from(orig: T) -> Self`]: https://doc.rust-lang.org/std/convert/trait.From.html#tymethod.from
[`into(self) -> T`]: https://doc.rust-lang.org/std/convert/trait.Into.html#tymethod.into
!*/
use core::convert::TryInto;
/// Wraps `Into::<T>::into` as a method that can be placed in pipelines.
pub trait Conv
where
Self: Sized,
{
/// Converts `self` into `T` using `Into<T>`.
///
/// # Examples
///
/// ```rust
/// use tap::conv::Conv;
///
/// let len = "Saluton, mondo!"
/// .conv::<String>()
/// .len();
/// ```
#[inline(always)]
fn conv<T>(self) -> T
where
Self: Into<T>,
T: Sized,
{
Into::<T>::into(self)
}
}
impl<T> Conv for T {}
/// Wraps `TryInto::<T>::try_into` as a method that can be placed in pipelines.
pub trait TryConv
where
Self: Sized,
{
/// Attempts to convert `self` into `T` using `TryInto<T>`.
///
/// # Examples
///
/// ```rust
/// use tap::conv::TryConv;
///
/// let len = "Saluton, mondo!"
/// .try_conv::<String>()
/// .unwrap()
/// .len();
/// ```
#[inline(always)]
fn try_conv<T>(self) -> Result<T, Self::Error>
where
Self: TryInto<T>,
T: Sized,
{
TryInto::<T>::try_into(self)
}
}
impl<T> TryConv for T {}
+147
View File
@@ -0,0 +1,147 @@
/*! # `tap` Syntactical Plumb-Lines
Rust permits functions that take a `self` receiver to be written in “dot-call”
suffix position, rather than the more traditional prefix-position function call
syntax. These functions are restricted to `impl [Trait for] Type` blocks, and
functions anywhere else cannot take advantage of this syntax.
This crate provides universally-implemented extension traits that permit smooth
suffix-position calls for a handful of common operations: transparent inspection
or modification (tapping), transformation (piping), and type conversion.
## Tapping
The [`tap`] module provides the [`Tap`], [`TapOptional`], and [`TapFallible`]
traits. Each of these traits provides methods that take and return a value, and
expose it as a borrow to an effect function. They look like this:
```rust
use tap::prelude::*;
# struct Tmp;
# fn make_value() -> Tmp { Tmp }
# impl Tmp { fn process_value(self) {} }
# macro_rules! log { ($msg:literal, $val:ident) => {{}}; }
let end = make_value()
.tap(|v| log!("Produced value: {:?}", v))
.process_value();
```
These methods are `self -> Self`, and return the value they received without
any transformation. This enables them to be placed anywhere in a larger
expression witohut changing its shape, or causing any semantic changes to the
code. The effect function receives a borrow of the tapped value, optionally run
through the `Borrow`, `AsRef`, or `Deref` view conversions, for the duration of
its execution.
The effect function cannot return a value, as the tap is incapable of handling
it.
## Piping
The [`pipe`] module provides the [`Pipe`] trait. This trait provides methods
that take and transform a value, returning the result of the transformation.
They look like this:
```rust
use tap::prelude::*;
struct One;
fn start() -> One { One }
struct Two;
fn end(_: One) -> Two { Two }
let val: Two = start().pipe(end);
// without pipes, this would be written as
let _: Two = end(start());
```
These methods are `self -> Other`, and return the value produced by the effect
function. As the methods are always available in suffix position, they can take
as arguments methods that are *not* eligible for dot-call syntax and still place
them as expression suffices. The effect function receives the piped value,
optionally run through the `Borrow`, `AsRef`, or `Deref` view conversions, as
its input, and its output is returned from the pipe.
For `.pipe()`, the input value is *moved* into the pipe and the effect function,
so the effect function *cannot* return a value whose lifetime depends on the
input value. The other pipe methods all borrow the input value, and may return a
value whose lifetime is tied to it.
## Converting
The [`conv`] module provides the [`Conv`] and [`TryConv`] traits. These provide
methods that accept a type parameter on the method name, and forward to the
appropriate `Into` or `TryInto` trait implementation when called. The difference
between `Conv` and `Into` is that `Conv` is declared as `Conv::conv::<T>`, while
`Into` is declared as `Into::<T>::into`. The location of the destination type
parameter makes `.into()` unusable as a non-terminal method call of an
expression, while `.conv::<T>()` can be used as a method call anywhere.
```rust,compile_fail
let upper = "hello, world"
.into()
.tap_mut(|s| s.make_ascii_uppercase());
```
The above snippet is illegal, because the Rust type solver cannot determine the
type of the sub-expression `"hello, world".into()`, and it will not attempt to
search all available `impl Into<X> for str` implementations to find an `X` which
has a
`fn tap_mut({self, &self, &mut self, Box<Self>, Rc<Self>, Arc<Self>}, _) -> Y`
declared, either as an inherent method or in a trait implemented by `X`, to
resolve the expression.
Instead, you can write it as
```rust
use tap::prelude::*;
let upper = "hello, world"
.conv::<String>()
.tap_mut(|s| s.make_ascii_uppercase());
```
The trait implementation is
```rust
pub trait Conv: Sized {
fn conv<T: Sized>(self) -> T
where Self: Into<T> {
self.into()
}
}
```
Each monomorphization of `.conv::<T>()` expands to the appropriate `Into<T>`
implementation, and does nothing else.
[`Conv`]: conv/trait.Conv.html
[`Pipe`]: pipe/trait.Pipe.html
[`Tap`]: tap/trait.Tap.html
[`TapFallible`]: tap/trait.TapFallible.html
[`TapOptional`]: tap/trait.TapOptional.html
[`TryConv`]: conv/trait.TryConv.html
[`conv`]: conv/index.html
[`pipe`]: pipe/index.html
[`tap`]: tap/index.html
!*/
#![no_std]
#![cfg_attr(debug_assertions, warn(missing_docs))]
#![cfg_attr(not(debug_assertions), deny(missing_docs))]
pub mod conv;
pub mod pipe;
pub mod tap;
/// Reëxports all traits in one place, for easy import.
pub mod prelude {
#[doc(inline)]
pub use crate::{conv::*, pipe::*, tap::*};
}
// also make traits available at crate root
#[doc(inline)]
pub use prelude::*;
+234
View File
@@ -0,0 +1,234 @@
/*! # Universal Suffix Calls
This module provides a single trait, `Pipe`, which provides a number of methods
useful for placing functions in suffix position. The most common method, `pipe`,
forwards a value `T` into any function `T -> R`, returning `R`. The other
methods all apply some form of borrowing to the value before passing the borrow
into the piped function. These are of less value, but provided to maintain a
similar API to the `tap` modules methods, and for convenience in the event that
you do have a use for them.
This module is as much of a [UFCS] method syntax that can be provided as a
library, rather than in the language grammar.
[UFCS]: https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax
!*/
use core::{
borrow::{Borrow, BorrowMut},
ops::{Deref, DerefMut},
};
/** Provides universal suffix-position call syntax for any function.
This trait provides methods that allow any closure or free function to be placed
as a suffix-position call, by writing them as
```rust
# use tap::pipe::Pipe;
# let receiver = 5;
fn not_a_method(x: i32) -> u8 { x as u8 }
receiver.pipe(not_a_method);
```
Piping into functions that take more than one argument still requires writing a
closure with ordinary function-call syntax. This is after all only a library,
not a syntax transformation:
```rust
use tap::pipe::Pipe;
fn add(x: i32, y: i32) -> i32 { x + y }
let out = 5.pipe(|x| add(x, 10));
assert_eq!(out, 15);
```
Like tapping, piping is useful for cases where you want to write a sequence of
processing steps without introducing many intermediate bindings, and your steps
contain functions which are not eligible for dot-call syntax.
The main difference between piping and tapping is that tapping always returns
the value that was passed into the tap, while piping forwards the value into the
effect function, and returns the output of evaluating the effect function with
the value. Piping is a transformation, not merely an inspection or modification.
**/
pub trait Pipe {
/// Pipes by value. This is generally the method you want to use.
///
/// # Examples
///
/// ```rust
/// use tap::pipe::Pipe;
///
/// fn triple(x: i32) -> i64 {
/// x as i64 * 3
/// }
///
/// assert_eq!(
/// 10.pipe(triple),
/// 30,
/// );
/// ```
#[inline(always)]
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where
Self: Sized,
R: Sized,
{
func(self)
}
/// Borrows `self` and passes that borrow into the pipe function.
///
/// # Examples
///
/// ```rust
/// use tap::pipe::Pipe;
///
/// fn fold(v: &Vec<i32>) -> i32 {
/// v.iter().copied().sum()
/// }
/// let vec = vec![1, 2, 3, 4, 5];
/// let sum = vec.pipe_ref(fold);
/// assert_eq!(sum, 15);
/// assert_eq!(vec.len(), 5);
/// ```
#[inline(always)]
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where
R: 'a + Sized,
{
func(self)
}
/// Mutably borrows `self` and passes that borrow into the pipe function.
///
/// # Examples
///
/// ```rust
/// use tap::pipe::Pipe;
///
/// let mut vec = vec![false, true];
/// let last = vec
/// .pipe_ref_mut(Vec::pop)
/// .pipe(Option::unwrap);
/// assert!(last);
/// ```
///
/// Both of these functions are eligible for method-call syntax, and should
/// not be piped. Writing out non-trivial examples for these is a lot of
/// boilerplate.
#[inline(always)]
fn pipe_ref_mut<'a, R>(
&'a mut self,
func: impl FnOnce(&'a mut Self) -> R,
) -> R
where
R: 'a + Sized,
{
func(self)
}
/// Borrows `self`, then passes `self.borrow()` into the pipe function.
///
/// # Examples
///
/// ```rust
/// use std::borrow::Cow;
/// use tap::pipe::Pipe;
///
/// let len = Cow::<'static, str>::from("hello, world")
/// .pipe_borrow(str::len);
/// assert_eq!(len, 12);
/// ```
#[inline(always)]
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where
Self: Borrow<B>,
B: 'a + ?Sized,
R: 'a + Sized,
{
func(Borrow::<B>::borrow(self))
}
/// Mutably borrows `self`, then passes `self.borrow_mut()` into the pipe
/// function.
///
/// ```rust
/// use tap::pipe::Pipe;
///
/// let mut txt = "hello, world".to_string();
/// let ptr = txt
/// .pipe_borrow_mut(str::as_mut_ptr);
/// ```
///
/// This is a very contrived example, but the `BorrowMut` trait has almost
/// no implementors in the standard library, and of the implementations
/// available, there are almost no methods that fit this API.
#[inline(always)]
fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
where
Self: BorrowMut<B>,
B: 'a + ?Sized,
R: 'a + Sized,
{
func(BorrowMut::<B>::borrow_mut(self))
}
/// Borrows `self`, then passes `self.as_ref()` into the pipe function.
#[inline(always)]
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where
Self: AsRef<U>,
U: 'a + ?Sized,
R: 'a + Sized,
{
func(AsRef::<U>::as_ref(self))
}
/// Mutably borrows `self`, then passes `self.as_mut()` into the pipe
/// function.
#[inline(always)]
fn pipe_as_mut<'a, U, R>(
&'a mut self,
func: impl FnOnce(&'a mut U) -> R,
) -> R
where
Self: AsMut<U>,
U: 'a + ?Sized,
R: 'a + Sized,
{
func(AsMut::<U>::as_mut(self))
}
/// Borrows `self`, then passes `self.deref()` into the pipe function.
#[inline(always)]
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where
Self: Deref<Target = T>,
T: 'a + ?Sized,
R: 'a + Sized,
{
func(Deref::deref(self))
}
/// Mutably borrows `self`, then passes `self.deref_mut()` into the pipe
/// function.
#[inline(always)]
fn pipe_deref_mut<'a, T, R>(
&'a mut self,
func: impl FnOnce(&'a mut T) -> R,
) -> R
where
Self: DerefMut + Deref<Target = T>,
T: 'a + ?Sized,
R: 'a + Sized,
{
func(DerefMut::deref_mut(self))
}
}
impl<T> Pipe for T where T: ?Sized {}
+587
View File
@@ -0,0 +1,587 @@
/*! # Point-Free Inspection
The standard library does not provide a way to view or modify an expression
without binding it to a name. This module provides extension methods that take
and return a value, allowing it to be temporarily bound without creating a new
`let`-statement in the enclosing scope.
The two main uses of these methods are to temporarily attach debugging
tracepoints to an expression without modifying its surrounding code, or to
temporarily mutate an otherwise-immutable object.
For convenience, methods are available that will modify the *view* of the tapped
object that is passed to the effect function, by using the values
`Borrow`/`BorrowMut`, `AsRef`/`AsMut`, or `Index`/`IndexMut` trait
implementations. For example, the `Vec` collection has no `fn sort` method: this
is actually implemented on slices, to which `Vec` dereferences.
```rust
use tap::tap::*;
# fn make_vec() -> Vec<i32> { vec![] }
// taps take ordinary closures, which can use deref coercion
make_vec().tap_mut(|v| v.sort());
// `Vec<T>` implements `BorrowMut<[T]>`,
make_vec().tap_borrow_mut(<[_]>::sort);
// and `AsMut<[T]>`,
make_vec().tap_ref_mut(<[_]>::sort);
// and `DerefMut<Target = [T]>,
make_vec().tap_deref_mut(<[_]>::sort);
// but has no inherent method `sort`.
// make_vec().tap_mut(Vec::sort);
```
!*/
use core::{
borrow::{Borrow, BorrowMut},
ops::{Deref, DerefMut},
};
/** Point-free value inspection and modification.
This trait provides methods that permit viewing the value of an expression
without requiring a new `let` binding or any other alterations to the original
code other than insertion of the `.tap()` call.
The methods in this trait do not perform any view conversions on the value they
receive; it is borrowed and passed directly to the effect argument.
**/
pub trait Tap
where
Self: Sized,
{
/// Immutable access to a value.
///
/// This function permits a value to be viewed by some inspecting function
/// without affecting the overall shape of the expression that contains this
/// method call. It is useful for attaching assertions or logging points
/// into a multi-part expression.
///
/// # Examples
///
/// Here we use `.tap()` to attach logging tracepoints to each stage of a
/// value-processing pipeline.
///
/// ```rust
/// use tap::tap::Tap;
/// # struct Tmp;
/// # impl Tmp { fn process_value(self) -> Self { self } }
/// # fn make_value() -> Tmp { Tmp }
/// # macro_rules! log { ($msg:literal, $x:ident) => {{}}; }
///
/// let end = make_value()
/// // this line has no effect on the rest of the code
/// .tap(|v| log!("The produced value was: {}", v))
/// .process_value();
/// ```
#[inline(always)]
fn tap(self, func: impl FnOnce(&Self)) -> Self {
func(&self);
self
}
/// Mutable access to a value.
///
/// This function permits a value to be modified by some function without
/// affecting the overall shape of the expression that contains this method
/// call. It is useful for attaching modifier functions that have an
/// `&mut Self -> ()` signature to an expression, without requiring an
/// explicit `let mut` binding.
///
/// # Examples
///
/// Here we use `.tap_mut()` to sort an array without requring multiple
/// bindings.
///
/// ```rust
/// use tap::tap::Tap;
///
/// let sorted = [1i32, 5, 2, 4, 3]
/// .tap_mut(|arr| arr.sort());
/// assert_eq!(sorted, [1, 2, 3, 4, 5]);
/// ```
///
/// Without tapping, this would be written as
///
/// ```rust
/// let mut received = [1, 5, 2, 4, 3];
/// received.sort();
/// let sorted = received;
/// ```
///
/// The mutable tap is a convenient alternative when the expression to
/// produce the collection is more complex, for example, an iterator
/// pipeline collected into a vector.
#[inline(always)]
fn tap_mut(mut self, func: impl FnOnce(&mut Self)) -> Self {
func(&mut self);
self
}
/// Immutable access to the `Borrow<B>` of a value.
///
/// This function is identcal to [`Tap::tap`], except that the effect
/// function recevies an `&B` produced by `Borrow::<B>::borrow`, rather than
/// an `&Self`.
///
/// [`Tap::tap`]: trait.Tap.html#method.tap
#[inline(always)]
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where
Self: Borrow<B>,
B: ?Sized,
{
func(Borrow::<B>::borrow(&self));
self
}
/// Mutable access to the `BorrowMut<B>` of a value.
///
/// This function is identical to [`Tap::tap_mut`], except that the effect
/// function receives an `&mut B` produced by `BorrowMut::<B>::borrow_mut`,
/// rather than an `&mut Self`.
///
/// [`Tap::tap_mut`]: trait.Tap.html#method.tap_mut
#[inline(always)]
fn tap_borrow_mut<B>(mut self, func: impl FnOnce(&mut B)) -> Self
where
Self: BorrowMut<B>,
B: ?Sized,
{
func(BorrowMut::<B>::borrow_mut(&mut self));
self
}
/// Immutable access to the `AsRef<R>` view of a value.
///
/// This function is identical to [`Tap::tap`], except that the effect
/// function receives an `&R` produced by `AsRef::<R>::as_ref`, rather than
/// an `&Self`.
///
/// [`Tap::tap`]: trait.Tap.html#method.tap
#[inline(always)]
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where
Self: AsRef<R>,
R: ?Sized,
{
func(AsRef::<R>::as_ref(&self));
self
}
/// Mutable access to the `AsMut<R>` view of a value.
///
/// This function is identical to [`Tap::tap_mut`], except that the effect
/// function receives an `&mut R` produced by `AsMut::<R>::as_mut`, rather
/// than an `&mut Self`.
///
/// [`Tap::tap_mut`]: trait.Tap.html#method.tap_mut
#[inline(always)]
fn tap_ref_mut<R>(mut self, func: impl FnOnce(&mut R)) -> Self
where
Self: AsMut<R>,
R: ?Sized,
{
func(AsMut::<R>::as_mut(&mut self));
self
}
/// Immutable access to the `Deref::Target` of a value.
///
/// This function is identical to [`Tap::tap`], except that the effect
/// function receives an `&Self::Target` produced by `Deref::deref`, rather
/// than an `&Self`.
///
/// [`Tap::tap`]: trait.Tap.html#method.tap
#[inline(always)]
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where
Self: Deref<Target = T>,
T: ?Sized,
{
func(Deref::deref(&self));
self
}
/// Mutable access to the `Deref::Target` of a value.
///
/// This function is identical to [`Tap::tap_mut`], except that the effect
/// function receives an `&mut Self::Target` produced by
/// `DerefMut::deref_mut`, rather than an `&mut Self`.
///
/// [`Tap::tap_mut`]: trait.Tap.html#method.tap_mut
#[inline(always)]
fn tap_deref_mut<T>(mut self, func: impl FnOnce(&mut T)) -> Self
where
Self: DerefMut + Deref<Target = T>,
T: ?Sized,
{
func(DerefMut::deref_mut(&mut self));
self
}
// debug-build-only copies of the above methods
/// Calls `.tap()` only in debug builds, and is erased in release builds.
#[inline(always)]
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self {
if cfg!(debug_assertions) {
func(&self);
}
self
}
/// Calls `.tap_mut()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_mut_dbg(mut self, func: impl FnOnce(&mut Self)) -> Self {
if cfg!(debug_assertions) {
func(&mut self);
}
self
}
/// Calls `.tap_borrow()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where
Self: Borrow<B>,
B: ?Sized,
{
if cfg!(debug_assertions) {
func(Borrow::<B>::borrow(&self));
}
self
}
/// Calls `.tap_borrow_mut()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_borrow_mut_dbg<B>(mut self, func: impl FnOnce(&mut B)) -> Self
where
Self: BorrowMut<B>,
B: ?Sized,
{
if cfg!(debug_assertions) {
func(BorrowMut::<B>::borrow_mut(&mut self));
}
self
}
/// Calls `.tap_ref()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where
Self: AsRef<R>,
R: ?Sized,
{
if cfg!(debug_assertions) {
func(AsRef::<R>::as_ref(&self));
}
self
}
/// Calls `.tap_ref_mut()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_ref_mut_dbg<R>(mut self, func: impl FnOnce(&mut R)) -> Self
where
Self: AsMut<R>,
R: ?Sized,
{
if cfg!(debug_assertions) {
func(AsMut::<R>::as_mut(&mut self));
}
self
}
/// Calls `.tap_deref()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where
Self: Deref<Target = T>,
T: ?Sized,
{
if cfg!(debug_assertions) {
func(Deref::deref(&self));
}
self
}
/// Calls `.tap_deref_mut()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_deref_mut_dbg<T>(mut self, func: impl FnOnce(&mut T)) -> Self
where
Self: DerefMut + Deref<Target = T>,
T: ?Sized,
{
if cfg!(debug_assertions) {
func(DerefMut::deref_mut(&mut self));
}
self
}
}
impl<T> Tap for T where T: Sized {}
/** Optional tapping, conditional on the optional presence of a value.
This trait is intended for use on types that express the concept of “optional
presence”, primarily the [`Option`] monad. It provides taps that inspect the
container to determine if the effect function should execute or not.
> Note: This trait is a specialization of [`TapFallible`], and exists because
> the [`std::ops::Try`] trait is still unstable. When `Try` stabilizes, this
> trait can be removed, and `TapFallible` blanket-applied to all `Try`
> implementors.
[`Option`]: https://doc.rust-lang.org/std/option/enum.Option.html
[`TapFallible`]: trait.TapFallible.html
[`std::ops::Try`]: https://doc.rust-lang.org/std/ops/trait.Try.html
**/
pub trait TapOptional
where
Self: Sized,
{
/// The interior type that the container may or may not carry.
type Val: ?Sized;
/// Immutabily accesses an interior value only when it is present.
///
/// This function is identical to [`Tap::tap`], except that it is required
/// to check the implementing container for value presence before running.
/// Implementors must not run the effect function if the container is marked
/// as being empty.
///
/// [`Tap::tap`]: trait.Tap.html#method.tap
fn tap_some(self, func: impl FnOnce(&Self::Val)) -> Self;
/// Mutably accesses an interor value only when it is present.
///
/// This function is identical to [`Tap::tap_mut`], except that it is
/// required to check the implementing container for value presence before
/// running. Implementors must not run the effect function if the container
/// is marked as being empty.
///
/// [`Tap::tap_mut`]: trait.Tap.html#method.tap_mut
fn tap_some_mut(self, func: impl FnOnce(&mut Self::Val)) -> Self;
/// Runs an effect function when the container is empty.
///
/// This function is identical to [`Tap::tap`], except that it is required
/// to check the implementing container for value absence before running.
/// Implementors must not run the effect function if the container is marked
/// as being non-empty.
///
/// [`Tap::tap`]: trait.Tap.html#method.tap
fn tap_none(self, func: impl FnOnce()) -> Self;
/// Calls `.tap_some()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_some_dbg(self, func: impl FnOnce(&Self::Val)) -> Self {
if cfg!(debug_assertions) {
self.tap_some(func)
} else {
self
}
}
/// Calls `.tap_some_mut()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_some_mut_dbg(self, func: impl FnOnce(&mut Self::Val)) -> Self {
if cfg!(debug_assertions) {
self.tap_some_mut(func)
} else {
self
}
}
/// Calls `.tap_none()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_none_dbg(self, func: impl FnOnce()) -> Self {
if cfg!(debug_assertions) {
self.tap_none(func)
} else {
self
}
}
}
impl<T> TapOptional for Option<T> {
type Val = T;
#[inline(always)]
fn tap_some(self, func: impl FnOnce(&T)) -> Self {
if let Some(ref val) = self {
func(val);
}
self
}
#[inline(always)]
fn tap_some_mut(mut self, func: impl FnOnce(&mut T)) -> Self {
if let Some(ref mut val) = self {
func(val);
}
self
}
#[inline(always)]
fn tap_none(self, func: impl FnOnce()) -> Self {
if self.is_none() {
func();
}
self
}
}
/** Fallible tapping, conditional on the optional success of an expression.
This trait is intended for use on types that express the concept of “fallible
presence”, primarily the [`Result`] monad. It provides taps that inspect the
container to determine if the effect function should execute or not.
> Note: This trait would ideally be implemented as a blanket over all
> [`std::ops::Try`] implementors. When `Try` stabilizes, this crate can be
> updated to do so.
[`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html
[`std::ops::Try`]: https://doc.rust-lang.org/std/ops/trait.Try.html
**/
pub trait TapFallible
where
Self: Sized,
{
/// The interior type used to indicate a successful construction.
type Ok: ?Sized;
/// The interior type used to indicate a failed construction.
type Err: ?Sized;
/// Immutably accesses an interior success value.
///
/// This function is identical to [`Tap::tap`], except that it is required
/// to check the implementing container for value success before running.
/// Implementors must not run the effect function if the container is marked
/// as being a failure.
///
/// [`Tap::tap`]: trait.Tap.html#method.tap
fn tap_ok(self, func: impl FnOnce(&Self::Ok)) -> Self;
/// Mutably accesses an interior success value.
///
/// This function is identical to [`Tap::tap_mut`], except that it is
/// required to check the implementing container for value success before
/// running. Implementors must not run the effect function if the container
/// is marked as being a failure.
///
/// [`Tap::tap_mut`]: trait.Tap.html#method.tap_mut
fn tap_ok_mut(self, func: impl FnOnce(&mut Self::Ok)) -> Self;
/// Immutably accesses an interior failure value.
///
/// This function is identical to [`Tap::tap`], except that it is required
/// to check the implementing container for value failure before running.
/// Implementors must not run the effect function if the container is marked
/// as being a success.
///
/// [`Tap::tap`]: trait.Tap.html#method.tap
fn tap_err(self, func: impl FnOnce(&Self::Err)) -> Self;
/// Mutably accesses an interior failure value.
///
/// This function is identical to [`Tap::tap_mut`], except that it is
/// required to check the implementing container for value failure before
/// running. Implementors must not run the effect function if the container
/// is marked as being a success.
///
/// [`Tap::tap_mut`]: trait.Tap.html#method.tap_mut
fn tap_err_mut(self, func: impl FnOnce(&mut Self::Err)) -> Self;
/// Calls `.tap_ok()` only in debug builds, and is erased in release builds.
#[inline(always)]
fn tap_ok_dbg(self, func: impl FnOnce(&Self::Ok)) -> Self {
if cfg!(debug_assertions) {
self.tap_ok(func)
} else {
self
}
}
/// Calls `.tap_ok_mut()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_ok_mut_dbg(self, func: impl FnOnce(&mut Self::Ok)) -> Self {
if cfg!(debug_assertions) {
self.tap_ok_mut(func)
} else {
self
}
}
/// Calls `.tap_err()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_err_dbg(self, func: impl FnOnce(&Self::Err)) -> Self {
if cfg!(debug_assertions) {
self.tap_err(func)
} else {
self
}
}
/// Calls `.tap_err_mut()` only in debug builds, and is erased in release
/// builds.
#[inline(always)]
fn tap_err_mut_dbg(self, func: impl FnOnce(&mut Self::Err)) -> Self {
if cfg!(debug_assertions) {
self.tap_err_mut(func)
} else {
self
}
}
}
impl<T, E> TapFallible for Result<T, E> {
type Ok = T;
type Err = E;
#[inline(always)]
fn tap_ok(self, func: impl FnOnce(&T)) -> Self {
if let Ok(ref val) = self {
func(val);
}
self
}
#[inline(always)]
fn tap_ok_mut(mut self, func: impl FnOnce(&mut T)) -> Self {
if let Ok(ref mut val) = self {
func(val);
}
self
}
#[inline(always)]
fn tap_err(self, func: impl FnOnce(&E)) -> Self {
if let Err(ref val) = self {
func(val);
}
self
}
#[inline(always)]
fn tap_err_mut(mut self, func: impl FnOnce(&mut E)) -> Self {
if let Err(ref mut val) = self {
func(val);
}
self
}
}