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
//! # Extruct
//!
//! Extruct is a proc-macro library that provides tools for listing named struct fields and
//! implementing conversion from a larger struct containing fields with same names.
//!
//! ## Description
//! Extruct is primarily driven by the following use-case.
//! <br>
//! It is customary for REST API to return a whole bunch of properties of an object
//! in a JSON response. Oftentimes, you as a user of this API are only interested in
//! a few of those and don't really need others.
//! To facilitate this, REST services typically support passing the list of properties
//! the client is interested in through the `fields` query parameter.
//! See examples of this pattern [here](https://yandex.com/dev/disk-api/doc/en/reference/all-files)
//! and [here](https://restcountries.com/#endpoints-filter-response).
//! <br>
//! Extruct offers two simple-to-use procedural macros that can be useful in implementing
//! wrappers around REST API that can retrieve only specific properties from the backend.
//!
//! The first macro is a derive macro [`Fields`](macro@Fields). It applies to structs with named
//! fields and implements the `Fields` trait that returns a list of fields' names as string
//! literals.
//!
//! The second macro is an attribute macro [`extruct_from`].
//! It can be used when there exists a "superstruct" that contains all possible fields.
//! In this case, when defining your own struct which contains only a subset of all
//! those fields you can use [`extruct_from`] which will implement the
//! [`std::convert::From`](https://doc.rust-lang.org/std/convert/trait.From.html) trait
//! converting an instance of the superstruct into an instance of your struct by converting
//! all fields from the original struct into fields with the same name of the substruct.
//!
//! Besides being handy for turning "full" objects into "partial", this ensures that all
//! fields are named the same and their types are compatible. To prove this, [`extruct_from`]
//! implements the [`ExtructedFrom`] trait which extends [`std::convert::From`](https://doc.rust-lang.org/std/convert/trait.From.html)
//! and verifies that the superstruct is not only convertible into substruct but also that
//! all the respective fields have same names.
//!
//! ## Examples
//! ```rust
//! # use extruct::ExtructedFrom;
//! # use extruct::Fields;
//! # use extruct::extruct_from;
//! #[derive(Fields)]
//! struct SuperStruct {
//! one_field: String,
//! another_field: u32,
//! and_one_more: char,
//! }
//!
//! #[derive(Fields)]
//! #[extruct_from(SuperStruct)]
//! struct SubStruct {
//! and_one_more: String,
//! }
//!
//! fn convert_preserving_names<T, S>(sup: S) -> T
//! where
//! T: ExtructedFrom<S>,
//! {
//! sup.into()
//! }
//!
//! assert_eq!(SuperStruct::fields(), ["one_field", "another_field", "and_one_more"]);
//! assert_eq!(SubStruct::fields(), ["and_one_more"]);
//!
//! let sup = SuperStruct {
//! one_field: "str".to_owned(),
//! another_field: 1135,
//! and_one_more: 'x',
//! };
//!
//! let sub: SubStruct = convert_preserving_names(sup);
//! assert_eq!(sub.and_one_more, "x".to_owned());
//! ```
//!
//! # Notes
//! The [`Fields`](macro@Fields) derive macro can be applied to named structs and unit structs,
//! but unnamed structs can only be annotated with `#[derive(Fields)]` if they are empty.
//!
//! The [`extruct_from`] attribute macro can only be applied to non-generic named structs
//! and can only reference a concrete (non-generic) struct as a superstruct.
//! This limitation holds because the macro does not have visibility into the definition
//! of the superstruct and therefore would not be able to specify trait bounds for generic
//! fields when implementing the [`std::convert::From`](https://doc.rust-lang.org/std/convert/trait.From.html) trait.
//! If you want to use a specific instantiation of a generic struct as a superstruct, you
//! can use a type alias like so:
//! ```rust
//! # use extruct::Fields;
//! # use extruct::extruct_from;
//! // A generic struct cannot be referenced by the extruct_from() attribute macro...
//! struct GenericStruct<T, S> {
//! one_field: T,
//! another_field: u32,
//! and_one_more: S,
//! }
//!
//! // ... but a non-generic type alias can be referenced by the extruct_from()
//! // attribute macro just fine
//! type ConcreteStruct = GenericStruct<String, char>;
//!
//! #[extruct_from(ConcreteStruct)]
//! struct SubStruct {
//! and_one_more: String,
//! }
//!
//! let sup = ConcreteStruct {
//! one_field: "str".to_owned(),
//! another_field: 1135,
//! and_one_more: 'x',
//! };
//!
//! let sub: SubStruct = sup.into();
//! assert_eq!(sub.and_one_more, "x".to_owned());
//! ```
pub use ExtructedFrom;
pub use Fields;
pub use extruct_from;
pub use Fields;