typesift-macros 0.1.1

Implementation detail of the typesift crate: the #[derive(TypeSift)] macro
Documentation
# TypeSift

A Rust derive macro that walks structs, enums, collections and maps to collect every value of a given type.

## Usage

```rust
use typesift::TypeSift;

#[derive(Debug, PartialEq, TypeSift)]
struct UserId(u64);

#[derive(TypeSift)]
struct Group {
    name: String,
    admin: UserId,
    members: Vec<UserId>,
}

let group = Group {
    name: "Core".to_string(),
    admin: UserId(7),
    members: vec![UserId(12), UserId(9)],
};

// Get references to all values of type `UserId` inside of `group`
let user_ids = group.sift::<UserId>();
assert_eq!(user_ids, [&UserId(7), &UserId(12), &UserId(9)]);
```

## Motivation

Big API responses tend to be graphs of DTOs that point at other resources by id.
Before responding you want those resources loaded.
Collecting the ids normally means a function that walks every field by hand, and that function may quietly go stale when a new field is added.

Typesift reduces the amount of code that needs to be written and eliminates this concern.


## Integration with third-party crates

If you don't own a type, the orphan rule stops it from implementing the trait.

### Feature flags

Support for types from some popular crates can be enabled with the corresponding crate feature: `bytes`, `chrono`, `enum-map`, `http`, `indexmap`, `rust_decimal`, `serde_json`, `smallvec`, `time`, `url`, `uuid`.

Example:
```toml
typesift = { version = "0.1", features = ["uuid"] }
```

### Typesift attributes

If the crate you're interested in is not supported, typesift offers you the following macro attributes to overcome the issue:

- `#[typesift(leaf)]` finds the field but doesn't look inside it. This is what you want for ids, timestamps and other opaque values.
- `#[typesift(skip)]` leaves it out of the search entirely. Also the escape hatch for `RefCell`, `Mutex` and friends, which can't lend out their contents for as long as the search needs them.
- `#[typesift(with = path)]` hands the field to a function of yours, which decides what the search sees and in what order.


## Limitations

Everything involved has to be `'static`, so the derive rejects types with lifetime parameters, though `&'static T` fields are fine.
Interior mutability isn't supported; skip those fields.


## Benchmarks

Run benchmarks with `just bench`.

| variant                       | time     | vs baseline  |
|-------------------------------|----------|--------------|
| `manual_collector` (baseline) | 3.82 µs  | -            |
| `typesift`                    | 5.48 µs  | 1.43x slower |
| `manual_iterator`             | 31.78 µs | 8.3x  slower |

- `manual_collector` walks the fields by hand and pushes into a `Vec`, which is about as fast as this
gets.
- `TypeSift` costs roughly 1.4x of that
- `manual_iterator` is the same walk written as a chain of `impl Iterator`s, which is what most people
reach for.


## License

MIT © [Serhii Potapov](https://www.greyblake.com)