| 1 | #![cfg_attr (feature = "nightly" , feature(proc_macro_diagnostic))] |
| 2 | |
| 3 | extern crate proc_macro; |
| 4 | |
| 5 | use darling::*; |
| 6 | use darling::util::Flag; |
| 7 | use proc_macro::TokenStream; |
| 8 | use proc_macro2::{Span, TokenStream as SynTokenStream}; |
| 9 | use std::result::Result; |
| 10 | use syn::*; |
| 11 | use syn::spanned::Spanned; |
| 12 | use quote::*; |
| 13 | |
| 14 | #[cfg (feature = "nightly" )] |
| 15 | fn error(span: Span, data: &str) -> SynTokenStream { |
| 16 | span.unstable().error(data).emit(); |
| 17 | SynTokenStream::new() |
| 18 | } |
| 19 | |
| 20 | #[cfg (not(feature = "nightly" ))] |
| 21 | fn error(_: Span, data: &str) -> SynTokenStream { |
| 22 | quote! { compile_error!(#data); } |
| 23 | } |
| 24 | |
| 25 | #[derive (Debug, Clone, FromMeta)] |
| 26 | struct ExternalDelegate { |
| 27 | /// The type to generate a delegate for. |
| 28 | ty: Path, |
| 29 | /// The field to delegate the methods to. |
| 30 | #[darling(default)] |
| 31 | field: Option<Ident>, |
| 32 | /// The method to delegate the methods to. |
| 33 | #[darling(default)] |
| 34 | method: Option<Ident>, |
| 35 | } |
| 36 | |
| 37 | #[derive (Debug, Clone, FromDeriveInput)] |
| 38 | #[darling(attributes(setters), supports(struct_named))] |
| 39 | struct ContainerAttrs { |
| 40 | ident: Ident, |
| 41 | generics: Generics, |
| 42 | |
| 43 | /// Use the core library rather than the std library. |
| 44 | #[darling(default)] |
| 45 | no_std: Flag, |
| 46 | |
| 47 | /// Whether to accept any field that converts via `Into` by default. |
| 48 | #[darling(default)] |
| 49 | into: bool, |
| 50 | |
| 51 | /// Whether to strip `Option<T>` into `T` in the parameters for the setter method by default. |
| 52 | #[darling(default)] |
| 53 | strip_option: bool, |
| 54 | |
| 55 | /// Whether to borrow or take ownership of `self` in the setter method by default. |
| 56 | #[darling(default)] |
| 57 | borrow_self: bool, |
| 58 | |
| 59 | /// Whether to generate a method that sets a boolean by default. |
| 60 | #[darling(default)] |
| 61 | bool: bool, |
| 62 | |
| 63 | /// Whether to generate setters for this struct's fields by default. If set to false, |
| 64 | /// `generate_public` and `generate_private` are ignored. |
| 65 | #[darling(default)] |
| 66 | generate: Option<bool>, |
| 67 | |
| 68 | /// Whether to generate setters for this struct's public fields by default. |
| 69 | #[darling(default)] |
| 70 | generate_public: Option<bool>, |
| 71 | |
| 72 | /// Whether to generate setters for this struct's private fields by default. |
| 73 | #[darling(default)] |
| 74 | generate_private: Option<bool>, |
| 75 | |
| 76 | /// A prefix for the generated setter methods. |
| 77 | #[darling(default)] |
| 78 | prefix: Option<String>, |
| 79 | |
| 80 | /// Other types to generate delegates to this type for. Note that this does not support |
| 81 | /// generics. |
| 82 | #[darling(multiple)] |
| 83 | generate_delegates: Vec<ExternalDelegate>, |
| 84 | } |
| 85 | |
| 86 | #[derive (Debug, Clone, FromField)] |
| 87 | #[darling(attributes(setters), forward_attrs(doc))] |
| 88 | struct FieldAttrs { |
| 89 | attrs: Vec<Attribute>, |
| 90 | |
| 91 | /// The name of the generated setter method. |
| 92 | #[darling(default)] |
| 93 | rename: Option<Ident>, |
| 94 | |
| 95 | /// Whether to accept any field that converts via `Into` to this field's type. |
| 96 | #[darling(default)] |
| 97 | into: Option<bool>, |
| 98 | |
| 99 | /// Whether to strip `Option<T>` into `T` in the parameters for the setter method. |
| 100 | #[darling(default)] |
| 101 | strip_option: Option<bool>, |
| 102 | |
| 103 | /// Whether to borrow or take ownership of `self` for the setter method. |
| 104 | #[darling(default)] |
| 105 | borrow_self: Option<bool>, |
| 106 | |
| 107 | /// Whether to generate a method that sets a boolean. |
| 108 | #[darling(default)] |
| 109 | bool: Option<bool>, |
| 110 | |
| 111 | /// Whether to generate a setter for this field regardless of global settings. |
| 112 | #[darling(default)] |
| 113 | generate: bool, |
| 114 | |
| 115 | /// Whether to skip this field regardless of global settings. Overwrites `generate`. |
| 116 | #[darling(default)] |
| 117 | skip: bool, |
| 118 | } |
| 119 | |
| 120 | struct ContainerDef { |
| 121 | name: Ident, |
| 122 | ty: Type, |
| 123 | std: Ident, |
| 124 | generics: Generics, |
| 125 | |
| 126 | prefix: String, |
| 127 | uses_into: bool, |
| 128 | strip_option: bool, |
| 129 | borrow_self: bool, |
| 130 | bool: bool, |
| 131 | generate_public: bool, |
| 132 | generate_private: bool, |
| 133 | |
| 134 | generate_delegates: Vec<ExternalDelegate>, |
| 135 | } |
| 136 | |
| 137 | struct FieldDef { |
| 138 | field_name: Ident, |
| 139 | field_ty: Type, |
| 140 | field_doc: SynTokenStream, |
| 141 | setter_name: Ident, |
| 142 | uses_into: bool, |
| 143 | strip_option: bool, |
| 144 | borrow_self: bool, |
| 145 | bool: bool, |
| 146 | } |
| 147 | |
| 148 | fn init_container_def(input: &DeriveInput) -> Result<ContainerDef, SynTokenStream> { |
| 149 | let darling_attrs: ContainerAttrs = match FromDeriveInput::from_derive_input(input) { |
| 150 | Ok(v) => v, |
| 151 | Err(e) => return Err(e.write_errors()), |
| 152 | }; |
| 153 | |
| 154 | let ident = &darling_attrs.ident; |
| 155 | let (_, generics_ty, _) = darling_attrs.generics.split_for_impl(); |
| 156 | let ty = quote! { #ident #generics_ty }; |
| 157 | |
| 158 | let generate = darling_attrs.generate.unwrap_or(true); |
| 159 | Ok(ContainerDef { |
| 160 | name: darling_attrs.ident, |
| 161 | ty: parse2(ty).expect("Internal error: failed to parse internally generated type." ), |
| 162 | std: if darling_attrs.no_std.is_present() { |
| 163 | Ident::new("core" , Span::call_site()) |
| 164 | } else { |
| 165 | Ident::new("std" , Span::call_site()) |
| 166 | }, |
| 167 | borrow_self: darling_attrs.borrow_self, |
| 168 | generics: darling_attrs.generics, |
| 169 | prefix: darling_attrs.prefix.unwrap_or(String::new()), |
| 170 | uses_into: darling_attrs.into, |
| 171 | strip_option: darling_attrs.strip_option, |
| 172 | bool: darling_attrs.bool, |
| 173 | generate_public: generate && darling_attrs.generate_public.unwrap_or(true), |
| 174 | generate_private: generate && darling_attrs.generate_private.unwrap_or(true), |
| 175 | generate_delegates: darling_attrs.generate_delegates, |
| 176 | }) |
| 177 | } |
| 178 | |
| 179 | fn init_field_def( |
| 180 | container: &ContainerDef, field: &Field, |
| 181 | ) -> Result<Option<FieldDef>, SynTokenStream> { |
| 182 | // Decode the various attribute options. |
| 183 | let darling_attrs: FieldAttrs = match FromField::from_field(field) { |
| 184 | Ok(v) => v, |
| 185 | Err(e) => return Err(e.write_errors()), |
| 186 | }; |
| 187 | |
| 188 | // Check whether this field should generate a setter. |
| 189 | if darling_attrs.skip { return Ok(None) } |
| 190 | let generates = match field.vis { |
| 191 | Visibility::Public(_) => container.generate_public, |
| 192 | _ => container.generate_private, |
| 193 | }; |
| 194 | if !(darling_attrs.generate || generates) { return Ok(None) } |
| 195 | |
| 196 | // Returns a definition for this field. |
| 197 | let ident = match &field.ident { |
| 198 | Some(i) => i.clone(), |
| 199 | None => panic!("Internal error: init_field_def on wrong item." ), |
| 200 | }; |
| 201 | Ok(Some(FieldDef { |
| 202 | field_name: ident.clone(), |
| 203 | field_ty: field.ty.clone(), |
| 204 | field_doc: if let Visibility::Public(_) = field.vis { |
| 205 | let doc_str = |
| 206 | format!("Sets the [` {}`](#structfield. {}) field of this struct." , ident, ident); |
| 207 | quote! { #[doc = #doc_str] } |
| 208 | } else { |
| 209 | let attrs = darling_attrs.attrs; |
| 210 | quote! { #( #attrs )* } |
| 211 | }, |
| 212 | setter_name: darling_attrs.rename.unwrap_or_else(|| |
| 213 | Ident::new(&format!(" {}{}" , container.prefix, ident), ident.span()) |
| 214 | ), |
| 215 | uses_into: darling_attrs.into.unwrap_or(container.uses_into), |
| 216 | strip_option: darling_attrs.strip_option.unwrap_or(container.strip_option), |
| 217 | borrow_self: darling_attrs.borrow_self.unwrap_or(container.borrow_self), |
| 218 | bool: darling_attrs.bool.unwrap_or(container.bool), |
| 219 | })) |
| 220 | } |
| 221 | |
| 222 | |
| 223 | fn generate_setter_method( |
| 224 | container: &ContainerDef, def: FieldDef, delegate_toks: &Option<SynTokenStream>, |
| 225 | ) -> Result<SynTokenStream, SynTokenStream> { |
| 226 | let FieldDef { |
| 227 | field_name, mut field_ty, field_doc, setter_name, .. |
| 228 | } = def; |
| 229 | let std = &container.std; |
| 230 | |
| 231 | // Strips `Option<T>` into `T` if the `strip_option` property is set. |
| 232 | let mut stripped_option = false; |
| 233 | if def.strip_option { |
| 234 | if let Type::Path(path) = &field_ty { |
| 235 | let segment = path.path.segments.last().unwrap(); |
| 236 | if segment.ident.to_string() == "Option" { |
| 237 | if let PathArguments::AngleBracketed(path) = &segment.arguments { |
| 238 | if let GenericArgument::Type(tp) = path.args.first().unwrap() { |
| 239 | field_ty = tp.clone(); |
| 240 | stripped_option = true; |
| 241 | } |
| 242 | } |
| 243 | } |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | // The type the setter accepts. |
| 248 | let value_ty = if def.uses_into { |
| 249 | quote! { impl ::#std::convert::Into<#field_ty> } |
| 250 | } else { |
| 251 | quote! { #field_ty } |
| 252 | }; |
| 253 | |
| 254 | // The expression actually stored into the field. |
| 255 | let mut expr = quote! { value }; |
| 256 | if def.uses_into { expr = quote! { #expr.into() }; } |
| 257 | if def.bool { expr = quote! { true }; } |
| 258 | if stripped_option { expr = quote! { Some(#expr) }; } |
| 259 | |
| 260 | // Handle the parameters when bool is enabled. |
| 261 | let params = if def.bool { |
| 262 | SynTokenStream::new() |
| 263 | } else { |
| 264 | quote! { value: #value_ty } |
| 265 | }; |
| 266 | |
| 267 | // Generates the setter method itself. |
| 268 | let container_name = &container.name; |
| 269 | if let Some(delegate) = delegate_toks { |
| 270 | let _self = if def.borrow_self { |
| 271 | quote! { &mut self } |
| 272 | } else { |
| 273 | quote! { mut self } |
| 274 | }; |
| 275 | |
| 276 | let return_self = if def.borrow_self { |
| 277 | quote! { &mut Self } |
| 278 | } else { |
| 279 | quote! { Self } |
| 280 | }; |
| 281 | |
| 282 | Ok(quote! { |
| 283 | #field_doc |
| 284 | pub fn #setter_name (#_self, #params) -> #return_self { |
| 285 | self.#delegate.#field_name = #expr; |
| 286 | self |
| 287 | } |
| 288 | }) |
| 289 | } else { |
| 290 | if def.borrow_self { |
| 291 | Ok(quote! { |
| 292 | #field_doc |
| 293 | pub fn #setter_name (&mut self, #params) -> &mut Self { |
| 294 | self.#field_name = #expr; |
| 295 | self |
| 296 | } |
| 297 | }) |
| 298 | } else { |
| 299 | Ok(quote! { |
| 300 | #field_doc |
| 301 | pub fn #setter_name (self, #params) -> Self { |
| 302 | #container_name { #field_name: #expr, ..self } |
| 303 | } |
| 304 | }) |
| 305 | } |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | fn generate_setters_for( |
| 310 | input: &DeriveInput, data: &DataStruct, generics: &Generics, |
| 311 | ty: SynTokenStream, delegate_toks: Option<SynTokenStream>, |
| 312 | ) -> Result<SynTokenStream, SynTokenStream> { |
| 313 | let container_def: ContainerDef = init_container_def(&input)?; |
| 314 | let mut toks: TokenStream = SynTokenStream::new(); |
| 315 | for field: &Field in &data.fields { |
| 316 | if let Some(field_def: FieldDef) = init_field_def(&container_def, field)? { |
| 317 | let method: TokenStream = generate_setter_method(&container_def, field_def, &delegate_toks)?; |
| 318 | toks.extend(iter:method); |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | let (generics_bound: ImplGenerics<'_>, _, generics_where: Option<&WhereClause>) = generics.split_for_impl(); |
| 323 | Ok(quote! { |
| 324 | impl #generics_bound #ty #generics_where { |
| 325 | #toks |
| 326 | } |
| 327 | }) |
| 328 | |
| 329 | } |
| 330 | |
| 331 | fn generate_setters(input: &DeriveInput, data: &DataStruct) -> Result<TokenStream, TokenStream> { |
| 332 | let container_def = init_container_def(&input)?; |
| 333 | let mut toks = SynTokenStream::new(); |
| 334 | let container_ty = &container_def.ty; |
| 335 | toks.extend(generate_setters_for( |
| 336 | input, data, &container_def.generics, quote! { #container_ty }, None, |
| 337 | )); |
| 338 | for delegate in container_def.generate_delegates { |
| 339 | let delegate_ty = delegate.ty; |
| 340 | toks.extend(generate_setters_for( |
| 341 | input, data, &Generics::default(), quote! { #delegate_ty }, |
| 342 | if delegate.field.is_some() && delegate.method.is_some() { |
| 343 | return Err(error(input.span(), |
| 344 | "Cannot set both `method` and `field` on a delegate." ).into()); |
| 345 | } else if let Some(field) = &delegate.field { |
| 346 | Some(quote! { #field }) |
| 347 | } else if let Some(method) = &delegate.method { |
| 348 | Some(quote! { #method() }) |
| 349 | } else { |
| 350 | return Err(error(input.span(), |
| 351 | "Must set either `method` or `field` on a delegate." ).into()); |
| 352 | } |
| 353 | )); |
| 354 | } |
| 355 | Ok(toks.into()) |
| 356 | } |
| 357 | |
| 358 | #[proc_macro_derive (Setters, attributes(setters))] |
| 359 | pub fn derive_setters(input: TokenStream) -> TokenStream { |
| 360 | let input: DeriveInput = parse_macro_input!(input); |
| 361 | if let Data::Struct(data: &DataStruct) = &input.data { |
| 362 | match generate_setters(&input, data) { |
| 363 | Ok(toks: TokenStream) => toks, |
| 364 | Err(toks: TokenStream) => toks, |
| 365 | } |
| 366 | } else { |
| 367 | error(input.span(), data:"`#[derive(Setters)] may only be used on structs." ).into() |
| 368 | } |
| 369 | } |
| 370 | |