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
//! # Occult
//!
//! Teach your code magic.
//!
//! Occult gives you the ability to define your own async "magic handler" functions. A
//! magic handler is a function that can take any number of arguments and return a future,
//! so long as those arguments can be extracted from a single input value.
//!
//! Magic handlers are popular in several parts of the rust community, such as the axum
//! and actix-web crates, and the bevy crate. They let you split your application into
//! two layers: what it is, and what it does. However, the implementation of these magic
//! handlers can be tough to understand, and so they tend to be tucked away inside their
//! respective crates.
//!
//! Occult aims to make it easy to define your own magic handlers, so you can use them
//! yourself for your own programs. It's a more general implementation of the pattern, so
//! you can pop it into your project and make a magic handler for whatever you want without
//! leveraging those other crates.
//!
//! ## Dependency injection & clarity
//!
//! Magic handlers are a kind of dependency injection pattern. Your handlers know what they
//! need to work, and your extractors know how to get it from a core type. This makes it easy
//! to model out logic but it makes it hard to trace cause and effect. It's a tradeoff, but
//! the ergonomics of magic handlers tend to broaden the amount of people who can work on code.
//!
//! It's up to you whether or not you feel as though magic handlers serve you and your team.
//! If you have a ton of people doing work on different layers, it might be ideal. Otherwise,
//! it might add too much extra time to debugging work!
//!
use Future;
/// # Extractor
///
/// Define the extractor trait for any type you want to use as an argument to your magic handler.
/// Extractors have several IO types: the input type, the state type, and the error type. These
/// need to line up with the types of the handler you're using.
///
/// ## Input Type
///
/// The input type is the type that your extractor will take as input. This is the type that
/// your handler will take as input, and the type that your extractor will extract from. Usually
/// this is a core concern of your application, and ultimately will pass through every handler
/// and extractor at some point.
///
/// ## State Type
///
/// The state type is the type that your extractor will take as context. This is a "hole" in the
/// magic handler pattern that allows you to keep it extensible to unknown consumer systems. In
/// other words, you can usually model out your whole system without knowing how it interacts with
/// an outside system, and then later use the state type to fill in that context gap.
///
/// State has to be uniform in the same way the input type does, because of how the extract and
/// handler traits are defined.
///
/// ## Error Type
///
/// The error type is the type that your extractor will return if it fails to extract. This is
/// another "hole" similar to the state type, because extractors might never fail. However,
/// because some might, the possibility of failure has to be considered for every extractor.
///
/// Like the state and input types, the error type has to somehow connect to the error type of
/// the handler. This isn't a one to one link in the case of the error type: anything that can
/// understand extractor errors and how to cast from them using `From`/`Into` can be used.
///