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
/*
Copyright 2024 Benjamin Richcreek
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
//! # The Struct-inator 3000!
//!
//! A procedural macro library for allowing conversion from iterators to user-defined
//! [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html)s.
//!
//! This library does so by implementing a procedural macro, [`macro@iter_convertable`] for [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html) definitions that automatically implements [`structinator_traits::SpecifyCreatableStruct`]
//! for the defined [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html).
//!
//! For more information about how [`macro@iter_convertable`] implements [`SpecifyCreatableStruct`](structinator_traits::SpecifyCreatableStruct), visit the macro's [documentation](macro@iter_convertable)
//!
//! For more information about how an implementation of [`SpecifyCreatableStruct`](structinator_traits::SpecifyCreatableStruct) allows for easy conversion between [`Iterator`]s and [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html)s, visit the documentation of [`structinator_traits`]
use syn;
use quote;
use TokenStream;
///Attribute for structs that can be built from an iterator.
/// This attribute must be attached to a [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html) definition
///
/// # Argument
///
///The argument passed to the attribute must be a type, and each unique type of the fields in the target [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html) must implement
///[`From`] or [`TryFrom`] the passed type
///
/// # Effects
/// This attribute implements the trait [`structinator_traits::SpecifyCreatableStruct`] with [`InnerIteratorType`](structinator_traits::SpecifyCreatableStruct::InnerIteratorType) set to
/// the argument passed to this attribute.
///
/// The generated function, [`create_struct`](structinator_traits::SpecifyCreatableStruct::create_struct), will be implemented using a [`HashMap<String,InnerIteratorType>`](std::collections::HashMap), which will store the first `N` values from the iterator, where `N` is the number of fields in the [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html) this attribute is attached to,
/// and then be assign the values in that [`HashMap`](std::collections::HashMap) to corresponding fields in the [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html), as determined by a stringification of the field's name.
///
/// The passed value will then be unwrapped from the [`InnerIteratorType`](structinator_traits::SpecifyCreatableStruct::InnerIteratorType) to the type of the struct, [`panic`](https://doc.rust-lang.org/1.58.1/core/macro.panic.html)king if the conversion fails.
///
/// In other words, if the field definition looks like this:
/// ```no_run
/// value_name: u16,
/// ```
/// Then the corresponding field in the struct literal generated by [`create_struct`](structinator_traits::SpecifyCreatableStruct::create_struct) would look something like this (with error messages removed)
/// ```no_run
/// value_name = <u16 as TryFrom>::try_from(hash_map.remove("value_name").unwrap()).unwrap(),
/// ```
/// # Panics
/// This attribute will cause a [`panic`](https://doc.rust-lang.org/1.58.1/core/macro.panic.html) if attached to anything other than a [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html) definition
///
/// This attribute will implement [`SpecifyCreatableStruct`](structinator_traits::SpecifyCreatableStruct) in a manner that assumes the [`InnerIteratorType`](structinator_traits::SpecifyCreatableStruct::InnerIteratorType)
/// implements [`TryFrom`] for each unique type used in the fields of the target [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html)
///
/// If [`InnerIteratorType`](structinator_traits::SpecifyCreatableStruct::InnerIteratorType)'s type does not implement [`TryFrom`], or the conversion fails, this function will [`panic`](https://doc.rust-lang.org/1.58.1/core/macro.panic.html).
/// The recomended way to make sure [`TryFrom`] is always implemented, minimizing panics to only when the conversion itself fails, is to create an [`enum`](https://doc.rust-lang.org/1.58.1/std/keyword.enum.html) specifically for this purpose, with unique variants for each unique type used by the fields of the target [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html),
/// and add the attribute [`unique_try_froms()`](https://docs.rs/enum_unwrapper/0.1.2/enum_unwrapper/attr.unique_try_froms.html) to said [`enum`](https://doc.rust-lang.org/1.58.1/std/keyword.enum.html).
/// See [`enum_unwrapper`](https://docs.rs/enum_unwrapper/0.1.2/enum_unwrapper/index.html)'s documentation for detailed
/// instructions on how to do so.
///
/// The function will also [`panic`](https://doc.rust-lang.org/1.58.1/core/macro.panic.html) if the [`Iterator`] argument yields [`NamedField`](structinator_traits::NamedField)s with identical [`name`](structinator_traits::NamedField::name) values before providing enough values to fill the target [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html).
///
/// # Errors
/// The generated implementation returns an [`Err`] containing a [`&'static str`](str) if the supplied [`Iterator`] returns [`None`] before yielding enough values to fill the target [`struct`](https://doc.rust-lang.org/1.58.1/std/keyword.struct.html).
/// # More Info
/// See [`SpecifyCreatableStruct`](structinator_traits::SpecifyCreatableStruct) documentation for more information & examples.
///