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
//! Enables turning a value that has `Serialize` into a `Deserializer`
//!
//! Effectively this enables extracting a struct that implements `Deserialize` from a struct that
//! implements `Serialize`.
//!
//! # Usage
//! ## TL;DR
//! ```
//! #[derive(serde_derive::Serialize)]
//! struct Source<'a> {
//! a: &'a str,
//! b: u32,
//! }
//! #[derive(Debug, PartialEq, serde_derive::Deserialize)]
//! struct Extract {
//! b: u32,
//! }
//! assert_eq!(
//! Extract { b: 3 },
//! serde_extract::extract(&Source { a: "hello", b: 3 }).unwrap(),
//! );
//! ```
//!
//! ## More realistic example
//!
//! Let's say we're in a scenario where we want to implement an SDK where results are paginated, we only need to send
//! the original query once, but we need to re-send `page_size` if it was provided in the original query.
//! Since the code that manages pagination has no knowledge of the underlying struct, and because adding a `page_size`
//! argument to our `make_paginated_request` function would be very un-ergonomic because (let's say) it would be very
//! rarely used and it's nicer to specify it in the same struct as the rest of the query parameters, this is a good
//! use-case for this crate.
//!
//! ```
//! // This will be our original query
//! #[derive(serde_derive::Serialize)]
//! struct SomeSpecificRequest {
//! field_a: &'static str,
//! page_size: usize,
//! }
//!
//! // Let's say make_request is our generic function that makes a call to the server
//! make_paginated_request(&SomeSpecificRequest {
//! field_a: "hello!",
//! page_size: 2,
//! })
//! .expect("Failed to make request");
//!
//! fn make_paginated_request<S: serde::Serialize>(
//! serializable: &S,
//! ) -> Result<(), Box<dyn std::error::Error>> {
//! #[derive(serde_derive::Deserialize)]
//! struct MaybePageSize {
//! page_size: Option<usize>,
//! }
//! // We will reuse the page size for the subsequent paginated requests if it was
//! // provided in the original query, so we need to extract it
//! let page_size_for_this_request =
//! serde_extract::extract::<MaybePageSize, _>(serializable)?.page_size;
//! // this works:
//! assert_eq!(page_size_for_this_request, Some(2));
//! // Make request...
//! Ok(())
//! }
//! ```
//!
//! # Limitations
//!
//! - Sequences are not supported for now (although support could theoritically be added, algorithmic complexity of
//! generated code would be O(n²) where n is the number of elements in the sequence because we would need to re-drive
//! the [`Serializer`] for each element called for by the [`Visitor`] through [`MapAccess`])
//! - For the same reason, deserializing into `map`s is currently unsupported. Specifically, currently we can only
//! extract struct fields if the fields names are hinted by [`deserialize_struct`](Deserializer::deserialize_struct).
//! (This enables driving the [`Serializer`] only as many times as there are fields to extract. In practice if both
//! sides are regular structs, the optimizer probably turns that into zero-cost extraction. In theory again, support
//! for deserializing into maps could be added with O(n²) complexity where n is the number of input fields.)
use ;
pub use Error;
/// Extract a `T: DeserializeOwned` from `S: Serialize`
///
/// See [crate-level documentation](crate) for examples
/// Our serializer that can be built from a type that implements `Serialize`
///
/// Note that while it implements `Deserializer<'de>` for any lifetime `'de`, in practice it will never provide
/// you with borrowed values (because these don't exist on [`Serializer`]).
/// This means that attempting to deserialize types that don't implement [`DeserializeOwned`] from this will most likely
/// fail.