| 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 | |