1//! Individual implementation for all traits.
2
3mod clone;
4mod common_ord;
5mod copy;
6mod debug;
7mod default;
8mod eq;
9mod hash;
10mod ord;
11mod partial_eq;
12mod partial_ord;
13#[cfg(feature = "zeroize")]
14mod zeroize;
15#[cfg(feature = "zeroize")]
16mod zeroize_on_drop;
17
18use proc_macro2::{Span, TokenStream};
19use syn::{punctuated::Punctuated, spanned::Spanned, Meta, Path, Result, Token, TypeParamBound};
20
21use 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))]
26pub 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
53impl 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::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
101impl 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.
160pub 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