derive_builder_core-0.12.0/.cargo_vcs_info.json0000644000000001610000000000100151060ustar { "git": { "sha1": "5705f00f23e3bd77c453a1c0bbd3de34b572b049" }, "path_in_vcs": "derive_builder_core" }derive_builder_core-0.12.0/CHANGELOG.md000064400000000000000000000024721046102023000155160ustar 00000000000000# Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## 0.3.0 - 2018-10-22 - Updated all dependencies #138 ## 0.2.0 - 2017-12-16 ### Fixed - `unused_mut` lint (variable does not need to be mutable) #104 ## 0.1.7 - 2017-04-29 ### Fixed - for generic structs, apply the `T: Clone` type bound in builder impl instead of struct definition #91 - only emit the `T: Clone` type bound when it is actually needed, i.e. mutable/immutable pattern, but not owned pattern. ## 0.1.6 - 2017-04-26 ### Added - pre-build validation ## 0.1.5 - 2017-04-25 ### Added - derive traits on builder struct ## 0.1.4 - 2017-04-12 ### Added - try_setters ## 0.1.3 - 2017-04-11 ### Fixed - `setter(skip)` honors struct-inherited and explicit defaults #68 ## 0.1.2 - 2017-04-10 ### Added - Bindings to abstract over libstd/libcore ### Changed - Use `bindings: Bindings` instead of `no_std: bool` ### Fixed - support generic references in structs #55 - no_std support #63 ## 0.1.1 - 2017-04-08 ### Added - struct default ## 0.1 - 2017-03-25 ### Added - helper crate `derive_builder_core`: Allow `derive_builder` to use its own code generation technique. - helper structs implementing `quote::ToTokens`: Allow unit tests on code generation items. derive_builder_core-0.12.0/Cargo.toml0000644000000023340000000000100131100ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] name = "derive_builder_core" version = "0.12.0" authors = [ "Colin Kiegel ", "Pascal Hertleif ", "Jan-Erik Rediger ", "Ted Driggs ", ] description = "Internal helper library for the derive_builder crate." documentation = "https://docs.rs/derive_builder_core" readme = "README.md" license = "MIT/Apache-2.0" repository = "https://github.com/colin-kiegel/rust-derive-builder" [dependencies.darling] version = "0.14.0" [dependencies.proc-macro2] version = "1.0.37" [dependencies.quote] version = "1.0.18" [dependencies.syn] version = "1.0.91" features = [ "full", "extra-traits", ] [dev-dependencies.pretty_assertions] version = "0.6.1" [features] clippy = [] derive_builder_core-0.12.0/Cargo.toml.orig000064400000000000000000000013051046102023000165660ustar 00000000000000[package] name = "derive_builder_core" version = "0.12.0" authors = ["Colin Kiegel ", "Pascal Hertleif ", "Jan-Erik Rediger ", "Ted Driggs "] description = "Internal helper library for the derive_builder crate." repository = "https://github.com/colin-kiegel/rust-derive-builder" documentation = "https://docs.rs/derive_builder_core" license = "MIT/Apache-2.0" readme = "README.md" [features] clippy = [] [dependencies] darling = "0.14.0" proc-macro2 = "1.0.37" quote = "1.0.18" syn = { version = "1.0.91", features = ["full", "extra-traits"] } [dev-dependencies] pretty_assertions = "0.6.1" derive_builder_core-0.12.0/LICENSE-APACHE000064400000000000000000000261361046102023000156340ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. derive_builder_core-0.12.0/LICENSE-MIT000064400000000000000000000021131046102023000153310ustar 00000000000000The MIT License (MIT) Copyright (c) 2016 rust-derive-builder contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. derive_builder_core-0.12.0/README.md000064400000000000000000000042041046102023000151570ustar 00000000000000![Build](https://github.com/colin-kiegel/rust-derive-builder/workflows/Build/badge.svg?branch=master) [![Documentation](https://docs.rs/derive_builder_core/badge.svg)](https://docs.rs/derive_builder_core) [![Latest version](https://img.shields.io/crates/v/derive_builder_core.svg)](https://crates.io/crates/derive_builder_core) [![All downloads](https://img.shields.io/crates/d/derive_builder_core.svg)](https://crates.io/crates/derive_builder_core) [![Downloads of latest version](https://img.shields.io/crates/dv/derive_builder_core.svg)](https://crates.io/crates/derive_builder_core) # Crate [`derive_builder_core`] **Important Note**: * You are probably looking for the [`derive_builder`] crate, which wraps this crate and is much more ergonomic to use. * The API of this crate might **change frequently** in the near future. The [`derive_builder`] crate also provides a much more stable API. ## Purpose This is an internal helper library of [`derive_builder`]. Its purpose is to allow [`derive_builder`] to use its own code generation technique, if needed. [`derive_builder_core`] might also be used in crates that [`derive_builder`] depends on - to break a dependency cycle. If [`derive_builder`] does not itself depend on _your_ crate, then you should consider using [`derive_builder`] instead of [`derive_builder_core`]. [`derive_builder`]: https://crates.io/crates/derive_builder [`derive_builder_core`]: https://crates.io/crates/derive_builder_core ## Documentation Please refer to [docs.rs/derive_builder_core](https://docs.rs/derive_builder_core) for the documentation of all published versions. ## [Changelog](CHANGELOG.md) Yes, we keep a changelog. ## License Licensed under either of - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) - MIT license ([LICENSE-MIT](LICENSE-MIT) or ) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. derive_builder_core-0.12.0/src/block.rs000064400000000000000000000047141046102023000161350ustar 00000000000000use std::convert::TryFrom; use proc_macro2::TokenStream; use quote::ToTokens; use syn::{self, spanned::Spanned, Block, LitStr}; /// A wrapper for expressions/blocks which automatically adds the start and end /// braces. /// /// - **full access** to variables environment. /// - **full access** to control-flow of the environment via `return`, `?` etc. #[derive(Debug, Clone)] pub struct BlockContents(Block); impl BlockContents { pub fn is_empty(&self) -> bool { self.0.stmts.is_empty() } } impl ToTokens for BlockContents { fn to_tokens(&self, tokens: &mut TokenStream) { self.0.to_tokens(tokens) } } impl TryFrom<&'_ LitStr> for BlockContents { type Error = syn::Error; fn try_from(s: &LitStr) -> Result { let mut block_str = s.value(); block_str.insert(0, '{'); block_str.push('}'); LitStr::new(&block_str, s.span()).parse().map(Self) } } impl From for BlockContents { fn from(v: syn::Expr) -> Self { Self(Block { brace_token: syn::token::Brace(v.span()), stmts: vec![syn::Stmt::Expr(v)], }) } } impl darling::FromMeta for BlockContents { fn from_value(value: &syn::Lit) -> darling::Result { if let syn::Lit::Str(s) = value { let contents = BlockContents::try_from(s)?; if contents.is_empty() { Err(darling::Error::unknown_value("").with_span(s)) } else { Ok(contents) } } else { Err(darling::Error::unexpected_lit_type(value)) } } } #[cfg(test)] mod test { use std::convert::TryInto; use super::*; use proc_macro2::Span; fn parse(s: &str) -> Result { (&LitStr::new(s, Span::call_site())).try_into() } #[test] #[should_panic(expected = r#"lex error"#)] fn block_invalid_token_trees() { parse("let x = 2; { x+1").unwrap(); } #[test] fn block_delimited_token_tree() { let expr = parse("let x = 2; { x+1 }").unwrap(); assert_eq!( quote!(#expr).to_string(), quote!({ let x = 2; { x + 1 } }) .to_string() ); } #[test] fn block_single_token_tree() { let expr = parse("42").unwrap(); assert_eq!(quote!(#expr).to_string(), quote!({ 42 }).to_string()); } } derive_builder_core-0.12.0/src/build_method.rs000064400000000000000000000202311046102023000174720ustar 00000000000000use std::borrow::Cow; use doc_comment_from; use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, TokenStreamExt}; use syn; use syn::spanned::Spanned; use BuilderPattern; use Initializer; use DEFAULT_STRUCT_NAME; use crate::DefaultExpression; /// Initializer for the struct fields in the build method, implementing /// `quote::ToTokens`. /// /// # Examples /// /// Will expand to something like the following (depending on settings): /// /// ```rust,ignore /// # extern crate proc_macro2; /// # #[macro_use] /// # extern crate quote; /// # extern crate syn; /// # #[macro_use(default_build_method)] /// # extern crate derive_builder_core; /// # use derive_builder_core::{BuildMethod, BuilderPattern}; /// # fn main() { /// # let build_method = default_build_method!(); /// # /// # assert_eq!(quote!(#build_method).to_string(), quote!( /// pub fn build(&self) -> ::derive_builder::export::core::result::Result { /// Ok(Foo { /// foo: self.foo, /// }) /// } /// # ).to_string()); /// # } /// ``` #[derive(Debug)] pub struct BuildMethod<'a> { /// Path to the root of the derive_builder crate. pub crate_root: &'a syn::Path, /// Enables code generation for this build method. pub enabled: bool, /// Name of this build fn. pub ident: &'a syn::Ident, /// Visibility of the build method, e.g. `syn::Visibility::Public`. pub visibility: Cow<'a, syn::Visibility>, /// How the build method takes and returns `self` (e.g. mutably). pub pattern: BuilderPattern, /// Type of the target field. /// /// The corresonding builder field will be `Option`. pub target_ty: &'a syn::Ident, /// Type parameters and lifetimes attached to this builder struct. pub target_ty_generics: Option>, /// Type of error. pub error_ty: syn::Path, /// Field initializers for the target type. pub initializers: Vec, /// Doc-comment of the builder struct. pub doc_comment: Option, /// Default value for the whole struct. /// /// This will be in scope for all initializers as `__default`. pub default_struct: Option<&'a DefaultExpression>, /// Validation function with signature `&FooBuilder -> Result<(), String>` /// to call before the macro-provided struct buildout. pub validate_fn: Option<&'a syn::Path>, } impl<'a> ToTokens for BuildMethod<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let ident = &self.ident; let vis = &self.visibility; let target_ty = &self.target_ty; let target_ty_generics = &self.target_ty_generics; let initializers = &self.initializers; let self_param = match self.pattern { BuilderPattern::Owned => quote!(self), BuilderPattern::Mutable | BuilderPattern::Immutable => quote!(&self), }; let doc_comment = &self.doc_comment; let default_struct = self.default_struct.as_ref().map(|default_expr| { let default_expr = default_expr.with_crate_root(self.crate_root); let ident = syn::Ident::new(DEFAULT_STRUCT_NAME, Span::call_site()); quote!(let #ident: #target_ty #target_ty_generics = #default_expr;) }); let validate_fn = self .validate_fn .as_ref() .map(|vfn| quote_spanned!(vfn.span() => #vfn(&self)?;)); let error_ty = &self.error_ty; if self.enabled { let crate_root = &self.crate_root; tokens.append_all(quote!( #doc_comment #vis fn #ident(#self_param) -> #crate_root::export::core::result::Result<#target_ty #target_ty_generics, #error_ty> { #validate_fn #default_struct Ok(#target_ty { #(#initializers)* }) } )) } } } impl<'a> BuildMethod<'a> { /// Set a doc-comment for this item. pub fn doc_comment(&mut self, s: String) -> &mut Self { self.doc_comment = Some(doc_comment_from(s)); self } /// Populate the `BuildMethod` with appropriate initializers of the /// underlying struct. /// /// For each struct field this must be called with the appropriate /// initializer. pub fn push_initializer(&mut self, init: Initializer) -> &mut Self { self.initializers.push(quote!(#init)); self } } // pub struct BuildMethodError { // is_generated: bool, // ident: syn::Ident, // } /// Helper macro for unit tests. This is _only_ public in order to be accessible /// from doc-tests too. #[doc(hidden)] #[macro_export] macro_rules! default_build_method { () => { BuildMethod { // Deliberately don't use the default value here - make sure // that all test cases are passing crate_root through properly. crate_root: &parse_quote!(::db), enabled: true, ident: &syn::Ident::new("build", ::proc_macro2::Span::call_site()), visibility: ::std::borrow::Cow::Owned(syn::parse_quote!(pub)), pattern: BuilderPattern::Mutable, target_ty: &syn::Ident::new("Foo", ::proc_macro2::Span::call_site()), target_ty_generics: None, error_ty: syn::parse_quote!(FooBuilderError), initializers: vec![quote!(foo: self.foo,)], doc_comment: None, default_struct: None, validate_fn: None, } }; } #[cfg(test)] mod tests { #[allow(unused_imports)] use super::*; #[test] fn std() { let build_method = default_build_method!(); #[rustfmt::skip] assert_eq!( quote!(#build_method).to_string(), quote!( pub fn build(&self) -> ::db::export::core::result::Result { Ok(Foo { foo: self.foo, }) } ) .to_string() ); } #[test] fn default_struct() { let mut build_method = default_build_method!(); let alt_default = DefaultExpression::explicit::(parse_quote!(Default::default())); build_method.default_struct = Some(&alt_default); #[rustfmt::skip] assert_eq!( quote!(#build_method).to_string(), quote!( pub fn build(&self) -> ::db::export::core::result::Result { let __default: Foo = { Default::default() }; Ok(Foo { foo: self.foo, }) } ) .to_string() ); } #[test] fn skip() { let mut build_method = default_build_method!(); build_method.enabled = false; build_method.enabled = false; assert_eq!(quote!(#build_method).to_string(), quote!().to_string()); } #[test] fn rename() { let ident = syn::Ident::new("finish", Span::call_site()); let mut build_method: BuildMethod = default_build_method!(); build_method.ident = &ident; #[rustfmt::skip] assert_eq!( quote!(#build_method).to_string(), quote!( pub fn finish(&self) -> ::db::export::core::result::Result { Ok(Foo { foo: self.foo, }) } ) .to_string() ); } #[test] fn validation() { let validate_path: syn::Path = parse_quote!(IpsumBuilder::validate); let mut build_method: BuildMethod = default_build_method!(); build_method.validate_fn = Some(&validate_path); #[rustfmt::skip] assert_eq!( quote!(#build_method).to_string(), quote!( pub fn build(&self) -> ::db::export::core::result::Result { IpsumBuilder::validate(&self)?; Ok(Foo { foo: self.foo, }) } ) .to_string() ); } } derive_builder_core-0.12.0/src/builder.rs000064400000000000000000000643431046102023000164750ustar 00000000000000use std::borrow::Cow; use proc_macro2::TokenStream; use quote::{format_ident, ToTokens, TokenStreamExt}; use syn::punctuated::Punctuated; use syn::{self, Path, TraitBound, TraitBoundModifier, TypeParamBound}; use doc_comment_from; use BuildMethod; use BuilderField; use BuilderPattern; use DeprecationNotes; use Setter; /// Builder, implementing `quote::ToTokens`. /// /// # Examples /// /// Will expand to something like the following (depending on settings): /// /// ```rust,ignore /// # extern crate proc_macro2; /// # #[macro_use] /// # extern crate quote; /// # extern crate syn; /// # #[macro_use] /// # extern crate derive_builder_core; /// # use quote::TokenStreamExt; /// # use derive_builder_core::{Builder, DeprecationNotes}; /// # fn main() { /// # let builder = default_builder!(); /// # /// # assert_eq!( /// # quote!(#builder).to_string(), /// # { /// # let mut result = quote!(); /// # #[cfg(not(feature = "clippy"))] /// # result.append_all(quote!(#[allow(clippy::all)])); /// # /// # result.append_all(quote!( /// #[derive(Clone)] /// pub struct FooBuilder { /// foo: u32, /// } /// /// #[doc="Error type for FooBuilder"] /// #[derive(Debug)] /// #[non_exhaustive] /// pub enum FooBuilderError { /// /// Uninitialized field /// UninitializedField(&'static str), /// /// Custom validation error /// ValidationError(::derive_builder::export::core::string::String), /// } /// /// impl ::derive_builder::export::core::convert::From<... various ...> for FooBuilderError {} /// /// #[cfg(not(no_std))] /// impl std::error::Error for FooBuilderError {} /// # )); /// # #[cfg(not(feature = "clippy"))] /// # result.append_all(quote!(#[allow(clippy::all)])); /// # /// # result.append_all(quote!( /// /// #[allow(dead_code)] /// impl FooBuilder { /// fn bar () -> { /// unimplemented!() /// } /// } /// /// impl ::derive_builder::export::core::default::Default for FooBuilder { /// fn default() -> Self { /// Self { /// foo: ::derive_builder::export::core::default::Default::default(), /// } /// } /// } /// /// # )); /// # result /// # }.to_string() /// # ); /// # } /// ``` #[derive(Debug)] pub struct Builder<'a> { /// Path to the root of the derive_builder crate. pub crate_root: &'a Path, /// Enables code generation for this builder struct. pub enabled: bool, /// Name of this builder struct. pub ident: syn::Ident, /// Pattern of this builder struct. pub pattern: BuilderPattern, /// Traits to automatically derive on the builder type. pub derives: &'a [Path], /// Attributes to include on the builder `struct` declaration. pub struct_attrs: &'a [syn::Attribute], /// Attributes to include on the builder's inherent `impl` block. pub impl_attrs: &'a [syn::Attribute], /// When true, generate `impl Default for #ident` which calls the `create_empty` inherent method. /// /// Note that the name of `create_empty` can be overridden; see the `create_empty` field for more. pub impl_default: bool, /// The identifier of the inherent method that creates a builder with all fields set to /// `None` or `PhantomData`. /// /// This method will be invoked by `impl Default` for the builder, but it is also accessible /// to `impl` blocks on the builder that expose custom constructors. pub create_empty: syn::Ident, /// Type parameters and lifetimes attached to this builder's struct /// definition. pub generics: Option<&'a syn::Generics>, /// Visibility of the builder struct, e.g. `syn::Visibility::Public`. pub visibility: Cow<'a, syn::Visibility>, /// Fields of the builder struct, e.g. `foo: u32,` /// /// Expects each entry to be terminated by a comma. pub fields: Vec, /// Builder field initializers, e.g. `foo: Default::default(),` /// /// Expects each entry to be terminated by a comma. pub field_initializers: Vec, /// Functions of the builder struct, e.g. `fn bar() -> { unimplemented!() }` pub functions: Vec, /// Whether or not a generated error type is required. /// /// This would be `false` in the case where an already-existing error is to be used. pub generate_error: bool, /// Whether this builder must derive `Clone`. /// /// This is true even for a builder using the `owned` pattern if there is a field whose setter /// uses a different pattern. pub must_derive_clone: bool, /// Doc-comment of the builder struct. pub doc_comment: Option, /// Emit deprecation notes to the user. pub deprecation_notes: DeprecationNotes, /// Whether or not a libstd is used. pub std: bool, } impl<'a> ToTokens for Builder<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { if self.enabled { let crate_root = self.crate_root; let builder_vis = &self.visibility; let builder_ident = &self.ident; let bounded_generics = self.compute_impl_bounds(); let (impl_generics, _, _) = bounded_generics.split_for_impl(); let (struct_generics, ty_generics, where_clause) = self .generics .map(syn::Generics::split_for_impl) .map(|(i, t, w)| (Some(i), Some(t), Some(w))) .unwrap_or((None, None, None)); let builder_fields = &self.fields; let builder_field_initializers = &self.field_initializers; let create_empty = &self.create_empty; let functions = &self.functions; // Create the comma-separated set of derived traits for the builder let derive_attr = { let clone_trait: Path = parse_quote!(Clone); let mut traits: Punctuated<&Path, Token![,]> = Default::default(); if self.must_derive_clone { traits.push(&clone_trait); } traits.extend(self.derives); if traits.is_empty() { quote!() } else { quote!(#[derive(#traits)]) } }; let struct_attrs = self.struct_attrs; let impl_attrs = self.impl_attrs; let builder_doc_comment = &self.doc_comment; let deprecation_notes = &self.deprecation_notes.as_item(); #[cfg(not(feature = "clippy"))] tokens.append_all(quote!(#[allow(clippy::all)])); // struct_attrs MUST come after derive_attr, otherwise attributes for a derived // trait will appear before its derivation. As of rustc 1.59.0 this is a compiler // warning; see https://github.com/rust-lang/rust/issues/79202 tokens.append_all(quote!( #derive_attr #(#struct_attrs)* #builder_doc_comment #builder_vis struct #builder_ident #struct_generics #where_clause { #(#builder_fields)* } )); #[cfg(not(feature = "clippy"))] tokens.append_all(quote!(#[allow(clippy::all)])); tokens.append_all(quote!( #(#impl_attrs)* #[allow(dead_code)] impl #impl_generics #builder_ident #ty_generics #where_clause { #(#functions)* #deprecation_notes /// Create an empty builder, with all fields set to `None` or `PhantomData`. fn #create_empty() -> Self { Self { #(#builder_field_initializers)* } } } )); if self.impl_default { tokens.append_all(quote!( impl #impl_generics #crate_root::export::core::default::Default for #builder_ident #ty_generics #where_clause { fn default() -> Self { Self::#create_empty() } } )); } if self.generate_error { let builder_error_ident = format_ident!("{}Error", builder_ident); let builder_error_doc = format!("Error type for {}", builder_ident); tokens.append_all(quote!( #[doc=#builder_error_doc] #[derive(Debug)] #[non_exhaustive] #builder_vis enum #builder_error_ident { /// Uninitialized field UninitializedField(&'static str), /// Custom validation error ValidationError(#crate_root::export::core::string::String), } impl #crate_root::export::core::convert::From<#crate_root::UninitializedFieldError> for #builder_error_ident { fn from(s: #crate_root::UninitializedFieldError) -> Self { Self::UninitializedField(s.field_name()) } } impl #crate_root::export::core::convert::From<#crate_root::export::core::string::String> for #builder_error_ident { fn from(s: #crate_root::export::core::string::String) -> Self { Self::ValidationError(s) } } impl #crate_root::export::core::fmt::Display for #builder_error_ident { fn fmt(&self, f: &mut #crate_root::export::core::fmt::Formatter) -> #crate_root::export::core::fmt::Result { match self { Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), Self::ValidationError(ref error) => write!(f, "{}", error), } } } )); if self.std { tokens.append_all(quote!( impl std::error::Error for #builder_error_ident {} )); } } } } } impl<'a> Builder<'a> { /// Set a doc-comment for this item. pub fn doc_comment(&mut self, s: String) -> &mut Self { self.doc_comment = Some(doc_comment_from(s)); self } /// Add a field to the builder pub fn push_field(&mut self, f: BuilderField) -> &mut Self { self.fields.push(quote!(#f)); self.field_initializers.push(f.default_initializer_tokens()); self } /// Add a setter function to the builder pub fn push_setter_fn(&mut self, f: Setter) -> &mut Self { self.functions.push(quote!(#f)); self } /// Add final build function to the builder pub fn push_build_fn(&mut self, f: BuildMethod) -> &mut Self { self.functions.push(quote!(#f)); self } /// Add `Clone` trait bound to generic types for non-owned builders. /// This enables target types to declare generics without requiring a /// `Clone` impl. This is the same as how the built-in derives for /// `Clone`, `Default`, `PartialEq`, and other traits work. fn compute_impl_bounds(&self) -> syn::Generics { if let Some(type_gen) = self.generics { let mut generics = type_gen.clone(); if !self.pattern.requires_clone() || type_gen.type_params().next().is_none() { return generics; } let crate_root = self.crate_root; let clone_bound = TypeParamBound::Trait(TraitBound { paren_token: None, modifier: TraitBoundModifier::None, lifetimes: None, path: syn::parse_quote!(#crate_root::export::core::clone::Clone), }); for typ in generics.type_params_mut() { typ.bounds.push(clone_bound.clone()); } generics } else { Default::default() } } } /// Helper macro for unit tests. This is _only_ public in order to be accessible /// from doc-tests too. #[doc(hidden)] #[macro_export] macro_rules! default_builder { () => { Builder { // Deliberately don't use the default value here - make sure // that all test cases are passing crate_root through properly. crate_root: &parse_quote!(::db), enabled: true, ident: syn::Ident::new("FooBuilder", ::proc_macro2::Span::call_site()), pattern: Default::default(), derives: &vec![], struct_attrs: &vec![], impl_attrs: &vec![], impl_default: true, create_empty: syn::Ident::new("create_empty", ::proc_macro2::Span::call_site()), generics: None, visibility: ::std::borrow::Cow::Owned(parse_quote!(pub)), fields: vec![quote!(foo: u32,)], field_initializers: vec![quote!(foo: ::db::export::core::default::Default::default(), )], functions: vec![quote!(fn bar() -> { unimplemented!() })], generate_error: true, must_derive_clone: true, doc_comment: None, deprecation_notes: DeprecationNotes::default(), std: true, } }; } #[cfg(test)] mod tests { #[allow(unused_imports)] use super::*; use proc_macro2::TokenStream; use syn::Ident; fn add_generated_error(result: &mut TokenStream) { result.append_all(quote!( #[doc="Error type for FooBuilder"] #[derive(Debug)] #[non_exhaustive] pub enum FooBuilderError { /// Uninitialized field UninitializedField(&'static str), /// Custom validation error ValidationError(::db::export::core::string::String), } impl ::db::export::core::convert::From<::db::UninitializedFieldError> for FooBuilderError { fn from(s: ::db::UninitializedFieldError) -> Self { Self::UninitializedField(s.field_name()) } } impl ::db::export::core::convert::From<::db::export::core::string::String> for FooBuilderError { fn from(s: ::db::export::core::string::String) -> Self { Self::ValidationError(s) } } impl ::db::export::core::fmt::Display for FooBuilderError { fn fmt(&self, f: &mut ::db::export::core::fmt::Formatter) -> ::db::export::core::fmt::Result { match self { Self::UninitializedField(ref field) => write!(f, "`{}` must be initialized", field), Self::ValidationError(ref error) => write!(f, "{}", error), } } } impl std::error::Error for FooBuilderError {} )); } #[test] fn simple() { let builder = default_builder!(); assert_eq!( quote!(#builder).to_string(), { let mut result = quote!(); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[derive(Clone)] pub struct FooBuilder { foo: u32, } )); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[allow(dead_code)] impl FooBuilder { fn bar () -> { unimplemented!() } /// Create an empty builder, with all fields set to `None` or `PhantomData`. fn create_empty() -> Self { Self { foo: ::db::export::core::default::Default::default(), } } } impl ::db::export::core::default::Default for FooBuilder { fn default() -> Self { Self::create_empty() } } )); add_generated_error(&mut result); result } .to_string() ); } #[test] fn rename_create_empty() { let mut builder = default_builder!(); builder.create_empty = Ident::new("empty", proc_macro2::Span::call_site()); assert_eq!( quote!(#builder).to_string(), { let mut result = quote!(); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[derive(Clone)] pub struct FooBuilder { foo: u32, } )); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[allow(dead_code)] impl FooBuilder { fn bar () -> { unimplemented!() } /// Create an empty builder, with all fields set to `None` or `PhantomData`. fn empty() -> Self { Self { foo: ::db::export::core::default::Default::default(), } } } impl ::db::export::core::default::Default for FooBuilder { fn default() -> Self { Self::empty() } } )); add_generated_error(&mut result); result } .to_string() ); } // This test depends on the exact formatting of the `stringify`'d code, // so we don't automatically format the test #[rustfmt::skip] #[test] fn generic() { let ast: syn::DeriveInput = parse_quote! { struct Lorem<'a, T: Debug> where T: PartialEq { } }; let generics = ast.generics; let mut builder = default_builder!(); builder.generics = Some(&generics); assert_eq!( quote!(#builder).to_string(), { let mut result = quote!(); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[derive(Clone)] pub struct FooBuilder<'a, T: Debug> where T: PartialEq { foo: u32, } )); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[allow(dead_code)] impl<'a, T: Debug + ::db::export::core::clone::Clone> FooBuilder<'a, T> where T: PartialEq { fn bar() -> { unimplemented!() } /// Create an empty builder, with all fields set to `None` or `PhantomData`. fn create_empty() -> Self { Self { foo: ::db::export::core::default::Default::default(), } } } impl<'a, T: Debug + ::db::export::core::clone::Clone> ::db::export::core::default::Default for FooBuilder<'a, T> where T: PartialEq { fn default() -> Self { Self::create_empty() } } )); add_generated_error(&mut result); result }.to_string() ); } // This test depends on the exact formatting of the `stringify`'d code, // so we don't automatically format the test #[rustfmt::skip] #[test] fn generic_reference() { let ast: syn::DeriveInput = parse_quote! { struct Lorem<'a, T: 'a + Default> where T: PartialEq{ } }; let generics = ast.generics; let mut builder = default_builder!(); builder.generics = Some(&generics); assert_eq!( quote!(#builder).to_string(), { let mut result = quote!(); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[derive(Clone)] pub struct FooBuilder<'a, T: 'a + Default> where T: PartialEq { foo: u32, } )); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[allow(dead_code)] impl<'a, T: 'a + Default + ::db::export::core::clone::Clone> FooBuilder<'a, T> where T: PartialEq { fn bar() -> { unimplemented!() } /// Create an empty builder, with all fields set to `None` or `PhantomData`. fn create_empty() -> Self { Self { foo: ::db::export::core::default::Default::default(), } } } impl<'a, T: 'a + Default + ::db::export::core::clone::Clone> ::db::export::core::default::Default for FooBuilder<'a, T> where T: PartialEq { fn default() -> Self { Self::create_empty() } } )); add_generated_error(&mut result); result }.to_string() ); } // This test depends on the exact formatting of the `stringify`'d code, // so we don't automatically format the test #[rustfmt::skip] #[test] fn owned_generic() { let ast: syn::DeriveInput = parse_quote! { struct Lorem<'a, T: Debug> where T: PartialEq { } }; let generics = ast.generics; let mut builder = default_builder!(); builder.generics = Some(&generics); builder.pattern = BuilderPattern::Owned; builder.must_derive_clone = false; assert_eq!( quote!(#builder).to_string(), { let mut result = quote!(); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( pub struct FooBuilder<'a, T: Debug> where T: PartialEq { foo: u32, } )); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[allow(dead_code)] impl<'a, T: Debug> FooBuilder<'a, T> where T: PartialEq { fn bar() -> { unimplemented!() } /// Create an empty builder, with all fields set to `None` or `PhantomData`. fn create_empty() -> Self { Self { foo: ::db::export::core::default::Default::default(), } } } impl<'a, T: Debug> ::db::export::core::default::Default for FooBuilder<'a, T> where T: PartialEq { fn default() -> Self { Self::create_empty() } } )); add_generated_error(&mut result); result }.to_string() ); } #[test] fn disabled() { let mut builder = default_builder!(); builder.enabled = false; assert_eq!(quote!(#builder).to_string(), quote!().to_string()); } #[test] fn add_derives() { let derives = vec![parse_quote!(Serialize)]; let mut builder = default_builder!(); builder.derives = &derives; assert_eq!( quote!(#builder).to_string(), { let mut result = quote!(); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[derive(Clone, Serialize)] pub struct FooBuilder { foo: u32, } )); #[cfg(not(feature = "clippy"))] result.append_all(quote!(#[allow(clippy::all)])); result.append_all(quote!( #[allow(dead_code)] impl FooBuilder { fn bar () -> { unimplemented!() } /// Create an empty builder, with all fields set to `None` or `PhantomData`. fn create_empty() -> Self { Self { foo: ::db::export::core::default::Default::default(), } } } impl ::db::export::core::default::Default for FooBuilder { fn default() -> Self { Self::create_empty() } } )); add_generated_error(&mut result); result } .to_string() ); } } derive_builder_core-0.12.0/src/builder_field.rs000064400000000000000000000154771046102023000176440ustar 00000000000000use std::borrow::Cow; use proc_macro2::TokenStream; use quote::{ToTokens, TokenStreamExt}; use syn; /// Field for the builder struct, implementing `quote::ToTokens`. /// /// # Examples /// /// Will expand to something like the following (depending on settings): /// /// ```rust,ignore /// # extern crate proc_macro2; /// # #[macro_use] /// # extern crate quote; /// # #[macro_use] /// # extern crate syn; /// # #[macro_use] /// # extern crate derive_builder_core; /// # use derive_builder_core::{BuilderField, BuilderPattern}; /// # fn main() { /// # let attrs = vec![parse_quote!(#[some_attr])]; /// # let mut field = default_builder_field!(); /// # field.attrs = attrs.as_slice(); /// # /// # assert_eq!(quote!(#field).to_string(), quote!( /// #[some_attr] pub foo: ::derive_builder::export::core::option::Option, /// # ).to_string()); /// # } /// ``` #[derive(Debug, Clone)] pub struct BuilderField<'a> { /// Path to the root of the derive_builder crate. pub crate_root: &'a syn::Path, /// Name of the target field. pub field_ident: &'a syn::Ident, /// Type of the builder field. pub field_type: BuilderFieldType<'a>, /// Visibility of this builder field, e.g. `syn::Visibility::Public`. pub field_visibility: Cow<'a, syn::Visibility>, /// Attributes which will be attached to this builder field. pub attrs: &'a [syn::Attribute], } impl<'a> ToTokens for BuilderField<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let ident = self.field_ident; let vis = &self.field_visibility; let ty = &self.field_type.with_crate_root(self.crate_root); let attrs = self.attrs; tokens.append_all(quote!( #(#attrs)* #vis #ident: #ty, )); } } impl<'a> BuilderField<'a> { /// Emits a struct field initializer that initializes the field to `Default::default`. pub fn default_initializer_tokens(&self) -> TokenStream { let ident = self.field_ident; let crate_root = self.crate_root; quote! { #ident : #crate_root::export::core::default::Default::default(), } } } /// The type of a field in the builder struct #[derive(Debug, Clone)] pub enum BuilderFieldType<'a> { /// The corresonding builder field will be `Option`. Optional(&'a syn::Type), /// The corresponding builder field will be just this type Precise(&'a syn::Type), /// The corresponding builder field will be a PhantomData /// /// We do this if if the field is disabled. We mustn't just completely omit the field from the builder: /// if we did that, the builder might have unused generic parameters (since we copy the generics from /// the target struct). Using a PhantomData of the original field type provides the right generic usage /// (and the right variance). The alternative would be to give the user a way to separately control /// the generics of the builder struct, which would be very awkward to use and complex to document. /// We could just include the field anyway, as `Option`, but this is wasteful of space, and it /// seems good to explicitly suppress the existence of a variable that won't be set or read. Phantom(&'a syn::Type), } impl<'a> BuilderFieldType<'a> { /// Obtain type information for the builder field setter /// /// Return value: /// * `.0`: type of the argument to the setter function /// (before application of `strip_option`, `into`) /// * `.1`: whether the builder field is `Option` rather than just `type` pub fn setter_type_info(&'a self) -> (&'a syn::Type, bool) { match self { BuilderFieldType::Optional(ty) => (ty, true), BuilderFieldType::Precise(ty) => (ty, false), BuilderFieldType::Phantom(_ty) => panic!("phantom fields should never have setters"), } } fn with_crate_root(&'a self, crate_root: &'a syn::Path) -> BuilderFieldTypeWithCrateRoot<'a> { BuilderFieldTypeWithCrateRoot { crate_root, field_type: self, } } } struct BuilderFieldTypeWithCrateRoot<'a> { crate_root: &'a syn::Path, field_type: &'a BuilderFieldType<'a>, } impl<'a> ToTokens for BuilderFieldTypeWithCrateRoot<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let crate_root = self.crate_root; match self.field_type { BuilderFieldType::Optional(ty) => tokens.append_all(quote!( #crate_root::export::core::option::Option<#ty> )), BuilderFieldType::Precise(ty) => ty.to_tokens(tokens), BuilderFieldType::Phantom(ty) => tokens.append_all(quote!( #crate_root::export::core::marker::PhantomData<#ty> )), } } } /// Helper macro for unit tests. This is _only_ public in order to be accessible /// from doc-tests too. #[cfg(test)] // This contains a Box::leak, so is suitable only for tests #[doc(hidden)] #[macro_export] macro_rules! default_builder_field { () => {{ BuilderField { // Deliberately don't use the default value here - make sure // that all test cases are passing crate_root through properly. crate_root: &parse_quote!(::db), field_ident: &syn::Ident::new("foo", ::proc_macro2::Span::call_site()), field_type: BuilderFieldType::Optional(Box::leak(Box::new(parse_quote!(String)))), field_visibility: ::std::borrow::Cow::Owned(parse_quote!(pub)), attrs: &[parse_quote!(#[some_attr])], } }}; } #[cfg(test)] mod tests { #[allow(unused_imports)] use super::*; #[test] fn setter_enabled() { let field = default_builder_field!(); assert_eq!( quote!(#field).to_string(), quote!( #[some_attr] pub foo: ::db::export::core::option::Option, ) .to_string() ); } #[test] fn setter_disabled() { let mut field = default_builder_field!(); field.field_visibility = Cow::Owned(syn::Visibility::Inherited); field.field_type = match field.field_type { BuilderFieldType::Optional(ty) => BuilderFieldType::Phantom(ty), _ => panic!(), }; assert_eq!( quote!(#field).to_string(), quote!( #[some_attr] foo: ::db::export::core::marker::PhantomData, ) .to_string() ); } #[test] fn private_field() { let private = Cow::Owned(syn::Visibility::Inherited); let mut field = default_builder_field!(); field.field_visibility = private; assert_eq!( quote!(#field).to_string(), quote!( #[some_attr] foo: ::db::export::core::option::Option, ) .to_string() ); } } derive_builder_core-0.12.0/src/change_span.rs000064400000000000000000000021351046102023000173040ustar 00000000000000use std::iter::FromIterator; use proc_macro2::{Group, Span, TokenStream, TokenTree}; /// Deeply change the span of some tokens, ensuring that the output only references `span`. /// /// Macros such as `quote_spanned` preserve the spans of interpolated tokens, which is useful. /// However, in some very specific scenarios it is desirable to suppress the original span /// information in favor of a different one. /// /// For more information, see [dtolnay/syn#309](https://github.com/dtolnay/syn/issues/309). pub(crate) fn change_span(tokens: TokenStream, span: Span) -> TokenStream { let mut result = vec![]; for mut token in tokens { match token { TokenTree::Group(group) => { let mut new_group = Group::new(group.delimiter(), change_span(group.stream(), span)); new_group.set_span(span); result.push(TokenTree::Group(new_group)); } _ => { token.set_span(span); result.push(token); } } } FromIterator::from_iter(result.into_iter()) } derive_builder_core-0.12.0/src/default_expression.rs000064400000000000000000000041231046102023000207400ustar 00000000000000use crate::BlockContents; use proc_macro2::Span; use quote::ToTokens; /// A `DefaultExpression` can be either explicit or refer to the canonical trait. #[derive(Debug, Clone)] pub enum DefaultExpression { Explicit(BlockContents), Trait, } impl DefaultExpression { /// Add the crate root path so the default expression can be emitted /// to a `TokenStream`. /// /// This function is needed because the crate root is inherited from the container, so it cannot /// be provided at parse time to [`darling::FromMeta::from_word`] when reading, and [`ToTokens`] does not /// accept any additional parameters, so it annot be provided at emit time. pub fn with_crate_root<'a>(&'a self, crate_root: &'a syn::Path) -> impl 'a + ToTokens { DefaultExpressionWithCrateRoot { crate_root, expr: self, } } #[cfg(test)] pub fn explicit>(content: I) -> Self { DefaultExpression::Explicit(content.into()) } } impl darling::FromMeta for DefaultExpression { fn from_word() -> darling::Result { Ok(DefaultExpression::Trait) } fn from_value(value: &syn::Lit) -> darling::Result { Ok(Self::Explicit(BlockContents::from_value(value)?)) } } impl syn::spanned::Spanned for DefaultExpression { fn span(&self) -> Span { match self { DefaultExpression::Explicit(block) => block.span(), DefaultExpression::Trait => Span::call_site(), } } } /// Wrapper for `DefaultExpression` struct DefaultExpressionWithCrateRoot<'a> { crate_root: &'a syn::Path, expr: &'a DefaultExpression, } impl<'a> ToTokens for DefaultExpressionWithCrateRoot<'a> { fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { let crate_root = self.crate_root; match self.expr { DefaultExpression::Explicit(ref block) => block.to_tokens(tokens), DefaultExpression::Trait => quote!( #crate_root::export::core::default::Default::default() ) .to_tokens(tokens), } } } derive_builder_core-0.12.0/src/deprecation_notes.rs000064400000000000000000000057651046102023000205570ustar 00000000000000use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, TokenStreamExt}; use syn; /// Deprecation notes we want to emit to the user, implementing /// `quote::ToTokens`. /// /// Can be expanded at every place that accepts statements and item definitions /// (e.g. function bodys). /// /// # Examples /// /// Will expand to something like the following (depending on settings): /// /// ```rust,ignore /// # #[macro_use] /// # extern crate quote; /// # extern crate derive_builder_core; /// # use derive_builder_core::DeprecationNotes; /// # fn main() { /// # let mut note = DeprecationNotes::default(); /// # note.push("Some Warning".to_string()); /// # assert_eq!(quote!(#note).to_string(), quote!( /// { /// #[deprecated(note = "Some Warning")] /// fn derive_builder_core_deprecation_note() { } /// derive_builder_core_deprecation_note(); /// } /// # ).to_string()); /// # } /// ``` /// /// This will emit a deprecation warning in the downstream crate. Cool stuff. ^^ /// /// Proof of concept: /// - #[derive(Debug, Default, Clone)] pub struct DeprecationNotes(Vec); impl ToTokens for DeprecationNotes { fn to_tokens(&self, tokens: &mut TokenStream) { for note in &self.0 { let fn_ident = syn::Ident::new("derive_builder_core_deprecation_note", Span::call_site()); tokens.append_all(quote!( { #[deprecated(note=#note)] fn #fn_ident() { } #fn_ident(); } )); } } } impl DeprecationNotes { /// Appends a note to the collection. #[cfg(test)] pub fn push(&mut self, note: String) { self.0.push(note) } /// Create a view of these deprecation notes that can annotate a struct. pub const fn as_item(&self) -> DeprecationNotesAsItem { DeprecationNotesAsItem(self) } } /// A view of `DeprecationNotes` that can be used in any context that accept /// items. /// /// Expands to a function `__deprecation_notes` which emits the notes. #[derive(Debug)] pub struct DeprecationNotesAsItem<'a>(&'a DeprecationNotes); impl<'a> ToTokens for DeprecationNotesAsItem<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let deprecation_notes = self.0; if !deprecation_notes.0.is_empty() { tokens.append_all(quote!( #[doc(hidden)] fn derive_builder_core_deprecation_note() { #deprecation_notes } )) } } } #[test] fn deprecation_note() { let mut note = DeprecationNotes::default(); note.push("Some Warning".to_string()); assert_eq!( quote!(#note).to_string(), quote!({ #[deprecated(note = "Some Warning")] fn derive_builder_core_deprecation_note() {} derive_builder_core_deprecation_note(); }) .to_string() ); } derive_builder_core-0.12.0/src/doc_comment.rs000064400000000000000000000012001046102023000173150ustar 00000000000000use syn::Attribute; /// Doc-comment, implementing `quote::ToTokens`. /// /// # Examples /// /// Will expand to something like the following (depending on inner value): /// /// ```rust,ignore /// # #[macro_use] /// # extern crate quote; /// # extern crate syn; /// # extern crate derive_builder_core; /// # use derive_builder_core::doc_comment_from; /// # fn main() { /// # let doc_comment = doc_comment_from("foo".to_string()); /// # /// # assert_eq!(quote!(#doc_comment).to_string(), quote!( /// #[doc = "foo"] /// # ).to_string()); /// # } /// ``` pub fn doc_comment_from(s: String) -> Attribute { parse_quote!(#[doc=#s]) } derive_builder_core-0.12.0/src/doc_tpl/builder_method.md000064400000000000000000000001271046102023000214230ustar 00000000000000Builds a new `{struct_name}`. # Errors If a required field has not been initialized. derive_builder_core-0.12.0/src/doc_tpl/builder_struct.md000064400000000000000000000000721046102023000214660ustar 00000000000000Builder for [`{struct_name}`](struct.{struct_name}.html). derive_builder_core-0.12.0/src/doc_tpl/mod.rs000064400000000000000000000007301046102023000172400ustar 00000000000000//! This module is organizes chunks of documentation templates //! for the generated code. //! //! Documentation templates may contain the following placeholders //! - {struct_name} //! - {builder_name} //! - {field_name} //! //! Templates are used like this: //! //! ```rust,ignore //! let builder_struct_doc = format!( //! include_str!("doc_tpl/builder_struct.md"), //! struct_name = /*..*/, //! builder_name = /*..*/), //! field_name = /*..*/); //! ``` derive_builder_core-0.12.0/src/initializer.rs000064400000000000000000000324651046102023000173720ustar 00000000000000use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, TokenStreamExt}; use syn; use BuilderPattern; use DEFAULT_STRUCT_NAME; use crate::{change_span, BlockContents, DefaultExpression}; /// Initializer for the target struct fields, implementing `quote::ToTokens`. /// /// Lives in the body of `BuildMethod`. /// /// # Examples /// /// Will expand to something like the following (depending on settings): /// /// ```rust,ignore /// # extern crate proc_macro2; /// # #[macro_use] /// # extern crate quote; /// # extern crate syn; /// # #[macro_use] /// # extern crate derive_builder_core; /// # use derive_builder_core::{DeprecationNotes, Initializer, BuilderPattern}; /// # fn main() { /// # let mut initializer = default_initializer!(); /// # initializer.default_value = Some("42".parse().unwrap()); /// # initializer.builder_pattern = BuilderPattern::Owned; /// # /// # assert_eq!(quote!(#initializer).to_string(), quote!( /// foo: match self.foo { /// Some(value) => value, /// None => { 42 }, /// }, /// # ).to_string()); /// # } /// ``` #[derive(Debug, Clone)] pub struct Initializer<'a> { /// Path to the root of the derive_builder crate. pub crate_root: &'a syn::Path, /// Name of the target field. pub field_ident: &'a syn::Ident, /// Whether the builder implements a setter for this field. pub field_enabled: bool, /// How the build method takes and returns `self` (e.g. mutably). pub builder_pattern: BuilderPattern, /// Default value for the target field. /// /// This takes precedence over a default struct identifier. pub default_value: Option<&'a DefaultExpression>, /// Whether the build_method defines a default struct. pub use_default_struct: bool, /// Span where the macro was told to use a preexisting error type, instead of creating one, /// to represent failures of the `build` method. /// /// An initializer can force early-return if a field has no set value and no default is /// defined. In these cases, it will convert from `derive_builder::UninitializedFieldError` /// into the return type of its enclosing `build` method. That conversion is guaranteed to /// work for generated error types, but if the caller specified an error type to use instead /// they may have forgotten the conversion from `UninitializedFieldError` into their specified /// error type. pub custom_error_type_span: Option, /// Method to use to to convert the builder's field to the target field /// /// For sub-builder fields, this will be `build` (or similar) pub conversion: FieldConversion<'a>, } impl<'a> ToTokens for Initializer<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let struct_field = &self.field_ident; let builder_field = struct_field; // This structure prevents accidental failure to add the trailing `,` due to incautious `return` let append_rhs = |tokens: &mut TokenStream| { if !self.field_enabled { let default = self.default(); tokens.append_all(quote!( #default )); } else { match &self.conversion { FieldConversion::Block(conv) => { conv.to_tokens(tokens); } FieldConversion::Move => tokens.append_all(quote!( self.#builder_field )), FieldConversion::OptionOrDefault => { let match_some = self.match_some(); let match_none = self.match_none(); tokens.append_all(quote!( match self.#builder_field { #match_some, #match_none, } )); } } } }; tokens.append_all(quote!(#struct_field:)); append_rhs(tokens); tokens.append_all(quote!(,)); } } impl<'a> Initializer<'a> { /// To be used inside of `#struct_field: match self.#builder_field { ... }` fn match_some(&'a self) -> MatchSome { match self.builder_pattern { BuilderPattern::Owned => MatchSome::Move, BuilderPattern::Mutable | BuilderPattern::Immutable => MatchSome::Clone { crate_root: self.crate_root, }, } } /// To be used inside of `#struct_field: match self.#builder_field { ... }` fn match_none(&'a self) -> MatchNone<'a> { match self.default_value { Some(expr) => MatchNone::DefaultTo { expr, crate_root: self.crate_root, }, None => { if self.use_default_struct { MatchNone::UseDefaultStructField(self.field_ident) } else { MatchNone::ReturnError { crate_root: self.crate_root, field_name: self.field_ident.to_string(), span: self.custom_error_type_span, } } } } } fn default(&'a self) -> TokenStream { let crate_root = self.crate_root; match self.default_value { Some(expr) => expr.with_crate_root(crate_root).into_token_stream(), None if self.use_default_struct => { let struct_ident = syn::Ident::new(DEFAULT_STRUCT_NAME, Span::call_site()); let field_ident = self.field_ident; quote!(#struct_ident.#field_ident) } None => { quote!(#crate_root::export::core::default::Default::default()) } } } } #[derive(Debug, Clone)] pub enum FieldConversion<'a> { /// Usual conversion: unwrap the Option from the builder, or (hope to) use a default value OptionOrDefault, /// Custom conversion is a block contents expression Block(&'a BlockContents), /// Custom conversion is just to move the field from the builder Move, } /// To be used inside of `#struct_field: match self.#builder_field { ... }` enum MatchNone<'a> { /// Inner value must be a valid Rust expression DefaultTo { expr: &'a DefaultExpression, crate_root: &'a syn::Path, }, /// Inner value must be the field identifier /// /// The default struct must be in scope in the build_method. UseDefaultStructField(&'a syn::Ident), /// Inner value must be the field name ReturnError { crate_root: &'a syn::Path, field_name: String, span: Option, }, } impl<'a> ToTokens for MatchNone<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { match *self { MatchNone::DefaultTo { expr, crate_root } => { let expr = expr.with_crate_root(crate_root); tokens.append_all(quote!(None => #expr)); } MatchNone::UseDefaultStructField(field_ident) => { let struct_ident = syn::Ident::new(DEFAULT_STRUCT_NAME, Span::call_site()); tokens.append_all(quote!( None => #struct_ident.#field_ident )) } MatchNone::ReturnError { ref field_name, ref span, crate_root, } => { let conv_span = span.unwrap_or_else(Span::call_site); // If the conversion fails, the compiler error should point to the error declaration // rather than the crate root declaration, but the compiler will see the span of #crate_root // and produce an undesired behavior (possibly because that's the first span in the bad expression?). // Creating a copy with deeply-rewritten spans preserves the desired error behavior. let crate_root = change_span(crate_root.into_token_stream(), conv_span); let err_conv = quote_spanned!(conv_span => #crate_root::export::core::convert::Into::into( #crate_root::UninitializedFieldError::from(#field_name) )); tokens.append_all(quote!( None => return #crate_root::export::core::result::Result::Err(#err_conv) )); } } } } /// To be used inside of `#struct_field: match self.#builder_field { ... }` enum MatchSome<'a> { Move, Clone { crate_root: &'a syn::Path }, } impl ToTokens for MatchSome<'_> { fn to_tokens(&self, tokens: &mut TokenStream) { match *self { Self::Move => tokens.append_all(quote!( Some(value) => value )), Self::Clone { crate_root } => tokens.append_all(quote!( Some(ref value) => #crate_root::export::core::clone::Clone::clone(value) )), } } } /// Helper macro for unit tests. This is _only_ public in order to be accessible /// from doc-tests too. #[doc(hidden)] #[macro_export] macro_rules! default_initializer { () => { Initializer { // Deliberately don't use the default value here - make sure // that all test cases are passing crate_root through properly. crate_root: &parse_quote!(::db), field_ident: &syn::Ident::new("foo", ::proc_macro2::Span::call_site()), field_enabled: true, builder_pattern: BuilderPattern::Mutable, default_value: None, use_default_struct: false, conversion: FieldConversion::OptionOrDefault, custom_error_type_span: None, } }; } #[cfg(test)] mod tests { #[allow(unused_imports)] use super::*; #[test] fn immutable() { let mut initializer = default_initializer!(); initializer.builder_pattern = BuilderPattern::Immutable; assert_eq!( quote!(#initializer).to_string(), quote!( foo: match self.foo { Some(ref value) => ::db::export::core::clone::Clone::clone(value), None => return ::db::export::core::result::Result::Err(::db::export::core::convert::Into::into( ::db::UninitializedFieldError::from("foo") )), }, ) .to_string() ); } #[test] fn mutable() { let mut initializer = default_initializer!(); initializer.builder_pattern = BuilderPattern::Mutable; assert_eq!( quote!(#initializer).to_string(), quote!( foo: match self.foo { Some(ref value) => ::db::export::core::clone::Clone::clone(value), None => return ::db::export::core::result::Result::Err(::db::export::core::convert::Into::into( ::db::UninitializedFieldError::from("foo") )), }, ) .to_string() ); } #[test] fn owned() { let mut initializer = default_initializer!(); initializer.builder_pattern = BuilderPattern::Owned; assert_eq!( quote!(#initializer).to_string(), quote!( foo: match self.foo { Some(value) => value, None => return ::db::export::core::result::Result::Err(::db::export::core::convert::Into::into( ::db::UninitializedFieldError::from("foo") )), }, ) .to_string() ); } #[test] fn default_value() { let mut initializer = default_initializer!(); let default_value = DefaultExpression::explicit::(parse_quote!(42)); initializer.default_value = Some(&default_value); assert_eq!( quote!(#initializer).to_string(), quote!( foo: match self.foo { Some(ref value) => ::db::export::core::clone::Clone::clone(value), None => { 42 }, }, ) .to_string() ); } #[test] fn default_struct() { let mut initializer = default_initializer!(); initializer.use_default_struct = true; assert_eq!( quote!(#initializer).to_string(), quote!( foo: match self.foo { Some(ref value) => ::db::export::core::clone::Clone::clone(value), None => __default.foo, }, ) .to_string() ); } #[test] fn setter_disabled() { let mut initializer = default_initializer!(); initializer.field_enabled = false; assert_eq!( quote!(#initializer).to_string(), quote!(foo: ::db::export::core::default::Default::default(),).to_string() ); } #[test] fn no_std() { let initializer = default_initializer!(); assert_eq!( quote!(#initializer).to_string(), quote!( foo: match self.foo { Some(ref value) => ::db::export::core::clone::Clone::clone(value), None => return ::db::export::core::result::Result::Err(::db::export::core::convert::Into::into( ::db::UninitializedFieldError::from("foo") )), }, ) .to_string() ); } } derive_builder_core-0.12.0/src/lib.rs000064400000000000000000000047451046102023000156150ustar 00000000000000//! Internal helper library for the `derive_builder` crate. //! //! **Important Note**: //! //! * You are probably looking for the [`derive_builder`] crate, //! which wraps this crate and is much more ergonomic to use. //! //! ## Purpose //! //! This is an internal helper library of [`derive_builder`], which allows for //! all the logic of builder creation to be decoupled from the proc-macro entry //! point. //! //! //! [`derive_builder`]: https://!crates.io/crates/derive_builder //! [`derive_builder_core`]: https://!crates.io/crates/derive_builder_core #![deny(warnings, missing_docs)] #![cfg_attr(test, recursion_limit = "100")] #[macro_use] extern crate darling; extern crate proc_macro; extern crate proc_macro2; #[macro_use] extern crate syn; #[macro_use] extern crate quote; #[cfg(test)] #[macro_use] extern crate pretty_assertions; mod block; mod build_method; mod builder; mod builder_field; mod change_span; mod default_expression; mod deprecation_notes; mod doc_comment; mod initializer; mod macro_options; mod options; mod setter; pub(crate) use block::BlockContents; pub(crate) use build_method::BuildMethod; pub(crate) use builder::Builder; pub(crate) use builder_field::{BuilderField, BuilderFieldType}; pub(crate) use change_span::change_span; use darling::FromDeriveInput; pub(crate) use default_expression::DefaultExpression; pub(crate) use deprecation_notes::DeprecationNotes; pub(crate) use doc_comment::doc_comment_from; pub(crate) use initializer::{FieldConversion, Initializer}; pub(crate) use options::{BuilderPattern, Each}; pub(crate) use setter::Setter; const DEFAULT_STRUCT_NAME: &str = "__default"; /// Derive a builder for a struct pub fn builder_for_struct(ast: syn::DeriveInput) -> proc_macro2::TokenStream { let opts = match macro_options::Options::from_derive_input(&ast) { Ok(val) => val, Err(err) => { return err.write_errors(); } }; let mut builder = opts.as_builder(); let mut build_fn = opts.as_build_method(); builder.doc_comment(format!( include_str!("doc_tpl/builder_struct.md"), struct_name = ast.ident )); build_fn.doc_comment(format!( include_str!("doc_tpl/builder_method.md"), struct_name = ast.ident )); for field in opts.fields() { builder.push_field(field.as_builder_field()); builder.push_setter_fn(field.as_setter()); build_fn.push_initializer(field.as_initializer()); } builder.push_build_fn(build_fn); quote!(#builder) } derive_builder_core-0.12.0/src/macro_options/darling_opts.rs000064400000000000000000000756151046102023000224140ustar 00000000000000use std::{borrow::Cow, vec::IntoIter}; use crate::BuildMethod; use darling::util::{Flag, PathList}; use darling::{self, Error, FromMeta}; use proc_macro2::{Span, TokenStream}; use syn::parse::{ParseStream, Parser}; use syn::Meta; use syn::{self, spanned::Spanned, Attribute, Generics, Ident, Path}; use crate::{ BlockContents, Builder, BuilderField, BuilderFieldType, BuilderPattern, DefaultExpression, DeprecationNotes, Each, FieldConversion, Initializer, Setter, }; /// `derive_builder` uses separate sibling keywords to represent /// mutually-exclusive visibility states. This trait requires implementers to /// expose those property values and provides a method to compute any explicit visibility /// bounds. trait Visibility { fn public(&self) -> &Flag; fn private(&self) -> &Flag; fn explicit(&self) -> Option<&syn::Visibility>; /// Get the explicitly-expressed visibility preference from the attribute. /// This returns `None` if the input didn't include either keyword. /// /// # Panics /// This method panics if the input specifies both `public` and `private`. fn as_expressed_vis(&self) -> Option> { let declares_public = self.public().is_present(); let declares_private = self.private().is_present(); let declares_explicit = self.explicit().is_some(); if declares_private { assert!(!declares_public && !declares_explicit); Some(Cow::Owned(syn::Visibility::Inherited)) } else if let Some(vis) = self.explicit() { assert!(!declares_public); Some(Cow::Borrowed(vis)) } else if declares_public { Some(Cow::Owned(syn::parse_quote!(pub))) } else { None } } } fn no_visibility_conflict(v: &T) -> darling::Result<()> { let declares_public = v.public().is_present(); let declares_private = v.private().is_present(); if let Some(vis) = v.explicit() { if declares_public || declares_private { Err( Error::custom(r#"`vis="..."` cannot be used with `public` or `private`"#) .with_span(vis), ) } else { Ok(()) } } else if declares_public && declares_private { Err( Error::custom(r#"`public` and `private` cannot be used together"#) .with_span(v.public()), ) } else { Ok(()) } } /// Options for the `build_fn` property in struct-level builder options. /// There is no inheritance for these settings from struct-level to field-level, /// so we don't bother using `Option` for values in this struct. #[derive(Debug, Clone, FromMeta)] #[darling(default)] pub struct BuildFn { skip: bool, name: Ident, validate: Option, public: Flag, private: Flag, vis: Option, /// The path to an existing error type that the build method should return. /// /// Setting this will prevent `derive_builder` from generating an error type for the build /// method. /// /// # Type Bounds /// This type's bounds depend on other settings of the builder. /// /// * If uninitialized fields cause `build()` to fail, then this type /// must `impl From`. Uninitialized fields do not cause errors /// when default values are provided for every field or at the struct level. /// * If `validate` is specified, then this type must provide a conversion from the specified /// function's error type. error: Option, } impl Default for BuildFn { fn default() -> Self { BuildFn { skip: false, name: Ident::new("build", Span::call_site()), validate: None, public: Default::default(), private: Default::default(), vis: None, error: None, } } } impl Visibility for BuildFn { fn public(&self) -> &Flag { &self.public } fn private(&self) -> &Flag { &self.private } fn explicit(&self) -> Option<&syn::Visibility> { self.vis.as_ref() } } /// Contents of the `field` meta in `builder` attributes at the struct level. #[derive(Debug, Clone, Default, FromMeta)] pub struct StructLevelFieldMeta { public: Flag, private: Flag, vis: Option, } impl Visibility for StructLevelFieldMeta { fn public(&self) -> &Flag { &self.public } fn private(&self) -> &Flag { &self.private } fn explicit(&self) -> Option<&syn::Visibility> { self.vis.as_ref() } } /// Contents of the `field` meta in `builder` attributes at the field level. // // This is a superset of the attributes permitted in `field` at the struct level. // Perhaps in the future we will be able to use `#[darling(flatten)]`, but // that does not exist right now: https://github.com/TedDriggs/darling/issues/146 #[derive(Debug, Clone, Default, FromMeta)] pub struct FieldLevelFieldMeta { public: Flag, private: Flag, vis: Option, /// Custom builder field type #[darling(rename = "type")] builder_type: Option, /// Custom builder field method, for making target struct field value build: Option, } impl Visibility for FieldLevelFieldMeta { fn public(&self) -> &Flag { &self.public } fn private(&self) -> &Flag { &self.private } fn explicit(&self) -> Option<&syn::Visibility> { self.vis.as_ref() } } #[derive(Debug, Clone, Default, FromMeta)] pub struct StructLevelSetter { prefix: Option, into: Option, strip_option: Option, skip: Option, } impl StructLevelSetter { /// Check if setters are explicitly enabled or disabled at /// the struct level. pub fn enabled(&self) -> Option { self.skip.map(|x| !x) } } /// Create `Each` from an attribute's `Meta`. /// /// Two formats are supported: /// /// * `each = "..."`, which provides the name of the `each` setter and otherwise uses default values /// * `each(name = "...")`, which allows setting additional options on the `each` setter fn parse_each(meta: &Meta) -> darling::Result> { if let Meta::NameValue(mnv) = meta { if let syn::Lit::Str(v) = &mnv.lit { v.parse::() .map(Each::from) .map(Some) .map_err(|_| darling::Error::unknown_value(&v.value()).with_span(v)) } else { Err(darling::Error::unexpected_lit_type(&mnv.lit)) } } else { Each::from_meta(meta).map(Some) } } /// The `setter` meta item on fields in the input type. /// Unlike the `setter` meta item at the struct level, this allows specific /// name overrides. #[derive(Debug, Clone, Default, FromMeta)] pub struct FieldLevelSetter { prefix: Option, name: Option, into: Option, strip_option: Option, skip: Option, custom: Option, #[darling(with = "parse_each")] each: Option, } impl FieldLevelSetter { /// Get whether the setter should be emitted. The rules are the same as /// for `field_enabled`, except we only skip the setter if `setter(custom)` is present. pub fn setter_enabled(&self) -> Option { if self.custom.is_some() { return self.custom.map(|x| !x); } self.field_enabled() } /// Get whether or not this field-level setter indicates a setter and /// field should be emitted. The setter shorthand rules are that the /// presence of a `setter` with _any_ properties set forces the setter /// to be emitted. pub fn field_enabled(&self) -> Option { if self.skip.is_some() { return self.skip.map(|x| !x); } if self.prefix.is_some() || self.name.is_some() || self.into.is_some() || self.strip_option.is_some() || self.each.is_some() { return Some(true); } None } } /// `derive_builder` allows the calling code to use `setter` as a word to enable /// setters when they've been disabled at the struct level. fn field_setter(meta: &Meta) -> darling::Result { // it doesn't matter what the path is; the fact that this function // has been called means that a valueless path is the shorthand case. if let Meta::Path(_) = meta { Ok(FieldLevelSetter { skip: Some(false), ..Default::default() }) } else { FieldLevelSetter::from_meta(meta) } } /// Data extracted from the fields of the input struct. #[derive(Debug, Clone, FromField)] #[darling( attributes(builder), forward_attrs(doc, cfg, allow, builder_field_attr, builder_setter_attr), and_then = "Self::resolve" )] pub struct Field { ident: Option, /// Raw input attributes, for consumption by Field::unnest_attrs. Do not use elsewhere. attrs: Vec, ty: syn::Type, /// Field-level override for builder pattern. /// Note that setting this may force the builder to derive `Clone`. pattern: Option, public: Flag, private: Flag, /// Declared visibility for the field in the builder, e.g. `#[builder(vis = "...")]`. /// /// This cannot be named `vis` or `darling` would put the deriving field's visibility into the /// field instead. #[darling(rename = "vis")] visibility: Option, // See the documentation for `FieldSetterMeta` to understand how `darling` // is interpreting this field. #[darling(default, with = "field_setter")] setter: FieldLevelSetter, /// The value for this field if the setter is never invoked. /// /// A field can get its default one of three ways: /// /// 1. An explicit `default = "..."` expression /// 2. An explicit `default` word, in which case the field type's `Default::default()` /// value is used /// 3. Inherited from the field's value in the struct's `default` value. /// /// This property only captures the first two, the third is computed in `FieldWithDefaults`. default: Option, try_setter: Flag, #[darling(default)] field: FieldLevelFieldMeta, #[darling(skip)] field_attrs: Vec, #[darling(skip)] setter_attrs: Vec, } impl Field { fn no_visibility_conflicts(&self) -> darling::Result<()> { let mut errors = Error::accumulator(); errors.handle(no_visibility_conflict(&self.field)); errors.handle(no_visibility_conflict(self)); errors.finish() } /// Resolve and check (post-parsing) options which come from multiple darling options /// /// * Check that we don't have a custom field type or builder *and* a default value /// * Populate `self.field_attrs` and `self.setter_attrs` by draining `self.attrs` fn resolve(mut self) -> darling::Result { let mut errors = darling::Error::accumulator(); // `default` can be preempted by properties in `field`. Silently ignoring a // `default` could cause the direct user of `derive_builder` to see unexpected // behavior from the builder, so instead we require that the deriving struct // not pass any ignored instructions. if let Field { default: Some(field_default), .. } = &self { // `field.build` is stronger than `default`, as it contains both instructions on how to // deal with a missing value and conversions to do on the value during target type // construction. if self.field.build.is_some() { errors.push( darling::Error::custom( r#"#[builder(default)] and #[builder(field(build="..."))] cannot be used together"#, ) .with_span(field_default), ); } // `field.type` being set means `default` will not be used, since we don't know how // to check a custom field type for the absence of a value and therefore we'll never // know that we should use the `default` value. if self.field.builder_type.is_some() { errors.push( darling::Error::custom( r#"#[builder(default)] and #[builder(field(type="..."))] cannot be used together"#, ) .with_span(field_default) ) } }; errors.handle(distribute_and_unnest_attrs( &mut self.attrs, &mut [ ("builder_field_attr", &mut self.field_attrs), ("builder_setter_attr", &mut self.setter_attrs), ], )); errors.finish_with(self) } } /// Divide a list of attributes into multiple partially-overlapping output lists. /// /// Some attributes from the macro input will be added to the output in multiple places; /// for example, a `cfg` attribute must be replicated to both the struct and its impl block or /// the resulting code will not compile. /// /// Other attributes are scoped to a specific output by their path, e.g. `builder_field_attr`. /// These attributes will only appear in one output list, but need that outer path removed. /// /// For performance reasons, we want to do this in one pass through the list instead of /// first distributing and then iterating through each of the output lists. /// /// Each item in `outputs` contains the attribute name unique to that output, and the `Vec` where all attributes for that output should be inserted. /// Attributes whose path matches any value in `outputs` will be added only to the first matching one, and will be "unnested". /// Other attributes are not unnested, and simply copied for each decoratee. fn distribute_and_unnest_attrs( input: &mut Vec, outputs: &mut [(&'static str, &mut Vec)], ) -> darling::Result<()> { let mut errors = vec![]; for (name, list) in &*outputs { assert!(list.is_empty(), "Output Vec for '{}' was not empty", name); } for attr in input.drain(..) { let destination = outputs .iter_mut() .find(|(ptattr, _)| attr.path.is_ident(ptattr)); if let Some((_, destination)) = destination { match unnest_from_one_attribute(attr) { Ok(n) => destination.push(n), Err(e) => errors.push(e), } } else { for (_, output) in outputs.iter_mut() { output.push(attr.clone()); } } } if !errors.is_empty() { return Err(darling::Error::multiple(errors)); } Ok(()) } fn unnest_from_one_attribute(attr: syn::Attribute) -> darling::Result { match &attr.style { syn::AttrStyle::Outer => (), syn::AttrStyle::Inner(bang) => { return Err(darling::Error::unsupported_format(&format!( "{} must be an outer attribute", attr.path .get_ident() .map(Ident::to_string) .unwrap_or_else(|| "Attribute".to_string()) )) .with_span(bang)); } }; #[derive(Debug)] struct ContainedAttribute(syn::Attribute); impl syn::parse::Parse for ContainedAttribute { fn parse(input: ParseStream) -> syn::Result { // Strip parentheses, and save the span of the parenthesis token let content; let paren_token = parenthesized!(content in input); let wrap_span = paren_token.span; // Wrap up in #[ ] instead. let pound = Token![#](wrap_span); // We can't write a literal # inside quote let content: TokenStream = content.parse()?; let content = quote_spanned!(wrap_span=> #pound [ #content ]); let parser = syn::Attribute::parse_outer; let mut attrs = parser.parse2(content)?.into_iter(); // TryFrom for Array not available in Rust 1.40 // We think this error can never actually happen, since `#[...]` ought to make just one Attribute let attr = match (attrs.next(), attrs.next()) { (Some(attr), None) => attr, _ => return Err(input.error("expected exactly one attribute")), }; Ok(Self(attr)) } } let ContainedAttribute(attr) = syn::parse2(attr.tokens)?; Ok(attr) } impl Visibility for Field { fn public(&self) -> &Flag { &self.public } fn private(&self) -> &Flag { &self.private } fn explicit(&self) -> Option<&syn::Visibility> { self.visibility.as_ref() } } fn default_crate_root() -> Path { parse_quote!(::derive_builder) } fn default_create_empty() -> Ident { Ident::new("create_empty", Span::call_site()) } #[derive(Debug, Clone, FromDeriveInput)] #[darling( attributes(builder), forward_attrs(cfg, allow, builder_struct_attr, builder_impl_attr), supports(struct_named), and_then = "Self::unnest_attrs" )] pub struct Options { ident: Ident, /// DO NOT USE. /// /// Initial receiver for forwarded attributes from the struct; these are split /// into `Options::struct_attrs` and `Options::impl_attrs` before `FromDeriveInput` /// returns. attrs: Vec, #[darling(skip)] struct_attrs: Vec, #[darling(skip)] impl_attrs: Vec, /// The visibility of the deriving struct. Do not confuse this with `#[builder(vis = "...")]`, /// which is received by `Options::visibility`. vis: syn::Visibility, generics: Generics, /// The name of the generated builder. Defaults to `#{ident}Builder`. name: Option, /// The path to the root of the derive_builder crate used in generated /// code. #[darling(rename = "crate", default = "default_crate_root")] crate_root: Path, #[darling(default)] pattern: BuilderPattern, #[darling(default)] build_fn: BuildFn, /// Additional traits to derive on the builder. #[darling(default)] derive: PathList, custom_constructor: Flag, /// The ident of the inherent method which takes no arguments and returns /// an instance of the builder with all fields empty. #[darling(default = "default_create_empty")] create_empty: Ident, /// Setter options applied to all field setters in the struct. #[darling(default)] setter: StructLevelSetter, /// Struct-level value to use in place of any unfilled fields default: Option, public: Flag, private: Flag, /// Desired visibility of the builder struct. /// /// Do not confuse this with `Options::vis`, which is the visibility of the deriving struct. #[darling(rename = "vis")] visibility: Option, /// The parsed body of the derived struct. data: darling::ast::Data, no_std: Flag, /// When present, emit additional fallible setters alongside each regular /// setter. try_setter: Flag, #[darling(default)] field: StructLevelFieldMeta, #[darling(skip, default)] deprecation_notes: DeprecationNotes, } impl Visibility for Options { fn public(&self) -> &Flag { &self.public } fn private(&self) -> &Flag { &self.private } fn explicit(&self) -> Option<&syn::Visibility> { self.visibility.as_ref() } } impl Options { /// Populate `self.struct_attrs` and `self.impl_attrs` by draining `self.attrs` fn unnest_attrs(mut self) -> darling::Result { let mut errors = Error::accumulator(); errors.handle(distribute_and_unnest_attrs( &mut self.attrs, &mut [ ("builder_struct_attr", &mut self.struct_attrs), ("builder_impl_attr", &mut self.impl_attrs), ], )); // Check for conflicting visibility declarations. These cannot be pushed // down into `FieldMeta` et al because of the call to `no_visibility_conflict(&self)`, // as all sub-fields must be valid for this `Options` function to run. errors.handle(no_visibility_conflict(&self.field)); errors.handle(no_visibility_conflict(&self.build_fn)); self.data .as_ref() .map_struct_fields(|f| errors.handle(f.no_visibility_conflicts())); errors.handle(no_visibility_conflict(&self)); errors.finish_with(self) } } /// Accessors for parsed properties. impl Options { pub fn builder_ident(&self) -> Ident { if let Some(ref custom) = self.name { return custom.clone(); } format_ident!("{}Builder", self.ident) } pub fn builder_error_ident(&self) -> Path { if let Some(existing) = self.build_fn.error.as_ref() { existing.clone() } else if let Some(ref custom) = self.name { format_ident!("{}Error", custom).into() } else { format_ident!("{}BuilderError", self.ident).into() } } /// The visibility of the builder struct. /// If a visibility was declared in attributes, that will be used; /// otherwise the struct's own visibility will be used. pub fn builder_vis(&self) -> Cow { self.as_expressed_vis().unwrap_or(Cow::Borrowed(&self.vis)) } /// Get the visibility of the emitted `build` method. /// This defaults to the visibility of the parent builder, but can be overridden. pub fn build_method_vis(&self) -> Cow { self.build_fn .as_expressed_vis() .unwrap_or_else(|| self.builder_vis()) } pub fn raw_fields(&self) -> Vec<&Field> { self.data .as_ref() .take_struct() .expect("Only structs supported") .fields } /// A builder requires `Clone` to be derived if its build method or any of its setters /// use the mutable or immutable pattern. pub fn requires_clone(&self) -> bool { self.pattern.requires_clone() || self.fields().any(|f| f.pattern().requires_clone()) } /// Get an iterator over the input struct's fields which pulls fallback /// values from struct-level settings. pub fn fields(&self) -> FieldIter { FieldIter(self, self.raw_fields().into_iter()) } pub fn field_count(&self) -> usize { self.raw_fields().len() } } /// Converters to codegen structs impl Options { pub fn as_builder(&self) -> Builder { Builder { crate_root: &self.crate_root, enabled: true, ident: self.builder_ident(), pattern: self.pattern, derives: &self.derive, struct_attrs: &self.struct_attrs, impl_attrs: &self.impl_attrs, impl_default: !self.custom_constructor.is_present(), create_empty: self.create_empty.clone(), generics: Some(&self.generics), visibility: self.builder_vis(), fields: Vec::with_capacity(self.field_count()), field_initializers: Vec::with_capacity(self.field_count()), functions: Vec::with_capacity(self.field_count()), generate_error: self.build_fn.error.is_none(), must_derive_clone: self.requires_clone(), doc_comment: None, deprecation_notes: Default::default(), std: !self.no_std.is_present(), } } pub fn as_build_method(&self) -> BuildMethod { let (_, ty_generics, _) = self.generics.split_for_impl(); BuildMethod { crate_root: &self.crate_root, enabled: !self.build_fn.skip, ident: &self.build_fn.name, visibility: self.build_method_vis(), pattern: self.pattern, target_ty: &self.ident, target_ty_generics: Some(ty_generics), error_ty: self.builder_error_ident(), initializers: Vec::with_capacity(self.field_count()), doc_comment: None, default_struct: self.default.as_ref(), validate_fn: self.build_fn.validate.as_ref(), } } } /// Accessor for field data which can pull through options from the parent /// struct. pub struct FieldWithDefaults<'a> { parent: &'a Options, field: &'a Field, } /// Accessors for parsed properties, with transparent pull-through from the /// parent struct's configuration. impl<'a> FieldWithDefaults<'a> { /// Check if this field should emit a setter. pub fn setter_enabled(&self) -> bool { self.field .setter .setter_enabled() .or_else(|| self.parent.setter.enabled()) .unwrap_or(true) } pub fn field_enabled(&self) -> bool { self.field .setter .field_enabled() .or_else(|| self.parent.setter.enabled()) .unwrap_or(true) } /// Check if this field should emit a fallible setter. /// This depends on the `TryFrom` trait, which hasn't yet stabilized. pub fn try_setter(&self) -> bool { self.field.try_setter.is_present() || self.parent.try_setter.is_present() } /// Get the prefix that should be applied to the field name to produce /// the setter ident, if any. pub fn setter_prefix(&self) -> Option<&Ident> { self.field .setter .prefix .as_ref() .or(self.parent.setter.prefix.as_ref()) } /// Get the ident of the emitted setter method pub fn setter_ident(&self) -> syn::Ident { if let Some(ref custom) = self.field.setter.name { return custom.clone(); } let ident = &self.field.ident; if let Some(ref prefix) = self.setter_prefix() { return format_ident!("{}_{}", prefix, ident.as_ref().unwrap()); } ident.clone().unwrap() } /// Checks if the emitted setter should be generic over types that impl /// `Into`. pub fn setter_into(&self) -> bool { self.field .setter .into .or(self.parent.setter.into) .unwrap_or_default() } /// Checks if the emitted setter should strip the wrapper Option over types that impl /// `Option`. pub fn setter_strip_option(&self) -> bool { self.field .setter .strip_option .or(self.parent.setter.strip_option) .unwrap_or_default() } /// Get the visibility of the emitted setter, if there will be one. pub fn setter_vis(&self) -> Cow { self.field .as_expressed_vis() .or_else(|| self.parent.as_expressed_vis()) .unwrap_or_else(|| Cow::Owned(syn::parse_quote!(pub))) } /// Get the ident of the input field. This is also used as the ident of the /// emitted field. pub fn field_ident(&self) -> &syn::Ident { self.field .ident .as_ref() .expect("Tuple structs are not supported") } pub fn field_vis(&self) -> Cow { self.field .field .as_expressed_vis() .or_else( // Disabled fields become a PhantomData in the builder. We make that field // non-public, even if the rest of the builder is public, since this field is just // there to make sure the struct's generics are properly handled. || { if self.field_enabled() { None } else { Some(Cow::Owned(syn::Visibility::Inherited)) } }, ) .or_else(|| self.parent.field.as_expressed_vis()) .unwrap_or(Cow::Owned(syn::Visibility::Inherited)) } pub fn field_type(&'a self) -> BuilderFieldType<'a> { if !self.field_enabled() { BuilderFieldType::Phantom(&self.field.ty) } else if let Some(custom_ty) = self.field.field.builder_type.as_ref() { BuilderFieldType::Precise(custom_ty) } else { BuilderFieldType::Optional(&self.field.ty) } } pub fn conversion(&'a self) -> FieldConversion<'a> { match (&self.field.field.builder_type, &self.field.field.build) { (_, Some(block)) => FieldConversion::Block(block), (Some(_), None) => FieldConversion::Move, (None, None) => FieldConversion::OptionOrDefault, } } pub fn pattern(&self) -> BuilderPattern { self.field.pattern.unwrap_or(self.parent.pattern) } pub fn use_parent_default(&self) -> bool { self.field.default.is_none() && self.parent.default.is_some() } pub fn deprecation_notes(&self) -> &DeprecationNotes { &self.parent.deprecation_notes } } /// Converters to codegen structs impl<'a> FieldWithDefaults<'a> { /// Returns a `Setter` according to the options. pub fn as_setter(&'a self) -> Setter<'a> { Setter { crate_root: &self.parent.crate_root, setter_enabled: self.setter_enabled(), try_setter: self.try_setter(), visibility: self.setter_vis(), pattern: self.pattern(), attrs: &self.field.setter_attrs, ident: self.setter_ident(), field_ident: self.field_ident(), field_type: self.field_type(), generic_into: self.setter_into(), strip_option: self.setter_strip_option(), deprecation_notes: self.deprecation_notes(), each: self.field.setter.each.as_ref(), } } /// Returns an `Initializer` according to the options. /// /// # Panics /// /// if `default_expression` can not be parsed as `Block`. pub fn as_initializer(&'a self) -> Initializer<'a> { Initializer { crate_root: &self.parent.crate_root, field_enabled: self.field_enabled(), field_ident: self.field_ident(), builder_pattern: self.pattern(), default_value: self.field.default.as_ref(), use_default_struct: self.use_parent_default(), conversion: self.conversion(), custom_error_type_span: self .parent .build_fn .error .as_ref() .map(|err_ty| err_ty.span()), } } pub fn as_builder_field(&'a self) -> BuilderField<'a> { BuilderField { crate_root: &self.parent.crate_root, field_ident: self.field_ident(), field_type: self.field_type(), field_visibility: self.field_vis(), attrs: &self.field.field_attrs, } } } pub struct FieldIter<'a>(&'a Options, IntoIter<&'a Field>); impl<'a> Iterator for FieldIter<'a> { type Item = FieldWithDefaults<'a>; fn next(&mut self) -> Option { self.1.next().map(|field| FieldWithDefaults { parent: self.0, field, }) } } derive_builder_core-0.12.0/src/macro_options/mod.rs000064400000000000000000000014061046102023000204710ustar 00000000000000//! Types and functions for parsing attribute options. //! //! Attribute parsing occurs in multiple stages: //! //! 1. Builder options on the struct are parsed into `OptionsBuilder`. //! 1. The `OptionsBuilder` instance is converted into a starting point for the //! per-field options (`OptionsBuilder`) and the finished struct-level config, //! called `StructOptions`. //! 1. Each struct field is parsed, with discovered attributes overriding or augmenting the //! options specified at the struct level. This creates one `OptionsBuilder` per //! struct field on the input/target type. Once complete, these get converted into //! `FieldOptions` instances. mod darling_opts; pub use self::darling_opts::Options; derive_builder_core-0.12.0/src/options.rs000064400000000000000000000025501046102023000165320ustar 00000000000000/// Controls the signature of a setter method, /// more specifically how `self` is passed and returned. /// /// It can also be generalized to methods with different parameter sets and /// return types, e.g. the `build()` method. #[derive(PartialEq, Eq, Debug, Clone, Copy, FromMeta)] pub enum BuilderPattern { /// E.g. `fn bar(self, bar: Bar) -> Self`. Owned, /// E.g. `fn bar(&mut self, bar: Bar) -> &mut Self`. Mutable, /// E.g. `fn bar(&self, bar: Bar) -> Self`. /// /// Note: /// - Needs to `clone` in order to return an _updated_ instance of `Self`. /// - There is a great chance that the Rust compiler (LLVM) will /// optimize chained `clone` calls away in release mode. /// Therefore this turns out not to be as bad as it sounds. Immutable, } impl BuilderPattern { /// Returns true if this style of builder needs to be able to clone its /// fields during the `build` method. pub fn requires_clone(&self) -> bool { *self != Self::Owned } } /// Defaults to `Mutable`. impl Default for BuilderPattern { fn default() -> Self { Self::Mutable } } #[derive(Debug, Clone, FromMeta)] pub struct Each { pub name: syn::Ident, #[darling(default)] pub into: bool, } impl From for Each { fn from(name: syn::Ident) -> Self { Self { name, into: false } } } derive_builder_core-0.12.0/src/setter.rs000064400000000000000000000512261046102023000163510ustar 00000000000000#![allow(clippy::useless_let_if_seq)] use std::borrow::Cow; use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, TokenStreamExt}; use syn; use BuilderFieldType; use BuilderPattern; use DeprecationNotes; use Each; /// Setter for the struct fields in the build method, implementing /// `quote::ToTokens`. /// /// # Examples /// /// Will expand to something like the following (depending on settings): /// /// ```rust,ignore /// # extern crate proc_macro2; /// # #[macro_use] /// # extern crate quote; /// # extern crate syn; /// # #[macro_use] /// # extern crate derive_builder_core; /// # use derive_builder_core::{Setter, BuilderPattern}; /// # fn main() { /// # let mut setter = default_setter!(); /// # setter.pattern = BuilderPattern::Mutable; /// # /// # assert_eq!(quote!(#setter).to_string(), quote!( /// # #[allow(unused_mut)] /// pub fn foo(&mut self, value: Foo) -> &mut Self { /// let mut new = self; /// new.foo = ::derive_builder::export::core::option::Option::Some(value); /// new /// } /// # ).to_string()); /// # } /// ``` #[derive(Debug, Clone)] pub struct Setter<'a> { /// Path to the root of the derive_builder crate. pub crate_root: &'a syn::Path, /// Enables code generation for this setter fn. pub setter_enabled: bool, /// Enables code generation for the `try_` variant of this setter fn. pub try_setter: bool, /// Visibility of the setter, e.g. `syn::Visibility::Public`. pub visibility: Cow<'a, syn::Visibility>, /// How the setter method takes and returns `self` (e.g. mutably). pub pattern: BuilderPattern, /// Attributes which will be attached to this setter fn. pub attrs: &'a [syn::Attribute], /// Name of this setter fn. pub ident: syn::Ident, /// Name of the target field. pub field_ident: &'a syn::Ident, /// Type of the builder field. /// /// The corresonding builder field will be `Option`. pub field_type: BuilderFieldType<'a>, /// Make the setter generic over `Into`, where `T` is the field type. pub generic_into: bool, /// Make the setter remove the Option wrapper from the setter, remove the need to call Some(...). /// when combined with into, the into is used on the content Type of the Option. pub strip_option: bool, /// Emit deprecation notes to the user. pub deprecation_notes: &'a DeprecationNotes, /// Emit extend method. pub each: Option<&'a Each>, } impl<'a> ToTokens for Setter<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { if self.setter_enabled { let crate_root = self.crate_root; let pattern = self.pattern; let vis = &self.visibility; let field_ident = self.field_ident; let ident = &self.ident; let attrs = self.attrs; let deprecation_notes = self.deprecation_notes; let self_param: TokenStream; let return_ty: TokenStream; let self_into_return_ty: TokenStream; match pattern { BuilderPattern::Owned => { self_param = quote!(self); return_ty = quote!(Self); self_into_return_ty = quote!(self); } BuilderPattern::Mutable => { self_param = quote!(&mut self); return_ty = quote!(&mut Self); self_into_return_ty = quote!(self); } BuilderPattern::Immutable => { self_param = quote!(&self); return_ty = quote!(Self); self_into_return_ty = quote!(#crate_root::export::core::clone::Clone::clone(self)); } }; let ty_params: TokenStream; let param_ty: TokenStream; let mut into_value: TokenStream; let (field_type, builder_field_is_option) = self.field_type.setter_type_info(); let (ty, stripped_option) = { if self.strip_option { match extract_type_from_option(field_type) { Some(ty) => (ty, true), None => (field_type, false), } } else { (field_type, false) } }; if self.generic_into { ty_params = quote!(>); param_ty = quote!(VALUE); into_value = quote!(value.into()); } else { ty_params = quote!(); param_ty = quote!(#ty); into_value = quote!(value); } // If both `stripped_option` and `builder_field_is_option`, the target field is `Option`, // the builder field is `Option>`, and the setter takes `file_type`, so we must wrap it twice. if stripped_option { into_value = wrap_expression_in_some(crate_root, into_value); } if builder_field_is_option { into_value = wrap_expression_in_some(crate_root, into_value); } tokens.append_all(quote!( #(#attrs)* #[allow(unused_mut)] #vis fn #ident #ty_params (#self_param, value: #param_ty) -> #return_ty { #deprecation_notes let mut new = #self_into_return_ty; new.#field_ident = #into_value; new } )); if self.try_setter { let try_ty_params = quote!(>); let try_ident = syn::Ident::new(&format!("try_{}", ident), Span::call_site()); let mut converted = quote! {converted}; if builder_field_is_option { converted = wrap_expression_in_some(crate_root, converted); } tokens.append_all(quote!( #(#attrs)* #vis fn #try_ident #try_ty_params (#self_param, value: VALUE) -> #crate_root::export::core::result::Result<#return_ty, VALUE::Error> { let converted : #ty = value.try_into()?; let mut new = #self_into_return_ty; new.#field_ident = #converted; Ok(new) } )); } if let Some(each) = self.each { let ident_each = &each.name; // Access the collection to extend, initialising with default value if necessary. let get_initialized_collection = if stripped_option { // Outer (builder) Option -> Inner (field) Option -> collection. quote!(get_or_insert_with(|| Some( #crate_root::export::core::default::Default::default() )) .get_or_insert_with(#crate_root::export::core::default::Default::default)) } else { // Outer (builder) Option -> collection. quote!(get_or_insert_with( #crate_root::export::core::default::Default::default )) }; let ty_params: TokenStream; let param_ty: TokenStream; let into_item: TokenStream; if each.into { ty_params = quote!(>); param_ty = quote!(FROM_VALUE); into_item = quote!(#crate_root::export::core::convert::Into::into(item)); } else { ty_params = quote!(); param_ty = quote!(VALUE); into_item = quote!(item); } tokens.append_all(quote!( #(#attrs)* #[allow(unused_mut)] #vis fn #ident_each #ty_params(#self_param, item: #param_ty) -> #return_ty where #ty: #crate_root::export::core::default::Default + #crate_root::export::core::iter::Extend, { #deprecation_notes let mut new = #self_into_return_ty; new.#field_ident .#get_initialized_collection .extend(#crate_root::export::core::option::Option::Some(#into_item)); new } )); } } } } /// Returns expression wrapping `bare_value` in `Some` fn wrap_expression_in_some(crate_root: &syn::Path, bare_value: impl ToTokens) -> TokenStream { quote!( #crate_root::export::core::option::Option::Some(#bare_value) ) } // adapted from https://stackoverflow.com/a/55277337/469066 // Note that since syn is a parser, it works with tokens. // We cannot know for sure that this is an Option. // The user could, for example, `type MaybeString = std::option::Option` // We cannot handle those arbitrary names. fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> { use syn::punctuated::Pair; use syn::token::Colon2; use syn::{GenericArgument, Path, PathArguments, PathSegment}; fn extract_type_path(ty: &syn::Type) -> Option<&Path> { match *ty { syn::Type::Path(ref typepath) if typepath.qself.is_none() => Some(&typepath.path), _ => None, } } // TODO store (with lazy static) precomputed parsing of Option when support of rust 1.18 will be removed (incompatible with lazy_static) // TODO maybe optimization, reverse the order of segments fn extract_option_segment(path: &Path) -> Option> { let idents_of_path = path.segments.iter().fold(String::new(), |mut acc, v| { acc.push_str(&v.ident.to_string()); acc.push('|'); acc }); vec!["Option|", "std|option|Option|", "core|option|Option|"] .into_iter() .find(|s| idents_of_path == *s) .and_then(|_| path.segments.last().map(Pair::End)) } extract_type_path(ty) .and_then(extract_option_segment) .and_then(|pair_path_segment| { let type_params = &pair_path_segment.into_value().arguments; // It should have only on angle-bracketed param (""): match *type_params { PathArguments::AngleBracketed(ref params) => params.args.first(), _ => None, } }) .and_then(|generic_arg| match *generic_arg { GenericArgument::Type(ref ty) => Some(ty), _ => None, }) } /// Helper macro for unit tests. This is _only_ public in order to be accessible /// from doc-tests too. #[doc(hidden)] #[macro_export] macro_rules! default_setter { () => { Setter { // Deliberately don't use the default value here - make sure // that all test cases are passing crate_root through properly. crate_root: &parse_quote!(::db), setter_enabled: true, try_setter: false, visibility: ::std::borrow::Cow::Owned(parse_quote!(pub)), pattern: BuilderPattern::Mutable, attrs: &vec![], ident: syn::Ident::new("foo", ::proc_macro2::Span::call_site()), field_ident: &syn::Ident::new("foo", ::proc_macro2::Span::call_site()), field_type: BuilderFieldType::Optional(Box::leak(Box::new(parse_quote!(Foo)))), generic_into: false, strip_option: false, deprecation_notes: &Default::default(), each: None, } }; } #[cfg(test)] mod tests { #[allow(unused_imports)] use super::*; #[test] fn immutable() { let mut setter = default_setter!(); setter.pattern = BuilderPattern::Immutable; assert_eq!( quote!(#setter).to_string(), quote!( #[allow(unused_mut)] pub fn foo(&self, value: Foo) -> Self { let mut new = ::db::export::core::clone::Clone::clone(self); new.foo = ::db::export::core::option::Option::Some(value); new } ) .to_string() ); } #[test] fn mutable() { let mut setter = default_setter!(); setter.pattern = BuilderPattern::Mutable; assert_eq!( quote!(#setter).to_string(), quote!( #[allow(unused_mut)] pub fn foo(&mut self, value: Foo) -> &mut Self { let mut new = self; new.foo = ::db::export::core::option::Option::Some(value); new } ) .to_string() ); } #[test] fn owned() { let mut setter = default_setter!(); setter.pattern = BuilderPattern::Owned; assert_eq!( quote!(#setter).to_string(), quote!( #[allow(unused_mut)] pub fn foo(self, value: Foo) -> Self { let mut new = self; new.foo = ::db::export::core::option::Option::Some(value); new } ) .to_string() ); } #[test] fn private() { let vis = Cow::Owned(syn::Visibility::Inherited); let mut setter = default_setter!(); setter.visibility = vis; assert_eq!( quote!(#setter).to_string(), quote!( #[allow(unused_mut)] fn foo(&mut self, value: Foo) -> &mut Self { let mut new = self; new.foo = ::db::export::core::option::Option::Some(value); new } ) .to_string() ); } #[test] fn generic() { let mut setter = default_setter!(); setter.generic_into = true; #[rustfmt::skip] assert_eq!( quote!(#setter).to_string(), quote!( #[allow(unused_mut)] pub fn foo>( &mut self, value: VALUE ) -> &mut Self { let mut new = self; new.foo = ::db::export::core::option::Option::Some(value.into()); new } ) .to_string() ); } #[test] fn strip_option() { let ty = parse_quote!(Option); let mut setter = default_setter!(); setter.strip_option = true; setter.field_type = BuilderFieldType::Optional(&ty); #[rustfmt::skip] assert_eq!( quote!(#setter).to_string(), quote!( #[allow(unused_mut)] pub fn foo(&mut self, value: Foo) -> &mut Self { let mut new = self; new.foo = ::db::export::core::option::Option::Some( ::db::export::core::option::Option::Some(value) ); new } ) .to_string() ); } #[test] fn strip_option_into() { let ty = parse_quote!(Option); let mut setter = default_setter!(); setter.strip_option = true; setter.generic_into = true; setter.field_type = BuilderFieldType::Optional(&ty); #[rustfmt::skip] assert_eq!( quote!(#setter).to_string(), quote!( #[allow(unused_mut)] pub fn foo>( &mut self, value: VALUE ) -> &mut Self { let mut new = self; new.foo = ::db::export::core::option::Option::Some( ::db::export::core::option::Option::Some(value.into()) ); new } ) .to_string() ); } // including try_setter #[test] fn full() { //named!(outer_attrs -> Vec, many0!(syn::Attribute::parse_outer)); //let attrs = outer_attrs.parse_str("#[some_attr]").unwrap(); let attrs: Vec = vec![parse_quote!(#[some_attr])]; let mut deprecated = DeprecationNotes::default(); deprecated.push("Some example.".to_string()); let mut setter = default_setter!(); setter.attrs = attrs.as_slice(); setter.generic_into = true; setter.deprecation_notes = &deprecated; setter.try_setter = true; assert_eq!( quote!(#setter).to_string(), quote!( #[some_attr] #[allow(unused_mut)] pub fn foo >(&mut self, value: VALUE) -> &mut Self { #deprecated let mut new = self; new.foo = ::db::export::core::option::Option::Some(value.into()); new } #[some_attr] pub fn try_foo>(&mut self, value: VALUE) -> ::db::export::core::result::Result<&mut Self, VALUE::Error> { let converted : Foo = value.try_into()?; let mut new = self; new.foo = ::db::export::core::option::Option::Some(converted); Ok(new) } ).to_string() ); } #[test] fn no_std() { let mut setter = default_setter!(); setter.pattern = BuilderPattern::Immutable; assert_eq!( quote!(#setter).to_string(), quote!( #[allow(unused_mut)] pub fn foo(&self, value: Foo) -> Self { let mut new = ::db::export::core::clone::Clone::clone(self); new.foo = ::db::export::core::option::Option::Some(value); new } ) .to_string() ); } #[test] fn no_std_generic() { let mut setter = default_setter!(); setter.generic_into = true; #[rustfmt::skip] assert_eq!( quote!(#setter).to_string(), quote!( #[allow(unused_mut)] pub fn foo>( &mut self, value: VALUE ) -> &mut Self { let mut new = self; new.foo = ::db::export::core::option::Option::Some(value.into()); new } ) .to_string() ); } #[test] fn setter_disabled() { let mut setter = default_setter!(); setter.setter_enabled = false; assert_eq!(quote!(#setter).to_string(), quote!().to_string()); } #[test] fn try_setter() { let mut setter: Setter = default_setter!(); setter.pattern = BuilderPattern::Mutable; setter.try_setter = true; #[rustfmt::skip] assert_eq!( quote!(#setter).to_string(), quote!( #[allow(unused_mut)] pub fn foo(&mut self, value: Foo) -> &mut Self { let mut new = self; new.foo = ::db::export::core::option::Option::Some(value); new } pub fn try_foo>( &mut self, value: VALUE ) -> ::db::export::core::result::Result<&mut Self, VALUE::Error> { let converted: Foo = value.try_into()?; let mut new = self; new.foo = ::db::export::core::option::Option::Some(converted); Ok(new) } ) .to_string() ); } #[test] fn extract_type_from_option_on_simple_type() { let ty_foo = parse_quote!(Foo); assert_eq!(extract_type_from_option(&ty_foo), None); for s in vec![ parse_quote!(Option), parse_quote!(std::option::Option), parse_quote!(::std::option::Option), parse_quote!(core::option::Option), parse_quote!(::core::option::Option), ] { assert_eq!(extract_type_from_option(&s), Some(&ty_foo)); } } }