File: README.md

package info (click to toggle)
rust-wyz 0.5.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 168 kB
  • sloc: makefile: 4
file content (192 lines) | stat: -rw-r--r-- 6,789 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
<div align="center">

# `wyz` <!-- omit in toc -->

[![Crate][crate_img]][crate]
[![Documentation][docs_img]][docs]
[![License][license_img]][license_file]

[![Continuous Integration][travis_img]][travis]
[![Code Coverage][codecov_img]][codecov]
[![Crate Downloads][downloads_img]][crate]
[![Crate Size][loc_img]][loc]

</div>

I have developed a collection of utility and convenience Rust modules that are
useful to me, and may be useful to you also.

This crate is a collection of largely-independent small modules. I do not
currently offer features to disable modules independently of each other, but
their compilation cost is small enough to essentially not matter.

## Modules <!-- omit in toc -->

1. [`conv`](#conv)
1. [`exit`](#exit)
1. [`fmt`](#fmt)
1. [`pipe`](#pipe)
1. [`tap`](#tap)

## `conv`

This module provides a single trait, of the same name, with a single generic
method, also of the same name. This trait is a sibling to `Into`, but rather
than placing its type parameter in the trait (`Into::<T>::into`), `Conv` places
it in the method: `Conv::conv::<T>`.

By placing the type parameter in the method name, `.conv` can be called in
suffix position in expressions where the result type cannot be inferred and must
be explicitly stated.

```rust
use wyz::conv::Conv;

let digits = 0xabcd.conv::<String>().len();
```

This is a trivial example, but writing a code context where `.conv` makes sense
takes a lot more context than a `README` wants.

## `exit`

This is a macro that calls `std::process::exit`. It can return a status code,
and also print a message to `stderr`.

```rust
use wyz::exit::exit;

exit!();
exit!(2);
exit!(3, "This is a {} message", "failure");
```

The default call is `std::process::exit(1)`; a call may provide its own exit
code and, in addition, a set of arguments to pass directly to `eprintln!`. The
error message is not guaranteed to be emitted, as `stderr` may be closed at time
of `exit!`.

## `fmt`

Rust uses the `Debug` trait for automatic printing events in several parts of
the standard library. This module provides wrapper types which forward their
`Debug` implementation to a specified other formatting trait. It also implements
extension methods on all types that have format trait implementations to wrap
them in the corresponding shim type.

```rust
use wyz::fmt::FmtForward as _;

let val = 6;
let addr = &val as *const i32;
println!("{:?}", addr.fmt_pointer());
```

This snippet uses the `Debug` format template, but will print the `Pointer`
implementation of `*const i32`.

This is useful for fitting your values into an error-handling framework that
only uses `Debug`, such as the `fn main() -> Result` program layout.

## `pipe`

Rust does not permit universal suffix-position function call syntax. That is,
you can *always* call a function with `Scope::name(arguments…)`, but only *some*
functions can be called as `first_arg.name(other_args…)`. Working in “data
pipelines” – flows where the return value of one function is passed directly as
the first argument to the next – is common enough in our field that it has a
name in languages that support it: *method chaining*. A *method* is a function
that the language considers to be treated specially in regards to only its
first argument, and permits changing the abstract token series
`function arg1 args…` into the series `arg1 function args…`.

Rust restricts that order transformation to only functions defined in scope for
some type (either `impl Type` or `impl Trait for Type` blocks) and that take a
first argument named `self`.

Other languages permit calling *any* function, regardless of its definition site
in source code, in this manner, as long as the first argument is of the correct
type for the first parameter of the function.

In languages like F♯ and Elixir, this uses the call operator `|>` rather than
the C++ family’s `.` caller. This operator is pronounced `pipe`.

Rust does not have a pipe operator. The dot-caller is restricted to only the
implementation blocks listed above, and this is not likely to change because it
also performs limited type transformation operations in order to find a name
that fits.

This module provides a `Pipe` trait whose method, `pipe`, passes its `self`
first argument as the argument to its second-order function:

```rust
use wyz::pipe::Pipe;

let final = 5
  .pipe(|a| a + 10)
  .pipe(|a| a * 2);

assert_eq!(final, 30);
```

Without language-level syntax support, piping into closures always requires
restating the argument, and functions cannot curry the argument they receive
from `pipe` and arguments from the environment in the manner that dot-called
methods can.

```rust
fn fma(a: i32, b: i32, c: i32) -> i32 {
  (a * b) + c
}
5.pipe(|a| fma(a, 2, 3));

let fma_2_3 = |a| fma(a, 2, 3);
5.pipe(fma_2_3);
```

These are the only ways to express `5 |> fma(2, 3)`.

Sorry.

Bug the language team.

## `tap`

Tapping is a cousin operation to piping, except that rather than pass the
receiver by *value* into some function, and return the result of that function,
it passes a *borrow* of a value into a function, and then returns the original
value.

It is useful for inserting an operation into an expression without changing the
overall state (type or value) of the expression.

```rust
use wyz::tap::Tap;

let result = complex_value()
  .tap(|v| log::info!("First stage: {}", v))
  .transform(other, args)
  .tap(|v| log::info!("Second stage: {}", v));
```

The tap calls have no effect on the expression into which they are placed,
except to induce side effects somewhere else in the system. Commenting out the
two `.tap` calls does not change anything about `complex_value()`, `.transform`,
or `result`; it only removes the log statements.

This enables easily inserting or removing inspection points in an expression
without otherwise altering it.

[codecov]: https://codecov.io/gh/myrrlyn/wyz "Code Coverage"
[codecov_img]: https://img.shields.io/codecov/c/github/myrrlyn/wyz.svg?logo=codecov "Code Coverage Display"
[crate]: https://crates.io/crates/wyz "Crate Link"
[crate_img]: https://img.shields.io/crates/v/wyz.svg?logo=rust "Crate Page"
[docs]: https://docs.rs/wyz "Documentation"
[docs_img]: https://docs.rs/wyz/badge.svg "Documentation Display"
[downloads_img]: https://img.shields.io/crates/dv/wyz.svg?logo=rust "Crate Downloads"
[license_file]: https://github.com/myrrlyn/wyz/blob/master/LICENSE.txt "License File"
[license_img]: https://img.shields.io/crates/l/wyz.svg "License Display"
[loc]: https://github.com/myrrlyn/wyz "Repository"
[loc_img]: https://tokei.rs/b1/github/myrrlyn/wyz?category=code "Repository Size"
[travis]: https://travis-ci.org/myrrlyn/wyz "Travis CI"
[travis_img]: https://img.shields.io/travis/myrrlyn/wyz.svg?logo=travis "Travis CI Display"