1 | //! Individual implementation for all traits. |
2 | |
3 | mod clone; |
4 | mod common_ord; |
5 | mod copy; |
6 | mod debug; |
7 | mod default; |
8 | mod eq; |
9 | mod hash; |
10 | mod ord; |
11 | mod partial_eq; |
12 | mod partial_ord; |
13 | #[cfg (feature = "zeroize" )] |
14 | mod zeroize; |
15 | #[cfg (feature = "zeroize" )] |
16 | mod zeroize_on_drop; |
17 | |
18 | use proc_macro2::{Span, TokenStream}; |
19 | use syn::{punctuated::Punctuated, spanned::Spanned, Meta, Path, Result, Token, TypeParamBound}; |
20 | |
21 | use crate::{Data, DeriveTrait, Error, Item, SplitGenerics}; |
22 | |
23 | /// Type implementing [`TraitImpl`] for every trait. |
24 | #[derive (Clone, Copy, Eq, PartialEq)] |
25 | #[cfg_attr (test, derive(Debug))] |
26 | pub enum Trait { |
27 | /// [`Clone`]. |
28 | Clone, |
29 | /// [`Copy`]. |
30 | Copy, |
31 | /// [`Debug`](std::fmt::Debug). |
32 | Debug, |
33 | /// [`Default`]. |
34 | Default, |
35 | /// [`Eq`]. |
36 | Eq, |
37 | /// [`Hash`](std::hash::Hash). |
38 | Hash, |
39 | /// [`Ord`]. |
40 | Ord, |
41 | /// [`PartialEq`]. |
42 | PartialEq, |
43 | /// [`PartialOrd`]. |
44 | PartialOrd, |
45 | /// [`Zeroize`](https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html). |
46 | #[cfg (feature = "zeroize" )] |
47 | Zeroize, |
48 | /// [`ZeroizeOnDrop`](https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html). |
49 | #[cfg (feature = "zeroize" )] |
50 | ZeroizeOnDrop, |
51 | } |
52 | |
53 | impl Trait { |
54 | /// Return dummy-struct for the internal implementation. |
55 | fn implementation(&self) -> &dyn TraitImpl { |
56 | match self { |
57 | Trait::Clone => &clone::Clone, |
58 | Trait::Copy => ©::Copy, |
59 | Trait::Debug => &debug::Debug, |
60 | Trait::Default => &default::Default, |
61 | Trait::Eq => &eq::Eq, |
62 | Trait::Hash => &hash::Hash, |
63 | Trait::Ord => &ord::Ord, |
64 | Trait::PartialEq => &partial_eq::PartialEq, |
65 | Trait::PartialOrd => &partial_ord::PartialOrd, |
66 | #[cfg (feature = "zeroize" )] |
67 | Trait::Zeroize => &zeroize::Zeroize, |
68 | #[cfg (feature = "zeroize" )] |
69 | Trait::ZeroizeOnDrop => &zeroize_on_drop::ZeroizeOnDrop, |
70 | } |
71 | } |
72 | |
73 | /// Create [`Trait`] from [`Path`]. |
74 | pub fn from_path(path: &Path) -> Result<Self> { |
75 | if let Some(ident) = path.get_ident() { |
76 | use Trait::*; |
77 | |
78 | match ident.to_string().as_str() { |
79 | "Clone" => Ok(Clone), |
80 | "Copy" => Ok(Copy), |
81 | "Debug" => Ok(Debug), |
82 | "Default" => Ok(Default), |
83 | "Eq" => Ok(Eq), |
84 | "Hash" => Ok(Hash), |
85 | "Ord" => Ok(Ord), |
86 | "PartialEq" => Ok(PartialEq), |
87 | "PartialOrd" => Ok(PartialOrd), |
88 | #[cfg (feature = "zeroize" )] |
89 | "Zeroize" => Ok(Zeroize), |
90 | #[cfg (feature = "zeroize" )] |
91 | "ZeroizeOnDrop" => Ok(ZeroizeOnDrop), |
92 | "crate" => Err(Error::crate_(path.span())), |
93 | _ => Err(Error::trait_(path.span())), |
94 | } |
95 | } else { |
96 | Err(Error::trait_(path.span())) |
97 | } |
98 | } |
99 | } |
100 | |
101 | impl TraitImpl for Trait { |
102 | fn as_str(&self) -> &'static str { |
103 | self.implementation().as_str() |
104 | } |
105 | |
106 | fn default_derive_trait(&self) -> DeriveTrait { |
107 | self.implementation().default_derive_trait() |
108 | } |
109 | |
110 | fn parse_derive_trait( |
111 | &self, |
112 | span: Span, |
113 | list: Punctuated<Meta, Token![,]>, |
114 | ) -> Result<DeriveTrait> { |
115 | self.implementation().parse_derive_trait(span, list) |
116 | } |
117 | |
118 | fn supports_union(&self) -> bool { |
119 | self.implementation().supports_union() |
120 | } |
121 | |
122 | fn additional_where_bounds(&self, data: &Item) -> Option<TypeParamBound> { |
123 | self.implementation().additional_where_bounds(data) |
124 | } |
125 | |
126 | fn additional_impl(&self, trait_: &DeriveTrait) -> Option<(Path, TokenStream)> { |
127 | self.implementation().additional_impl(trait_) |
128 | } |
129 | |
130 | fn impl_path(&self, trait_: &DeriveTrait) -> Path { |
131 | self.implementation().impl_path(trait_) |
132 | } |
133 | |
134 | fn build_signature( |
135 | &self, |
136 | any_bound: bool, |
137 | item: &Item, |
138 | generics: &SplitGenerics<'_>, |
139 | traits: &[DeriveTrait], |
140 | trait_: &DeriveTrait, |
141 | body: &TokenStream, |
142 | ) -> TokenStream { |
143 | self.implementation() |
144 | .build_signature(any_bound, item, generics, traits, trait_, body) |
145 | } |
146 | |
147 | fn build_body( |
148 | &self, |
149 | any_bound: bool, |
150 | traits: &[DeriveTrait], |
151 | trait_: &DeriveTrait, |
152 | data: &Data, |
153 | ) -> TokenStream { |
154 | self.implementation() |
155 | .build_body(any_bound, traits, trait_, data) |
156 | } |
157 | } |
158 | |
159 | /// Single trait implementation. Parses attributes and constructs `impl`s. |
160 | pub trait TraitImpl { |
161 | /// [`str`] representation of this [`Trait`]. |
162 | /// Used to compare against [`Ident`](struct@syn::Ident)s and create error |
163 | /// messages. |
164 | fn as_str(&self) -> &'static str; |
165 | |
166 | /// Associated [`DeriveTrait`]. |
167 | fn default_derive_trait(&self) -> DeriveTrait; |
168 | |
169 | /// Parse a `derive_where` trait with it's options. |
170 | fn parse_derive_trait( |
171 | &self, |
172 | span: Span, |
173 | _list: Punctuated<Meta, Token![,]>, |
174 | ) -> Result<DeriveTrait> { |
175 | Err(Error::options(span, self.as_str())) |
176 | } |
177 | |
178 | /// Returns `true` if [`Trait`] supports unions. |
179 | fn supports_union(&self) -> bool { |
180 | false |
181 | } |
182 | |
183 | /// Additional bounds to add to [`WhereClause`](syn::WhereClause). |
184 | fn additional_where_bounds(&self, _data: &Item) -> Option<TypeParamBound> { |
185 | None |
186 | } |
187 | |
188 | /// Additional implementation to add for this [`Trait`]. |
189 | fn additional_impl(&self, _trait_: &DeriveTrait) -> Option<(Path, TokenStream)> { |
190 | None |
191 | } |
192 | |
193 | /// Trait to implement. Only used for [`ZeroizeOnDrop`](https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html) |
194 | /// because it implements [`Drop`] and not itself. |
195 | fn impl_path(&self, trait_: &DeriveTrait) -> Path { |
196 | trait_.path() |
197 | } |
198 | |
199 | /// Build method signature for this [`Trait`]. |
200 | fn build_signature( |
201 | &self, |
202 | _any_bound: bool, |
203 | _item: &Item, |
204 | _generics: &SplitGenerics<'_>, |
205 | _traits: &[DeriveTrait], |
206 | _trait_: &DeriveTrait, |
207 | _body: &TokenStream, |
208 | ) -> TokenStream { |
209 | TokenStream::new() |
210 | } |
211 | |
212 | /// Build method body for this [`Trait`]. |
213 | fn build_body( |
214 | &self, |
215 | _any_bound: bool, |
216 | _traits: &[DeriveTrait], |
217 | _trait_: &DeriveTrait, |
218 | _data: &Data, |
219 | ) -> TokenStream { |
220 | TokenStream::new() |
221 | } |
222 | } |
223 | |