derive_more-0.15.0/CHANGELOG.md010064400017500001750000000046321347675043000141450ustar0000000000000000# Change Log All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## 0.15.0 - 2019-06-08 - Automatic detection of traits needed for `Display` format strings ## 0.14.0 - 2019-02-02 - Added `no_std` support - Suppress `unused_variables` warnings in derives ## 0.13.0 - 2018-10-19 - Updated to `syn` v0.15 - Extended Display-like derives to support custom formats ## 0.12.0 - 2018-09-19 ### Changed - Updated to `syn` v0.14, `quote` v0.6 and `proc-macro2` v0.4 ## 0.11.0 - 2018-05-12 ### Changed - Updated to latest version of `syn` and `quote` ### Fixed - Changed some URLs in the docs so they were correct on crates.io and docs.rs - The `Result` type is now referenced in the derives using its absolute path (`::std::result::Result`) to make sure that the derives don't accidentally use another `Result` type that is in scope. ## 0.10.0 - 2018-03-29 ### Added - Allow deriving of `TryInto` - Allow deriving of `Deref` - Allow deriving of `DerefMut` ## 0.9.0 - 2018-03-18 ### Added - Allow deriving of `Display`, `Binary`, `Octal`, `LowerHex`, `UpperHex`, `LowerExp`, `UpperExp`, `Pointer` - Allow deriving of `Index` - Allow deriving of `IndexMut` ### Fixed - Allow cross crate inlining of derived methods ### Internal changes - Fix most `clippy` warnings ## 0.8.0 - 2018-03-10 ### Added - Allow deriving of `FromStr` ### Changed - Updated to latest version of `syn` and `quote` ## 0.7.1 - 2018-01-25 ### Fixed - Add `#[allow(missing_docs)]` to the Constructor definition ### Internal changes - Run `rustfmt` on the code ## 0.7.0 - 2017-07-25 ### Changed - Changed code to work with newer version of the `syn` library. ## 0.6.2 - 2017-04-23 ### Changed - Deriving `From`, `Into` and `Constructor` now works for empty structs. ## 0.6.1 - 2017-03-08 ### Changed - The `new()` method that is created when deriving `Constructor` is now public. This makes it a lot more useful. ## 0.6.0 - 2017-02-20 ### Added - Derives for `Into`, `Constructor` and `MulAssign`-like ### Changed - `From` is now derived for enum variants with multiple fields. ### Fixed - Derivations now support generics. ## 0.5.0 - 2017-02-02 ### Added - Lots of docs. - Derives for `Neg`-like and `AddAssign`-like. ### Changed - `From` can now be derived for structs with multiple fields. derive_more-0.15.0/Cargo.toml.orig010064400017500001750000000020411347675045400152210ustar0000000000000000[package] name = "derive_more" version = "0.15.0" description = "Adds #[derive(x)] macros for more traits" authors = ["Jelte Fennema "] license = "MIT" repository = "https://github.com/JelteF/derive_more" documentation = "https://jeltef.github.io/derive_more/derive_more/" readme = "README.md" keywords = ["derive", "Add", "From", "Constructor", "implementation"] categories = ["development-tools", "development-tools::procedural-macro-helpers", "no-std"] include = [ "src/**/*.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md", ] autotests = true [lib] name = "derive_more" proc-macro = true [dependencies] lazy_static = "1.3" proc-macro2 = "0.4" quote = "0.6" regex = "1" syn = { version = "0.15", features = ["extra-traits"] } [build-dependencies] rustc_version = "0.2" [badges] travis-ci = { repository = "JelteF/derive_more" } appveyor = { repository = "JelteF/derive_more" } [features] nightly = [] no_std = [] [[test]] name = "no_std" path = "tests/no_std.rs" required-features = ["no_std"] derive_more-0.15.0/Cargo.toml0000644000000031610000000000000114550ustar00# 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 believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "derive_more" version = "0.15.0" authors = ["Jelte Fennema "] include = ["src/**/*.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md"] autotests = true description = "Adds #[derive(x)] macros for more traits" documentation = "https://jeltef.github.io/derive_more/derive_more/" readme = "README.md" keywords = ["derive", "Add", "From", "Constructor", "implementation"] categories = ["development-tools", "development-tools::procedural-macro-helpers", "no-std"] license = "MIT" repository = "https://github.com/JelteF/derive_more" [lib] name = "derive_more" proc-macro = true [[test]] name = "no_std" path = "tests/no_std.rs" required-features = ["no_std"] [dependencies.lazy_static] version = "1.3" [dependencies.proc-macro2] version = "0.4" [dependencies.quote] version = "0.6" [dependencies.regex] version = "1" [dependencies.syn] version = "0.15" features = ["extra-traits"] [build-dependencies.rustc_version] version = "0.2" [features] nightly = [] no_std = [] [badges.appveyor] repository = "JelteF/derive_more" [badges.travis-ci] repository = "JelteF/derive_more" derive_more-0.15.0/LICENSE010064400017500001750000000020701303351202500133140ustar0000000000000000The MIT License (MIT) Copyright (c) 2016 Jelte Fennema 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_more-0.15.0/README.md010064400017500001750000000204321347171412000135760ustar0000000000000000# `derive_more` [![Build Status](https://api.travis-ci.org/JelteF/derive_more.svg?branch=master)](https://travis-ci.org/JelteF/derive_more) [![Latest Version](https://img.shields.io/crates/v/derive_more.svg)](https://crates.io/crates/derive_more) [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://jeltef.github.io/derive_more/derive_more/) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/JelteF/derive_more/master/LICENSE) Rust has lots of builtin traits that are implemented for its basic types, such as [`Add`], [`Not`] or [`From`]. However, when wrapping these types inside your own structs or enums you lose the implementations of these traits and are required to recreate them. This is especially annoying when your own structures are very simple, such as when using the commonly advised newtype pattern (e.g. `MyInt(i32)`). This library tries to remove these annoyances and the corresponding boilerplate code. It does this by allowing you to derive lots of commonly used traits for both structs and enums. ## Example code By using this library the following code just works: ```rust #[macro_use] extern crate derive_more; #[derive(Debug, Eq, PartialEq, From, Add)] struct MyInt(i32); #[derive(Debug, Eq, PartialEq, From, Into, Constructor, Mul)] struct Point2D { x: i32, y: i32, } #[derive(Debug, Eq, PartialEq, From, Add)] enum MyEnum { Int(i32), UnsignedInt(u32), Nothing, } fn main() { let my_11 = MyInt(5) + 6.into(); assert_eq!(MyInt(11), MyInt(5) + 6.into()); assert_eq!(Point2D { x: 5, y: 6 } * 10, (50, 60).into()); assert_eq!((5, 6), Point2D { x: 5, y: 6 }.into()); assert_eq!(Point2D { x: 5, y: 6 }, Point2D::new(5, 6)); assert_eq!(MyEnum::Int(15), (MyEnum::Int(8) + 7.into()).unwrap()) } ``` ## The derivable traits Below are all the traits that you can derive using this library. Some trait derivations are so similar that the further documentation will only show a single one of them. You can recognize these by the "-like" suffix in their name. The trait name before that will be the only one that is used throughout the further documentation. **NOTE**: You still have to derive each trait separately. So `#[derive(Mul)]` doesn't automatically derive `Div` as well. To derive both you should do `#[derive(Mul, Div)]` ### Conversion traits These are traits that are used to convert automatically between types. 1. [`From`] 2. [`Into`] 3. [`FromStr`] 4. [`TryInto`] ### Formatting traits These traits are used for converting a struct to a string in different ways. 1. `Display`-like, contains [`Display`], [`Binary`], [`Octal`], [`LowerHex`], [`UpperHex`], [`LowerExp`], [`UpperExp`], [`Pointer`] ### Operators These are traits that can be used for operator overloading. 1. [`Index`] 2. [`Deref`] 3. `Not`-like, contains [`Not`] and [`Neg`] 4. `Add`-like, contains [`Add`], [`Sub`], [`BitAnd`], [`BitOr`] and [`BitXor`] 5. `Mul`-like, contains [`Mul`], [`Div`], [`Rem`], [`Shr`] and [`Shl`] 6. [`IndexMut`] 7. [`DerefMut`] 8. `AddAssign`-like, contains [`AddAssign`], [`SubAssign`], [`BitAndAssign`], [`BitOrAssign`] and [`BitXorAssign`] 9. `MulAssign`-like, contains [`MulAssign`], [`DivAssign`], [`RemAssign`], [`ShrAssign`] and [`ShlAssign`] ### Static methods These don't derive traits, but derive static methods instead. 1. `Constructor`, this derives a `new` method that can be used as a constructor. This is very basic if you need more customization for your constructor, check out the [`derive-new`] crate. ## Generated code It is important to understand what code gets generated when using one of the derives from this crate. That is why the links below explain what code gets generated for a trait for each group from before. 1. [`#[derive(From)]`](https://jeltef.github.io/derive_more/derive_more/from.html) 2. [`#[derive(Into)]`](https://jeltef.github.io/derive_more/derive_more/into.html) 3. [`#[derive(FromStr)]`](https://jeltef.github.io/derive_more/derive_more/from_str.html) 4. [`#[derive(TryInto)]`](https://jeltef.github.io/derive_more/derive_more/try_into.html) 5. [`#[derive(Display)]`](https://jeltef.github.io/derive_more/derive_more/display.html) 6. [`#[derive(Index)]`](https://jeltef.github.io/derive_more/derive_more/index_op.html) 7. [`#[derive(Deref)]`](https://jeltef.github.io/derive_more/derive_more/deref.html) 8. [`#[derive(Not)]`](https://jeltef.github.io/derive_more/derive_more/not.html) 9. [`#[derive(Add)]`](https://jeltef.github.io/derive_more/derive_more/add.html) 10. [`#[derive(Mul)]`](https://jeltef.github.io/derive_more/derive_more/mul.html) 11. [`#[derive(IndexMut)]`](https://jeltef.github.io/derive_more/derive_more/index_mut.html) 12. [`#[derive(DerefMut)]`](https://jeltef.github.io/derive_more/derive_more/deref_mut.html) 13. [`#[derive(AddAssign)]`](https://jeltef.github.io/derive_more/derive_more/add_assign.html) 14. [`#[derive(MulAssign)]`](https://jeltef.github.io/derive_more/derive_more/mul_assign.html) 15. [`#[derive(Constructor)]`](https://jeltef.github.io/derive_more/derive_more/constructor.html) If you want to be sure what code is generated for your specific type I recommend using the [`cargo-expand`] utility. This will show you your code with all macros and derives expanded. ## Installation This library requires Rust 1.15 or higher, so this needs to be installed. Then add the following to `Cargo.toml`: ```toml [dependencies] derive_more = "0.13.0" ``` And this to the top of your Rust file: ```rust #[macro_use] extern crate derive_more; ``` This crate support `no_std` through the `no_std` feature. So use the following instead if you want to use it in a `no_std` environment. ```toml # Example Cargo.toml [dependencies] derive_more = {version = "0.13.0", default-features = false, features=["no_std"]} ``` [`cargo-expand`]: https://github.com/dtolnay/cargo-expand [`derive-new`]: https://github.com/nrc/derive-new [`From`]: https://doc.rust-lang.org/core/convert/trait.From.html [`Into`]: https://doc.rust-lang.org/core/convert/trait.Into.html [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html [`TryInto`]: https://doc.rust-lang.org/core/convert/trait.TryInto.html [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html [`Binary`]: https://doc.rust-lang.org/std/fmt/trait.Binary.html [`Octal`]: https://doc.rust-lang.org/std/fmt/trait.Octal.html [`LowerHex`]: https://doc.rust-lang.org/std/fmt/trait.LowerHex.html [`UpperHex`]: https://doc.rust-lang.org/std/fmt/trait.UpperHex.html [`LowerExp`]: https://doc.rust-lang.org/std/fmt/trait.LowerExp.html [`UpperExp`]: https://doc.rust-lang.org/std/fmt/trait.UpperExp.html [`Pointer`]: https://doc.rust-lang.org/std/fmt/trait.Pointer.html [`Index`]: https://doc.rust-lang.org/std/ops/trait.Index.html [`Deref`]: https://doc.rust-lang.org/std/ops/trait.Deref.html [`Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html [`Neg`]: https://doc.rust-lang.org/std/ops/trait.Neg.html [`Add`]: https://doc.rust-lang.org/std/ops/trait.Add.html [`Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html [`BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html [`BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html [`BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html [`Mul`]: https://doc.rust-lang.org/std/ops/trait.Mul.html [`Div`]: https://doc.rust-lang.org/std/ops/trait.Div.html [`Rem`]: https://doc.rust-lang.org/std/ops/trait.Rem.html [`Shr`]: https://doc.rust-lang.org/std/ops/trait.Shr.html [`Shl`]: https://doc.rust-lang.org/std/ops/trait.Shl.html [`IndexMut`]: https://doc.rust-lang.org/std/ops/trait.IndexMut.html [`DerefMut`]: https://doc.rust-lang.org/std/ops/trait.DerefMut.html [`AddAssign`]: https://doc.rust-lang.org/std/ops/trait.AddAssign.html [`SubAssign`]: https://doc.rust-lang.org/std/ops/trait.SubAssign.html [`BitAndAssign`]: https://doc.rust-lang.org/std/ops/trait.BitAndAssign.html [`BitOrAssign`]: https://doc.rust-lang.org/std/ops/trait.BitOrAssign.html [`BitXorAssign`]: https://doc.rust-lang.org/std/ops/trait.BitXorAssign.html [`MulAssign`]: https://doc.rust-lang.org/std/ops/trait.MulAssign.html [`DivAssign`]: https://doc.rust-lang.org/std/ops/trait.DivAssign.html [`RemAssign`]: https://doc.rust-lang.org/std/ops/trait.RemAssign.html [`ShrAssign`]: https://doc.rust-lang.org/std/ops/trait.ShrAssign.html [`ShlAssign`]: https://doc.rust-lang.org/std/ops/trait.ShlAssign.html derive_more-0.15.0/src/add_assign_like.rs010064400017500001750000000031341342517241200165550ustar0000000000000000use add_like::{struct_exprs, tuple_exprs}; use proc_macro2::{Span, TokenStream}; use syn::{Data, DeriveInput, Fields, Ident}; use utils::{add_extra_ty_param_bound_op, get_import_root, named_to_vec, unnamed_to_vec}; pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let trait_ident = Ident::new(trait_name, Span::call_site()); let method_name = trait_name.to_string(); #[allow(deprecated)] let method_name = method_name.trim_right_matches("Assign"); let method_name = method_name.to_lowercase(); let method_ident = Ident::new(&(method_name.to_string() + "_assign"), Span::call_site()); let input_type = &input.ident; let generics = add_extra_ty_param_bound_op(&input.generics, &trait_ident); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let exprs = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => tuple_exprs(&unnamed_to_vec(fields), &method_ident), Fields::Named(ref fields) => struct_exprs(&named_to_vec(fields), &method_ident), _ => panic!(format!("Unit structs cannot use derive({})", trait_name)), }, _ => panic!(format!("Only structs can use derive({})", trait_name)), }; let import_root = get_import_root(); quote!( impl#impl_generics #import_root::ops::#trait_ident for #input_type#ty_generics #where_clause { #[inline] fn #method_ident(&mut self, rhs: #input_type#ty_generics) { #(#exprs; )* } } ) } derive_more-0.15.0/src/add_like.rs010064400017500001750000000137461342517241200152230ustar0000000000000000use proc_macro2::{Span, TokenStream}; use quote::ToTokens; use std::iter; use syn::{Data, DataEnum, DeriveInput, Field, Fields, Ident, Index}; use utils::{ add_extra_type_param_bound_op_output, field_idents, get_import_root, named_to_vec, numbered_vars, unnamed_to_vec, }; pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let import_root = get_import_root(); let trait_ident = Ident::new(trait_name, Span::call_site()); let method_name = trait_name.to_lowercase(); let method_ident = Ident::new(&method_name, Span::call_site()); let input_type = &input.ident; let generics = add_extra_type_param_bound_op_output(&input.generics, &trait_ident); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (output_type, block) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => ( quote!(#input_type#ty_generics), tuple_content(input_type, &unnamed_to_vec(fields), &method_ident), ), Fields::Named(ref fields) => ( quote!(#input_type#ty_generics), struct_content(input_type, &named_to_vec(fields), &method_ident), ), _ => panic!(format!("Unit structs cannot use derive({})", trait_name)), }, Data::Enum(ref data_enum) => ( quote!(#import_root::result::Result<#input_type#ty_generics, &'static str>), enum_content(input_type, data_enum, &method_ident), ), _ => panic!(format!( "Only structs and enums can use derive({})", trait_name )), }; quote!( impl#impl_generics #import_root::ops::#trait_ident for #input_type#ty_generics #where_clause { type Output = #output_type; #[inline] fn #method_ident(self, rhs: #input_type#ty_generics) -> #output_type { #block } } ) } fn tuple_content( input_type: &T, fields: &[&Field], method_ident: &Ident, ) -> TokenStream { let exprs = tuple_exprs(fields, method_ident); quote!(#input_type(#(#exprs),*)) } pub fn tuple_exprs(fields: &[&Field], method_ident: &Ident) -> Vec { let mut exprs = vec![]; for i in 0..fields.len() { let i = Index::from(i); // generates `self.0.add(rhs.0)` let expr = quote!(self.#i.#method_ident(rhs.#i)); exprs.push(expr); } exprs } fn struct_content(input_type: &Ident, fields: &[&Field], method_ident: &Ident) -> TokenStream { // It's safe to unwrap because struct fields always have an identifier let exprs = struct_exprs(fields, method_ident); let field_names = field_idents(fields); quote!(#input_type{#(#field_names: #exprs),*}) } pub fn struct_exprs(fields: &[&Field], method_ident: &Ident) -> Vec { let mut exprs = vec![]; for field in fields { // It's safe to unwrap because struct fields always have an identifier let field_id = field.ident.as_ref().unwrap(); // generates `x: self.x.add(rhs.x)` let expr = quote!(self.#field_id.#method_ident(rhs.#field_id)); exprs.push(expr) } exprs } fn enum_content(input_type: &Ident, data_enum: &DataEnum, method_ident: &Ident) -> TokenStream { let import_root = get_import_root(); let mut matches = vec![]; let mut method_iter = iter::repeat(method_ident); for variant in &data_enum.variants { let subtype = &variant.ident; let subtype = quote!(#input_type::#subtype); match variant.fields { Fields::Unnamed(ref fields) => { // The patern that is outputted should look like this: // (Subtype(left_vars), TypePath(right_vars)) => Ok(TypePath(exprs)) let size = unnamed_to_vec(fields).len(); let l_vars = &numbered_vars(size, "l_"); let r_vars = &numbered_vars(size, "r_"); let method_iter = method_iter.by_ref(); let matcher = quote! { (#subtype(#(#l_vars),*), #subtype(#(#r_vars),*)) => { #import_root::result::Result::Ok(#subtype(#(#l_vars.#method_iter(#r_vars)),*)) } }; matches.push(matcher); } Fields::Named(ref fields) => { // The patern that is outputted should look like this: // (Subtype{a: __l_a, ...}, Subtype{a: __r_a, ...} => { // Ok(Subtype{a: __l_a.add(__r_a), ...}) // } let field_vec = named_to_vec(fields); let size = field_vec.len(); let field_names = &field_idents(&field_vec); let l_vars = &numbered_vars(size, "l_"); let r_vars = &numbered_vars(size, "r_"); let method_iter = method_iter.by_ref(); let matcher = quote! { (#subtype{#(#field_names: #l_vars),*}, #subtype{#(#field_names: #r_vars),*}) => { ::std::result::Result::Ok(#subtype{#(#field_names: #l_vars.#method_iter(#r_vars)),*}) } }; matches.push(matcher); } Fields::Unit => { let message = format!("Cannot {}() unit variants", method_ident.to_string()); matches.push(quote!((#subtype, #subtype) => ::std::result::Result::Err(#message))); } } } if data_enum.variants.len() > 1 { // In the strange case where there's only one enum variant this is would be an unreachable // match. let message = format!( "Trying to {} mismatched enum variants", method_ident.to_string() ); matches.push(quote!(_ => ::std::result::Result::Err(#message))); } quote!( match (self, rhs) { #(#matches),* } ) } derive_more-0.15.0/src/constructor.rs010064400017500001750000000035551342516066000160530ustar0000000000000000use proc_macro2::TokenStream; use syn::{Data, DeriveInput, Field, Fields, Ident}; use utils::{field_idents, get_field_types, named_to_vec, numbered_vars, unnamed_to_vec}; /// Provides the hook to expand `#[derive(Constructor)]` into an implementation of `Constructor` pub fn expand(input: &DeriveInput, _: &str) -> TokenStream { let input_type = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let ((body, vars), fields) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { let field_vec = unnamed_to_vec(fields); (tuple_body(input_type, &field_vec), field_vec) } Fields::Named(ref fields) => { let field_vec = named_to_vec(fields); (struct_body(input_type, &field_vec), field_vec) } Fields::Unit => (struct_body(input_type, &[]), vec![]), }, _ => panic!("Only structs can derive a constructor"), }; let original_types = &get_field_types(&fields); quote!{ #[allow(missing_docs)] impl#impl_generics #input_type#ty_generics #where_clause { #[inline] pub fn new(#(#vars: #original_types),*) -> #input_type#ty_generics { #body } } } } fn tuple_body(return_type: &Ident, fields: &[&Field]) -> (TokenStream, Vec) { let vars = &numbered_vars(fields.len(), ""); (quote!(#return_type(#(#vars),*)), vars.clone()) } fn struct_body(return_type: &Ident, fields: &[&Field]) -> (TokenStream, Vec) { let field_names: &Vec = &field_idents(fields).iter().map(|f| (**f).clone()).collect(); let vars = field_names; let ret_vars = field_names.clone(); (quote!(#return_type{#(#field_names: #vars),*}), ret_vars) } derive_more-0.15.0/src/deref.rs010064400017500001750000000043141342516066000145450ustar0000000000000000use proc_macro2::{Span, TokenStream}; use syn::{Data, DeriveInput, Field, Fields, Ident}; use utils::{add_extra_ty_param_bound, named_to_vec, unnamed_to_vec}; /// Provides the hook to expand `#[derive(Index)]` into an implementation of `From` pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let trait_ident = Ident::new(trait_name, Span::call_site()); let trait_path = "e!(::std::ops::#trait_ident); let input_type = &input.ident; let field_vec: Vec<&Field>; let member = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { field_vec = unnamed_to_vec(fields); tuple_from_str(trait_name, &field_vec) } Fields::Named(ref fields) => { field_vec = named_to_vec(fields); struct_from_str(trait_name, &field_vec) } Fields::Unit => panic_one_field(trait_name), }, _ => panic_one_field(trait_name), }; let field_type = &field_vec[0].ty; let generics = add_extra_ty_param_bound(&input.generics, trait_path); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); // let generics = add_extra_ty_param_bound(&input.generics, trait_path); let casted_trait = "e!(<#field_type as #trait_path>); quote!{ impl#impl_generics #trait_path for #input_type#ty_generics #where_clause { type Target = #casted_trait::Target; #[inline] fn deref(&self) -> &Self::Target { #casted_trait::deref(&#member) } } } } fn panic_one_field(trait_name: &str) -> ! { panic!(format!( "Only structs with one field can derive({})", trait_name )) } fn tuple_from_str<'a>(trait_name: &str, fields: &[&'a Field]) -> (TokenStream) { if fields.len() != 1 { panic_one_field(trait_name) }; quote!(self.0) } fn struct_from_str<'a>(trait_name: &str, fields: &[&'a Field]) -> TokenStream { if fields.len() != 1 { panic_one_field(trait_name) }; let field = &fields[0]; let field_ident = &field.ident; quote!(self.#field_ident) } derive_more-0.15.0/src/deref_mut.rs010064400017500001750000000042571342516066000154400ustar0000000000000000use proc_macro2::{Span, TokenStream}; use syn::{Data, DeriveInput, Field, Fields, Ident}; use utils::{add_extra_ty_param_bound, named_to_vec, unnamed_to_vec}; /// Provides the hook to expand `#[derive(Index)]` into an implementation of `From` pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let trait_ident = Ident::new(trait_name, Span::call_site()); let trait_path = "e!(::std::ops::#trait_ident); let input_type = &input.ident; let field_vec: Vec<&Field>; let member = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { field_vec = unnamed_to_vec(fields); tuple_from_str(trait_name, &field_vec) } Fields::Named(ref fields) => { field_vec = named_to_vec(fields); struct_from_str(trait_name, &field_vec) } Fields::Unit => panic_one_field(trait_name), }, _ => panic_one_field(trait_name), }; let field_type = &field_vec[0].ty; let generics = add_extra_ty_param_bound(&input.generics, trait_path); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); // let generics = add_extra_ty_param_bound(&input.generics, trait_path); let casted_trait = "e!(<#field_type as #trait_path>); quote!{ impl#impl_generics #trait_path for #input_type#ty_generics #where_clause { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { #casted_trait::deref_mut(&mut #member) } } } } fn panic_one_field(trait_name: &str) -> ! { panic!(format!( "Only structs with one field can derive({})", trait_name )) } fn tuple_from_str<'a>(trait_name: &str, fields: &[&'a Field]) -> (TokenStream) { if fields.len() != 1 { panic_one_field(trait_name) }; quote!(self.0) } fn struct_from_str<'a>(trait_name: &str, fields: &[&'a Field]) -> TokenStream { if fields.len() != 1 { panic_one_field(trait_name) }; let field = &fields[0]; let field_ident = &field.ident; quote!(self.#field_ident) } derive_more-0.15.0/src/display.rs010064400017500001750000000507211347675035000151370ustar0000000000000000use std::{ collections::{HashMap, HashSet}, fmt::Display, }; use proc_macro2::{Ident, Span, TokenStream}; use regex::Regex; use syn::{ parse::{Error, Result}, punctuated::Pair, spanned::Spanned, Attribute, Data, DeriveInput, Fields, Lit, Meta, MetaNameValue, NestedMeta, Type, }; use utils::{add_extra_where_clauses, get_import_root}; /// Provides the hook to expand `#[derive(Display)]` into an implementation of `From` pub fn expand(input: &DeriveInput, trait_name: &str) -> Result { let import_root = get_import_root(); let trait_ident = Ident::new(trait_name, Span::call_site()); let trait_path = "e!(#import_root::fmt::#trait_ident); let trait_attr = match trait_name { "Display" => "display", "Binary" => "binary", "Octal" => "octal", "LowerHex" => "lower_hex", "UpperHex" => "upper_hex", "LowerExp" => "lower_exp", "UpperExp" => "upper_exp", "Pointer" => "pointer", _ => unimplemented!(), }; let type_params = input .generics .type_params() .map(|t| t.ident.clone()) .collect(); let (arms, bounds) = State { trait_path, trait_attr, input, type_params, } .get_match_arms_and_extra_bounds()?; let generics = if !bounds.is_empty() { let bounds: Vec<_> = bounds .into_iter() .map(|(ty, trait_names)| { let bounds: Vec<_> = trait_names .into_iter() .map(|trait_name| { let import_root = get_import_root(); let trait_ident = Ident::new(trait_name, Span::call_site()); quote!(#import_root::fmt::#trait_ident) }) .collect(); quote!(#ty: #(#bounds)+*) }) .collect(); let where_clause = quote_spanned!(input.span()=> where #(#bounds),*); add_extra_where_clauses(&input.generics, where_clause) } else { input.generics.clone() }; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let name = &input.ident; Ok(quote! { impl #impl_generics #trait_path for #name #ty_generics #where_clause { #[allow(unused_variables)] #[inline] fn fmt(&self, _derive_more_Display_formatter: &mut #import_root::fmt::Formatter) -> #import_root::fmt::Result { match self { #arms _ => Ok(()) // This is needed for empty enums } } } }) } struct State<'a, 'b> { trait_path: &'b TokenStream, trait_attr: &'static str, input: &'a DeriveInput, type_params: HashSet, } impl<'a, 'b> State<'a, 'b> { fn get_proper_syntax(&self) -> impl Display { format!( r#"Proper syntax: #[{}(fmt = "My format", "arg1", "arg2")]"#, self.trait_attr ) } fn get_matcher(&self, fields: &Fields) -> TokenStream { match fields { Fields::Unit => TokenStream::new(), Fields::Unnamed(fields) => { let fields: TokenStream = (0..fields.unnamed.len()) .map(|n| { let i = Ident::new(&format!("_{}", n), Span::call_site()); quote!(#i,) }) .collect(); quote!((#fields)) } Fields::Named(fields) => { let fields: TokenStream = fields .named .iter() .map(|f| { let i = f.ident.as_ref().unwrap(); quote!(#i,) }) .collect(); quote!({#fields}) } } } fn find_meta(&self, attrs: &[Attribute]) -> Result> { let mut it = attrs .iter() .filter_map(Attribute::interpret_meta) .filter(|m| m.name() == self.trait_attr); let meta = it.next(); if it.next().is_some() { Err(Error::new(meta.span(), "Too many formats given")) } else { Ok(meta) } } fn get_meta_fmt(&self, meta: &Meta) -> Result { let list = match meta { Meta::List(list) => list, _ => return Err(Error::new(meta.span(), self.get_proper_syntax())), }; let fmt = match &list.nested[0] { NestedMeta::Meta(Meta::NameValue(MetaNameValue { ident, lit: Lit::Str(s), .. })) if ident == "fmt" => s, _ => return Err(Error::new(list.nested[0].span(), self.get_proper_syntax())), }; let args = list .nested .iter() .skip(1) // skip fmt = "..." .try_fold(TokenStream::new(), |args, arg| { let arg = match arg { NestedMeta::Literal(Lit::Str(s)) => s, NestedMeta::Meta(Meta::Word(i)) => { return Ok(quote_spanned!(list.span()=> #args #i,)); } _ => return Err(Error::new(arg.span(), self.get_proper_syntax())), }; let arg: TokenStream = arg.parse().map_err(|e| Error::new(arg.span(), e))?; Ok(quote_spanned!(list.span()=> #args #arg,)) })?; Ok(quote_spanned!(meta.span()=> write!(_derive_more_Display_formatter, #fmt, #args))) } fn infer_fmt(&self, fields: &Fields, name: &Ident) -> Result { let fields = match fields { Fields::Unit => { return Ok(quote!(write!( _derive_more_Display_formatter, stringify!(#name) ))); } Fields::Named(fields) => &fields.named, Fields::Unnamed(fields) => &fields.unnamed, }; if fields.is_empty() { return Ok(quote!(write!( _derive_more_Display_formatter, stringify!(#name) ))); } else if fields.len() > 1 { return Err(Error::new( fields.span(), "Can not automatically infer format for types with more than 1 field", )); } let trait_path = self.trait_path; if let Some(ident) = &fields.iter().next().as_ref().unwrap().ident { Ok(quote!(#trait_path::fmt(#ident, _derive_more_Display_formatter))) } else { Ok(quote!(#trait_path::fmt(_0, _derive_more_Display_formatter))) } } fn get_match_arms_and_extra_bounds( &self, ) -> Result<(TokenStream, HashMap>)> { match &self.input.data { Data::Enum(e) => { if let Some(meta) = self.find_meta(&self.input.attrs)? { let fmt = self.get_meta_fmt(&meta)?; e.variants.iter().try_for_each(|v| { if let Some(meta) = self.find_meta(&v.attrs)? { Err(Error::new( meta.span(), "Can not have a format on the variant when the whole enum has one", )) } else { Ok(()) } })?; Ok(( quote_spanned!(self.input.span()=> _ => #fmt,), HashMap::new(), )) } else { e.variants.iter().try_fold( (TokenStream::new(), HashMap::new()), |(arms, mut all_bounds), v| { let matcher = self.get_matcher(&v.fields); let name = &self.input.ident; let v_name = &v.ident; let fmt: TokenStream; let bounds: HashMap<_, _>; if let Some(meta) = self.find_meta(&v.attrs)? { fmt = self.get_meta_fmt(&meta)?; bounds = self.get_used_type_params_bounds(&v.fields, &meta); } else { fmt = self.infer_fmt(&v.fields, v_name)?; bounds = self.infer_type_params_bounds(&v.fields); }; all_bounds = bounds.into_iter() .fold(all_bounds, |mut bounds, (ty, trait_names)| { bounds.entry(ty).or_insert_with(HashSet::new).extend(trait_names); bounds }); Ok(( quote_spanned!(self.input.span()=> #arms #name::#v_name #matcher => #fmt,), all_bounds, )) }, ) } } Data::Struct(s) => { let matcher = self.get_matcher(&s.fields); let name = &self.input.ident; let fmt: TokenStream; let bounds: HashMap<_, _>; if let Some(meta) = self.find_meta(&self.input.attrs)? { fmt = self.get_meta_fmt(&meta)?; bounds = self.get_used_type_params_bounds(&s.fields, &meta); } else { fmt = self.infer_fmt(&s.fields, name)?; bounds = self.infer_type_params_bounds(&s.fields); } Ok(( quote_spanned!(self.input.span()=> #name #matcher => #fmt,), bounds, )) } Data::Union(_) => { let meta = self.find_meta(&self.input.attrs)?.ok_or_else(|| { Error::new( self.input.span(), "Can not automatically infer format for unions", ) })?; let fmt = self.get_meta_fmt(&meta)?; Ok(( quote_spanned!(self.input.span()=> _ => #fmt,), HashMap::new(), )) } } } fn get_used_type_params_bounds( &self, fields: &Fields, meta: &Meta, ) -> HashMap> { if self.type_params.is_empty() { return HashMap::new(); } let fields_type_params: HashMap<_, _> = fields .iter() .enumerate() .filter_map(|(i, field)| { if !self.has_type_param_in(field) { return None; } let ident = field .ident .clone() .unwrap_or_else(|| Ident::new(&format!("_{}", i), Span::call_site())); Some((ident, field.ty.clone())) }) .collect(); if fields_type_params.is_empty() { return HashMap::new(); } let list = match meta { Meta::List(list) => list, // This one has been checked already in get_meta_fmt() method. _ => unreachable!(), }; let fmt_args: HashMap<_, _> = list .nested .iter() .skip(1) // skip fmt = "..." .enumerate() .filter_map(|(i, arg)| match arg { NestedMeta::Literal(Lit::Str(ref s)) => { syn::parse_str(&s.value()).ok().map(|id| (i, id)) } NestedMeta::Meta(Meta::Word(ref id)) => Some((i, id.clone())), // This one has been checked already in get_meta_fmt() method. _ => unreachable!(), }) .collect(); if fmt_args.is_empty() { return HashMap::new(); } let fmt_string = match &list.nested[0] { NestedMeta::Meta(Meta::NameValue(MetaNameValue { ident, lit: Lit::Str(s), .. })) if ident == "fmt" => s.value(), // This one has been checked already in get_meta_fmt() method. _ => unreachable!(), }; Placeholder::parse_fmt_string(&fmt_string).into_iter().fold( HashMap::new(), |mut bounds, pl| { if let Some(arg) = fmt_args.get(&pl.position) { if fields_type_params.contains_key(arg) { bounds .entry(fields_type_params[arg].clone()) .or_insert_with(HashSet::new) .insert(pl.trait_name); } } bounds }, ) } fn infer_type_params_bounds(&self, fields: &Fields) -> HashMap> { if self.type_params.is_empty() { return HashMap::new(); } if let Fields::Unit = fields { return HashMap::new(); } // infer_fmt() uses only first field. fields .iter() .take(1) .filter_map(|field| { if !self.has_type_param_in(field) { return None; } Some(( field.ty.clone(), [match self.trait_attr { "display" => "Display", "binary" => "Binary", "octal" => "Octal", "lower_hex" => "LowerHex", "upper_hex" => "UpperHex", "lower_exp" => "LowerExp", "upper_exp" => "UpperExp", "pointer" => "Pointer", _ => unreachable!(), }] .iter() .cloned() .collect(), )) }) .collect() } fn has_type_param_in(&self, field: &syn::Field) -> bool { if let Type::Path(ref ty) = field.ty { return match ty.path.segments.first() { Some(Pair::Punctuated(ref t, _)) => self.type_params.contains(&t.ident), Some(Pair::End(ref t)) => self.type_params.contains(&t.ident), _ => false, }; } false } } lazy_static! { /// Regular expression for parsing formatting placeholders from a string. /// /// Reproduces `maybe-format` expression of [formatting syntax][1]. /// /// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax static ref MAYBE_PLACEHOLDER: Regex = Regex::new( r"(\{\{|}}|(?P\{[^{}]*}))", ).unwrap(); /// Regular expression for parsing inner type of formatting placeholder. /// /// Reproduces `format` expression of [formatting syntax][1], but is simplified /// in the following way (as we need to parse `type` only): /// - `argument` is replaced just with `\d+` (instead of [`identifier`][2]); /// - `character` is allowed to be any symbol. /// /// [1]: https://doc.rust-lang.org/stable/std/fmt/index.html#syntax /// [2]: https://doc.rust-lang.org/reference/identifiers.html#identifiers static ref PLACEHOLDER_FORMAT: Regex = Regex::new( r"^\{(?P\d+)?(:(.?[<^>])?[+-]?#?0?(\w+\$|\d+)?(\.(\w+\$|\d+|\*))?(?P([oxXpbeE?]|[xX]\?)?)?)?}$", ).unwrap(); } /// Representation of formatting placeholder. #[derive(Debug, PartialEq)] struct Placeholder { /// Position of formatting argument to be used for this placeholder. position: usize, /// Name of [`std::fmt`] trait to be used for rendering this placeholder. trait_name: &'static str, } impl Placeholder { /// Parses [`Placeholder`]s from a given formatting string. fn parse_fmt_string(s: &str) -> Vec { let mut n = 0; MAYBE_PLACEHOLDER .captures_iter(s) .filter_map(|cap| cap.name("placeholder")) .map(|m| { let captured = PLACEHOLDER_FORMAT.captures(m.as_str()).unwrap(); let position = captured .name("arg") .map(|s| s.as_str().parse().unwrap()) .unwrap_or_else(|| { // Assign "the next argument". // https://doc.rust-lang.org/stable/std/fmt/index.html#positional-parameters n += 1; n - 1 }); let typ = captured .name("type") .map(|s| s.as_str()) .unwrap_or_default(); let trait_name = match typ { "" => "Display", "?" | "x?" | "X?" => "Debug", "o" => "Octal", "x" => "LowerHex", "X" => "UpperHex", "p" => "Pointer", "b" => "Binary", "e" => "LowerExp", "E" => "UpperExp", _ => unreachable!(), }; Placeholder { position, trait_name, } }) .collect() } } #[cfg(test)] mod regex_maybe_placeholder_spec { use super::*; #[test] fn parses_placeholders_and_omits_escaped() { let fmt_string = "{}, {:?}, {{}}, {{{1:0$}}}"; let placeholders: Vec<_> = MAYBE_PLACEHOLDER .captures_iter(&fmt_string) .filter_map(|cap| cap.name("placeholder")) .map(|m| m.as_str()) .collect(); assert_eq!(placeholders, vec!["{}", "{:?}", "{1:0$}"]); } } #[cfg(test)] mod regex_placeholder_format_spec { use super::*; #[test] fn detects_type() { for (p, expected) in vec![ ("{}", ""), ("{:?}", "?"), ("{:x?}", "x?"), ("{:X?}", "X?"), ("{:o}", "o"), ("{:x}", "x"), ("{:X}", "X"), ("{:p}", "p"), ("{:b}", "b"), ("{:e}", "e"), ("{:E}", "E"), ("{:.*}", ""), ("{8}", ""), ("{:04}", ""), ("{1:0$}", ""), ("{:width$}", ""), ("{9:>8.*}", ""), ("{2:.1$x}", "x"), ] { let typ = PLACEHOLDER_FORMAT .captures(p) .unwrap() .name("type") .map(|s| s.as_str()) .unwrap_or_default(); assert_eq!(typ, expected); } } #[test] fn detects_arg() { for (p, expected) in vec![ ("{}", ""), ("{0:?}", "0"), ("{12:x?}", "12"), ("{3:X?}", "3"), ("{5:o}", "5"), ("{6:x}", "6"), ("{:X}", ""), ("{8}", "8"), ("{:04}", ""), ("{1:0$}", "1"), ("{:width$}", ""), ("{9:>8.*}", "9"), ("{2:.1$x}", "2"), ] { let arg = PLACEHOLDER_FORMAT .captures(p) .unwrap() .name("arg") .map(|s| s.as_str()) .unwrap_or_default(); assert_eq!(arg, expected); } } } #[cfg(test)] mod placeholder_parse_fmt_string_spec { use super::*; #[test] fn indicates_position_and_trait_name_for_each_fmt_placeholder() { let fmt_string = "{},{:?},{{}},{{{1:0$}}}-{2:.1$x}{0:#?}{:width$}"; assert_eq!( Placeholder::parse_fmt_string(&fmt_string), vec![ Placeholder { position: 0, trait_name: "Display", }, Placeholder { position: 1, trait_name: "Debug", }, Placeholder { position: 1, trait_name: "Display", }, Placeholder { position: 2, trait_name: "LowerHex", }, Placeholder { position: 0, trait_name: "Debug", }, Placeholder { position: 2, trait_name: "Display", }, ], ) } } derive_more-0.15.0/src/from.rs010064400017500001750000000117561342517241200144310ustar0000000000000000use std::collections::HashMap; use std::ops::Index; use proc_macro2::TokenStream; use quote::ToTokens; use syn::{Data, DataEnum, DeriveInput, Field, Fields}; use utils::{ field_idents, get_field_types, get_import_root, named_to_vec, number_idents, unnamed_to_vec, }; /// Provides the hook to expand `#[derive(From)]` into an implementation of `From` pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => tuple_from(input, &unnamed_to_vec(fields)), Fields::Named(ref fields) => struct_from(input, &named_to_vec(fields)), Fields::Unit => struct_from(input, &[]), }, Data::Enum(ref data_enum) => enum_from(input, data_enum), _ => panic!(format!( "Only structs and enums can use derive({})", trait_name )), } } pub fn from_impl(input: &DeriveInput, fields: &[&Field], body: T) -> TokenStream { let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let input_type = &input.ident; let original_types = &get_field_types(fields); let import_root = get_import_root(); quote! { impl#impl_generics #import_root::convert::From<(#(#original_types),*)> for #input_type#ty_generics #where_clause { #[allow(unused_variables)] #[inline] fn from(original: (#(#original_types),*)) -> #input_type#ty_generics { #body } } } } fn tuple_from(input: &DeriveInput, fields: &[&Field]) -> TokenStream { let input_type = &input.ident; let body = tuple_body(input_type, fields); from_impl(input, fields, body) } fn tuple_body(return_type: T, fields: &[&Field]) -> TokenStream { if fields.len() == 1 { quote!(#return_type(original)) } else { let field_names = &number_idents(fields.len()); quote!(#return_type(#(original.#field_names),*)) } } fn struct_from(input: &DeriveInput, fields: &[&Field]) -> TokenStream { let input_type = &input.ident; let body = struct_body(input_type, fields); from_impl(input, fields, body) } fn struct_body(return_type: T, fields: &[&Field]) -> TokenStream { if fields.len() == 1 { let field_name = &fields[0].ident; quote!(#return_type{#field_name: original}) } else { let argument_field_names = &number_idents(fields.len()); let field_names = &field_idents(fields); quote!(#return_type{#(#field_names: original.#argument_field_names),*}) } } fn enum_from(input: &DeriveInput, data_enum: &DataEnum) -> TokenStream { let mut type_signature_counts = HashMap::new(); let input_type = &input.ident; for variant in &data_enum.variants { match variant.fields { Fields::Unnamed(ref fields) => { let original_types = unnamed_to_vec(fields).iter().map(|f| &f.ty).collect(); let counter = type_signature_counts.entry(original_types).or_insert(0); *counter += 1; } Fields::Named(ref fields) => { let original_types = named_to_vec(fields).iter().map(|f| &f.ty).collect(); let counter = type_signature_counts.entry(original_types).or_insert(0); *counter += 1; } Fields::Unit => { let counter = type_signature_counts.entry(vec![]).or_insert(0); *counter += 1; } } } let mut tokens = TokenStream::new(); for variant in &data_enum.variants { match variant.fields { Fields::Unnamed(ref fields) => { let field_vec = &unnamed_to_vec(fields); let original_types = get_field_types(field_vec); if *type_signature_counts.index(&original_types) == 1 { let variant_ident = &variant.ident; let body = tuple_body(quote!(#input_type::#variant_ident), field_vec); from_impl(input, field_vec, body).to_tokens(&mut tokens) } } Fields::Named(ref fields) => { let field_vec = &named_to_vec(fields); let original_types = get_field_types(field_vec); if *type_signature_counts.index(&original_types) == 1 { let variant_ident = &variant.ident; let body = struct_body(quote!(#input_type::#variant_ident), field_vec); from_impl(input, field_vec, body).to_tokens(&mut tokens) } } Fields::Unit => { if *type_signature_counts.index(&vec![]) == 1 { let variant_ident = &variant.ident; let body = struct_body(quote!(#input_type::#variant_ident), &[]); from_impl(input, &[], body).to_tokens(&mut tokens) } } } } tokens } derive_more-0.15.0/src/from_str.rs010064400017500001750000000045011342517241200153070ustar0000000000000000use proc_macro2::TokenStream; use syn::{Data, DeriveInput, Field, Fields, Ident, Type}; use utils::{add_extra_ty_param_bound, get_import_root, named_to_vec, unnamed_to_vec}; /// Provides the hook to expand `#[derive(FromStr)]` into an implementation of `From` pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let import_root = get_import_root(); let trait_path = "e!(#import_root::str::FromStr); let generics = add_extra_ty_param_bound(&input.generics, trait_path); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let input_type = &input.ident; let (result, field_type) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { tuple_from_str(input_type, trait_name, &unnamed_to_vec(fields)) } Fields::Named(ref fields) => { struct_from_str(input_type, trait_name, &named_to_vec(fields)) } Fields::Unit => panic_one_field(trait_name), }, _ => panic_one_field(trait_name), }; quote! { impl#impl_generics #trait_path for #input_type#ty_generics #where_clause { type Err = <#field_type as #trait_path>::Err; #[inline] fn from_str(src: &str) -> #import_root::result::Result { return #import_root::result::Result::Ok(#result) } } } } fn panic_one_field(trait_name: &str) -> ! { panic!(format!( "Only structs with one field can derive({})", trait_name )) } fn tuple_from_str<'a>( input_type: &Ident, trait_name: &str, fields: &[&'a Field], ) -> (TokenStream, &'a Type) { if fields.len() != 1 { panic_one_field(trait_name) }; let field = &fields[0]; let field_type = &field.ty; (quote!(#input_type(#field_type::from_str(src)?)), field_type) } fn struct_from_str<'a>( input_type: &Ident, trait_name: &str, fields: &[&'a Field], ) -> (TokenStream, &'a Type) { if fields.len() != 1 { panic_one_field(trait_name) }; let field = &fields[0]; let field_type = &field.ty; let field_ident = &field.ident; ( quote!(#input_type{#field_ident: #field_type::from_str(src)?}), field_type, ) } derive_more-0.15.0/src/index.rs010064400017500001750000000051301342517241200145620ustar0000000000000000use proc_macro2::{Span, TokenStream}; use syn::{Data, DeriveInput, Field, Fields, Ident}; use utils::{add_where_clauses_for_new_ident, get_import_root, named_to_vec, unnamed_to_vec}; /// Provides the hook to expand `#[derive(Index)]` into an implementation of `From` pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let import_root = get_import_root(); let trait_ident = Ident::new(trait_name, Span::call_site()); let index_type = &Ident::new("__IdxT", Span::call_site()); let trait_path = "e!(#import_root::ops::#trait_ident<#index_type>); let input_type = &input.ident; let field_vec: Vec<&Field>; let member = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { field_vec = unnamed_to_vec(fields); tuple_from_str(trait_name, &field_vec) } Fields::Named(ref fields) => { field_vec = named_to_vec(fields); struct_from_str(trait_name, &field_vec) } Fields::Unit => panic_one_field(trait_name), }, _ => panic_one_field(trait_name), }; let field_type = &field_vec[0].ty; let type_where_clauses = quote! { where #field_type: #trait_path }; let new_generics = add_where_clauses_for_new_ident( &input.generics, &field_vec, index_type, type_where_clauses, ); let (impl_generics, _, where_clause) = new_generics.split_for_impl(); let (_, ty_generics, _) = input.generics.split_for_impl(); // let generics = add_extra_ty_param_bound(&input.generics, trait_path); let casted_trait = "e!(<#field_type as #trait_path>); quote! { impl#impl_generics #trait_path for #input_type#ty_generics #where_clause { type Output = #casted_trait::Output; #[inline] fn index(&self, idx: #index_type) -> &Self::Output { #casted_trait::index(&#member, idx) } } } } fn panic_one_field(trait_name: &str) -> ! { panic!(format!( "Only structs with one field can derive({})", trait_name )) } fn tuple_from_str<'a>(trait_name: &str, fields: &[&'a Field]) -> (TokenStream) { if fields.len() != 1 { panic_one_field(trait_name) }; quote!(self.0) } fn struct_from_str<'a>(trait_name: &str, fields: &[&'a Field]) -> TokenStream { if fields.len() != 1 { panic_one_field(trait_name) }; let field = &fields[0]; let field_ident = &field.ident; quote!(self.#field_ident) } derive_more-0.15.0/src/index_mut.rs010064400017500001750000000050741342517241200154560ustar0000000000000000use proc_macro2::{Span, TokenStream}; use syn::{Data, DeriveInput, Field, Fields, Ident}; use utils::{add_where_clauses_for_new_ident, get_import_root, named_to_vec, unnamed_to_vec}; /// Provides the hook to expand `#[derive(IndexMut)]` into an implementation of `From` pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let trait_ident = Ident::new(trait_name, Span::call_site()); let index_type = &Ident::new("__IdxT", Span::call_site()); let import_root = get_import_root(); let trait_path = "e!(#import_root::ops::#trait_ident<#index_type>); let input_type = &input.ident; let field_vec: Vec<&Field>; let member = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { field_vec = unnamed_to_vec(fields); tuple_from_str(trait_name, &field_vec) } Fields::Named(ref fields) => { field_vec = named_to_vec(fields); struct_from_str(trait_name, &field_vec) } Fields::Unit => panic_one_field(trait_name), }, _ => panic_one_field(trait_name), }; let field_type = &field_vec[0].ty; let type_where_clauses = quote!{ where #field_type: #trait_path }; let new_generics = add_where_clauses_for_new_ident( &input.generics, &field_vec, index_type, type_where_clauses, ); let (impl_generics, _, where_clause) = new_generics.split_for_impl(); let (_, ty_generics, _) = input.generics.split_for_impl(); // let generics = add_extra_ty_param_bound(&input.generics, trait_path); let casted_trait = "e!(<#field_type as #trait_path>); quote!{ impl#impl_generics #trait_path for #input_type#ty_generics #where_clause { #[inline] fn index_mut(&mut self, idx: #index_type) -> &mut Self::Output { #casted_trait::index_mut(&mut #member, idx) } } } } fn panic_one_field(trait_name: &str) -> ! { panic!(format!( "Only structs with one field can derive({})", trait_name )) } fn tuple_from_str<'a>(trait_name: &str, fields: &[&'a Field]) -> (TokenStream) { if fields.len() != 1 { panic_one_field(trait_name) }; quote!(self.0) } fn struct_from_str<'a>(trait_name: &str, fields: &[&'a Field]) -> TokenStream { if fields.len() != 1 { panic_one_field(trait_name) }; let field = &fields[0]; let field_ident = &field.ident; quote!(self.#field_ident) } derive_more-0.15.0/src/into.rs010064400017500001750000000035311342517241200144270ustar0000000000000000use proc_macro2::TokenStream; use quote::ToTokens; use syn::{Data, DeriveInput, Field, Fields}; use utils::{ field_idents, get_field_types, get_import_root, named_to_vec, number_idents, unnamed_to_vec, }; /// Provides the hook to expand `#[derive(Into)]` into an implementation of `Into` pub fn expand(input: &DeriveInput, _: &str) -> TokenStream { let input_type = &input.ident; let field_vec: Vec<_>; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let (field_names, fields) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { field_vec = unnamed_to_vec(fields); (tuple_field_names(&field_vec), field_vec) } Fields::Named(ref fields) => { field_vec = named_to_vec(fields); (struct_field_names(&field_vec), field_vec) } Fields::Unit => (vec![], vec![]), }, _ => panic!("Only structs can derive Into"), }; let original_types = &get_field_types(&fields); let import_root = get_import_root(); quote! { impl#impl_generics #import_root::convert::From<#input_type#ty_generics> for (#(#original_types),*) #where_clause { #[allow(unused_variables)] #[inline] fn from(original: #input_type#ty_generics) -> (#(#original_types),*) { (#(original.#field_names),*) } } } } fn tuple_field_names(fields: &[&Field]) -> Vec { number_idents(fields.len()) .iter() .map(|f| f.into_token_stream()) .collect() } fn struct_field_names(fields: &[&Field]) -> Vec { field_idents(fields) .iter() .map(|f| (*f).into_token_stream()) .collect() } derive_more-0.15.0/src/lib.rs010064400017500001750000000300311347675035000142300ustar0000000000000000//! # `derive_more` //! Rust has lots of builtin traits that are implemented for its basic types, such as [`Add`], //! [`Not`] or [`From`]. //! However, when wrapping these types inside your own structs or enums you lose the //! implementations of these traits and are required to recreate them. //! This is especially annoying when your own structures are very simple, such as when using the //! commonly advised newtype pattern (e.g. `MyInt(i32)`). //! //! This library tries to remove these annoyances and the corresponding boilerplate code. //! It does this by allowing you to derive lots of commonly used traits for both structs and enums. //! //! ## Example code //! //! By using this library the following code just works: //! //! //! ```rust //! #[macro_use] //! extern crate derive_more; //! //! #[derive(Debug, Eq, PartialEq, From, Add)] //! struct MyInt(i32); //! //! #[derive(Debug, Eq, PartialEq, From, Into, Constructor, Mul)] //! struct Point2D { //! x: i32, //! y: i32, //! } //! //! #[derive(Debug, Eq, PartialEq, From, Add)] //! enum MyEnum { //! Int(i32), //! UnsignedInt(u32), //! Nothing, //! } //! //! fn main() { //! let my_11 = MyInt(5) + 6.into(); //! assert_eq!(MyInt(11), MyInt(5) + 6.into()); //! assert_eq!(Point2D { x: 5, y: 6 } * 10, (50, 60).into()); //! assert_eq!((5, 6), Point2D { x: 5, y: 6 }.into()); //! assert_eq!(Point2D { x: 5, y: 6 }, Point2D::new(5, 6)); //! assert_eq!(MyEnum::Int(15), (MyEnum::Int(8) + 7.into()).unwrap()) //! } //! ``` //! //! ## The derivable traits //! //! Below are all the traits that you can derive using this library. //! Some trait derivations are so similar that the further documentation will only show a single one //! of them. //! You can recognize these by the "-like" suffix in their name. //! The trait name before that will be the only one that is used throughout the further //! documentation. //! //! **NOTE**: You still have to derive each trait separately. So `#[derive(Mul)]` doesn't //! automatically derive `Div` as well. To derive both you should do `#[derive(Mul, Div)]` //! //! ### Conversion traits //! These are traits that are used to convert automatically between types. //! //! 1. [`From`] //! 2. [`Into`] //! 3. [`FromStr`] //! 4. [`TryInto`] //! //! ### Formatting traits //! These traits are used for converting a struct to a string in different ways. //! //! 1. `Display`-like, contains [`Display`], [`Binary`], [`Octal`], [`LowerHex`], [`UpperHex`], //! [`LowerExp`], [`UpperExp`], [`Pointer`] //! //! ### Operators //! These are traits that can be used for operator overloading. //! //! 1. [`Index`] //! 2. [`Deref`] //! 3. `Not`-like, contains [`Not`] and [`Neg`] //! 4. `Add`-like, contains [`Add`], [`Sub`], [`BitAnd`], [`BitOr`] and [`BitXor`] //! 5. `Mul`-like, contains [`Mul`], [`Div`], [`Rem`], [`Shr`] and [`Shl`] //! 6. [`IndexMut`] //! 7. [`DerefMut`] //! 8. `AddAssign`-like, contains [`AddAssign`], [`SubAssign`], [`BitAndAssign`], [`BitOrAssign`] //! and [`BitXorAssign`] //! 9. `MulAssign`-like, contains [`MulAssign`], [`DivAssign`], [`RemAssign`], [`ShrAssign`] and //! [`ShlAssign`] //! //! ### Static methods //! These don't derive traits, but derive static methods instead. //! //! 1. `Constructor`, this derives a `new` method that can be used as a constructor. This is very //! basic if you need more customization for your constructor, check out the [`derive-new`] crate. //! //! //! ## Generated code //! //! It is important to understand what code gets generated when using one of the derives from this //! crate. //! That is why the links below explain what code gets generated for a trait for each group from //! before. //! //! 1. [`#[derive(From)]`](https://jeltef.github.io/derive_more/derive_more/from.html) //! 2. [`#[derive(Into)]`](https://jeltef.github.io/derive_more/derive_more/into.html) //! 3. [`#[derive(FromStr)]`](https://jeltef.github.io/derive_more/derive_more/from_str.html) //! 4. [`#[derive(TryInto)]`](https://jeltef.github.io/derive_more/derive_more/try_into.html) //! 5. [`#[derive(Display)]`](https://jeltef.github.io/derive_more/derive_more/display.html) //! 6. [`#[derive(Index)]`](https://jeltef.github.io/derive_more/derive_more/index_op.html) //! 7. [`#[derive(Deref)]`](https://jeltef.github.io/derive_more/derive_more/deref.html) //! 8. [`#[derive(Not)]`](https://jeltef.github.io/derive_more/derive_more/not.html) //! 9. [`#[derive(Add)]`](https://jeltef.github.io/derive_more/derive_more/add.html) //! 10. [`#[derive(Mul)]`](https://jeltef.github.io/derive_more/derive_more/mul.html) //! 11. [`#[derive(IndexMut)]`](https://jeltef.github.io/derive_more/derive_more/index_mut.html) //! 12. [`#[derive(DerefMut)]`](https://jeltef.github.io/derive_more/derive_more/deref_mut.html) //! 13. [`#[derive(AddAssign)]`](https://jeltef.github.io/derive_more/derive_more/add_assign.html) //! 14. [`#[derive(MulAssign)]`](https://jeltef.github.io/derive_more/derive_more/mul_assign.html) //! 15. [`#[derive(Constructor)]`](https://jeltef.github.io/derive_more/derive_more/constructor.html) //! //! If you want to be sure what code is generated for your specific type I recommend using the //! [`cargo-expand`] utility. //! This will show you your code with all macros and derives expanded. //! //! ## Installation //! //! This library requires Rust 1.15 or higher, so this needs to be installed. //! Then add the following to `Cargo.toml`: //! //! ```toml //! [dependencies] //! derive_more = "0.13.0" //! ``` //! //! And this to the top of your Rust file: //! //! ```rust //! #[macro_use] //! extern crate derive_more; //! # fn main () {} //! ``` //! //!This crate support `no_std` through the `no_std` feature. So use the following //!instead if you want to use it in a `no_std` environment. //! //!```toml //!# Example Cargo.toml //![dependencies] //!derive_more = {version = "0.13.0", default-features = false, features=["no_std"]} //!``` //! //! [`cargo-expand`]: https://github.com/dtolnay/cargo-expand //! [`derive-new`]: https://github.com/nrc/derive-new //! [`From`]: https://doc.rust-lang.org/core/convert/trait.From.html //! [`Into`]: https://doc.rust-lang.org/core/convert/trait.Into.html //! [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html //! [`TryInto`]: https://doc.rust-lang.org/core/convert/trait.TryInto.html //! [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html //! [`Binary`]: https://doc.rust-lang.org/std/fmt/trait.Binary.html //! [`Octal`]: https://doc.rust-lang.org/std/fmt/trait.Octal.html //! [`LowerHex`]: https://doc.rust-lang.org/std/fmt/trait.LowerHex.html //! [`UpperHex`]: https://doc.rust-lang.org/std/fmt/trait.UpperHex.html //! [`LowerExp`]: https://doc.rust-lang.org/std/fmt/trait.LowerExp.html //! [`UpperExp`]: https://doc.rust-lang.org/std/fmt/trait.UpperExp.html //! [`Pointer`]: https://doc.rust-lang.org/std/fmt/trait.Pointer.html //! [`Index`]: https://doc.rust-lang.org/std/ops/trait.Index.html //! [`Deref`]: https://doc.rust-lang.org/std/ops/trait.Deref.html //! [`Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html //! [`Neg`]: https://doc.rust-lang.org/std/ops/trait.Neg.html //! [`Add`]: https://doc.rust-lang.org/std/ops/trait.Add.html //! [`Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html //! [`BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html //! [`BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html //! [`BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html //! [`Mul`]: https://doc.rust-lang.org/std/ops/trait.Mul.html //! [`Div`]: https://doc.rust-lang.org/std/ops/trait.Div.html //! [`Rem`]: https://doc.rust-lang.org/std/ops/trait.Rem.html //! [`Shr`]: https://doc.rust-lang.org/std/ops/trait.Shr.html //! [`Shl`]: https://doc.rust-lang.org/std/ops/trait.Shl.html //! [`IndexMut`]: https://doc.rust-lang.org/std/ops/trait.IndexMut.html //! [`DerefMut`]: https://doc.rust-lang.org/std/ops/trait.DerefMut.html //! [`AddAssign`]: https://doc.rust-lang.org/std/ops/trait.AddAssign.html //! [`SubAssign`]: https://doc.rust-lang.org/std/ops/trait.SubAssign.html //! [`BitAndAssign`]: https://doc.rust-lang.org/std/ops/trait.BitAndAssign.html //! [`BitOrAssign`]: https://doc.rust-lang.org/std/ops/trait.BitOrAssign.html //! [`BitXorAssign`]: https://doc.rust-lang.org/std/ops/trait.BitXorAssign.html //! [`MulAssign`]: https://doc.rust-lang.org/std/ops/trait.MulAssign.html //! [`DivAssign`]: https://doc.rust-lang.org/std/ops/trait.DivAssign.html //! [`RemAssign`]: https://doc.rust-lang.org/std/ops/trait.RemAssign.html //! [`ShrAssign`]: https://doc.rust-lang.org/std/ops/trait.ShrAssign.html //! [`ShlAssign`]: https://doc.rust-lang.org/std/ops/trait.ShlAssign.html #![recursion_limit = "128"] #[macro_use] extern crate lazy_static; extern crate proc_macro; extern crate proc_macro2; #[macro_use] extern crate quote; extern crate regex; extern crate syn; use proc_macro::TokenStream; use syn::parse::Error as ParseError; mod utils; mod add_assign_like; mod add_like; mod constructor; mod deref; mod deref_mut; mod display; mod from; mod from_str; mod index; mod index_mut; mod into; mod mul_assign_like; mod mul_like; mod not_like; mod try_into; // This trait describes the possible return types of // the derives. A derive can generally be infallible and // return a TokenStream, or it can be fallible and return // a Result. trait Output { fn process(self) -> TokenStream; } impl Output for proc_macro2::TokenStream { fn process(self) -> TokenStream { self.into() } } impl Output for Result { fn process(self) -> TokenStream { match self { Ok(ts) => ts.into(), Err(e) => e.to_compile_error().into(), } } } macro_rules! create_derive( ($mod_:ident, $trait_:ident, $fn_name: ident $(,$attribute:ident)*) => { #[proc_macro_derive($trait_, attributes($($attribute),*))] #[doc(hidden)] pub fn $fn_name(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); Output::process($mod_::expand(&ast, stringify!($trait_))) } } ); create_derive!(from, From, from_derive); create_derive!(into, Into, into_derive); create_derive!(constructor, Constructor, constructor_derive); create_derive!(not_like, Not, not_derive); create_derive!(not_like, Neg, neg_derive); create_derive!(add_like, Add, add_derive); create_derive!(add_like, Sub, sub_derive); create_derive!(add_like, BitAnd, bit_and_derive); create_derive!(add_like, BitOr, bit_or_derive); create_derive!(add_like, BitXor, bit_xor_derive); create_derive!(mul_like, Mul, mul_derive); create_derive!(mul_like, Div, div_derive); create_derive!(mul_like, Rem, rem_derive); create_derive!(mul_like, Shr, shr_derive); create_derive!(mul_like, Shl, shl_derive); create_derive!(add_assign_like, AddAssign, add_assign_derive); create_derive!(add_assign_like, SubAssign, sub_assign_derive); create_derive!(add_assign_like, BitAndAssign, bit_and_assign_derive); create_derive!(add_assign_like, BitOrAssign, bit_or_assign_derive); create_derive!(add_assign_like, BitXorAssign, bit_xor_assign_derive); create_derive!(mul_assign_like, MulAssign, mul_assign_derive); create_derive!(mul_assign_like, DivAssign, div_assign_derive); create_derive!(mul_assign_like, RemAssign, rem_assign_derive); create_derive!(mul_assign_like, ShrAssign, shr_assign_derive); create_derive!(mul_assign_like, ShlAssign, shl_assign_derive); create_derive!(from_str, FromStr, from_str_derive); create_derive!(display, Display, display_derive, display); create_derive!(display, Binary, binary_derive, binary); create_derive!(display, Octal, octal_derive, octal); create_derive!(display, LowerHex, lower_hex_derive, lower_hex); create_derive!(display, UpperHex, upper_hex_derive, upper_hex); create_derive!(display, LowerExp, lower_exp_derive, lower_exp); create_derive!(display, UpperExp, upper_exp_derive, upper_exp); create_derive!(display, Pointer, pointer_derive, pointer); create_derive!(index, Index, index_derive); create_derive!(index_mut, IndexMut, index_mut_derive); create_derive!(try_into, TryInto, try_into_derive); create_derive!(deref, Deref, deref_derive); create_derive!(deref_mut, DerefMut, deref_mut_derive); derive_more-0.15.0/src/mul_assign_like.rs010064400017500001750000000045331342517241200166260ustar0000000000000000use mul_like::{struct_exprs, tuple_exprs}; use proc_macro2::{Span, TokenStream}; use std::collections::HashSet; use std::iter; use syn::{Data, DeriveInput, Fields, Ident}; use utils::{ add_where_clauses_for_new_ident, get_field_types_iter, get_import_root, named_to_vec, unnamed_to_vec, }; pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let import_root = get_import_root(); let trait_ident = Ident::new(trait_name, Span::call_site()); let trait_path = "e!(#import_root::ops::#trait_ident); let method_name = trait_name.to_string(); #[allow(deprecated)] let method_name = method_name.trim_right_matches("Assign"); let method_name = method_name.to_lowercase(); let method_ident = Ident::new(&(method_name.to_string() + "_assign"), Span::call_site()); let input_type = &input.ident; let (exprs, fields) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { let field_vec = unnamed_to_vec(fields); (tuple_exprs(&field_vec, &method_ident), field_vec) } Fields::Named(ref fields) => { let field_vec = named_to_vec(fields); (struct_exprs(&field_vec, &method_ident), field_vec) } _ => panic!(format!("Unit structs cannot use derive({})", trait_name)), }, _ => panic!(format!("Only structs can use derive({})", trait_name)), }; let scalar_ident = &Ident::new("__RhsT", Span::call_site()); let tys: &HashSet<_> = &get_field_types_iter(&fields).collect(); let scalar_iter = iter::repeat(scalar_ident); let trait_path_iter = iter::repeat(trait_path); let type_where_clauses = quote! { where #(#tys: #trait_path_iter<#scalar_iter>),* }; let new_generics = add_where_clauses_for_new_ident(&input.generics, &fields, scalar_ident, type_where_clauses); let (impl_generics, _, where_clause) = new_generics.split_for_impl(); let (_, ty_generics, _) = input.generics.split_for_impl(); quote!( impl#impl_generics #trait_path<#scalar_ident> for #input_type#ty_generics #where_clause{ #[inline] fn #method_ident(&mut self, rhs: #scalar_ident#ty_generics) { #(#exprs; )* } } ) } derive_more-0.15.0/src/mul_like.rs010064400017500001750000000064431342517241200152640ustar0000000000000000use proc_macro2::{Span, TokenStream}; use quote::ToTokens; use std::collections::HashSet; use std::iter; use syn::{Data, DeriveInput, Field, Fields, Ident}; use utils::{ add_where_clauses_for_new_ident, field_idents, get_field_types_iter, get_import_root, named_to_vec, number_idents, unnamed_to_vec, }; pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let import_root = get_import_root(); let trait_ident = Ident::new(trait_name, Span::call_site()); let trait_path = "e!(#import_root::ops::#trait_ident); let method_name = trait_name.to_lowercase(); let method_ident = &Ident::new(&method_name, Span::call_site()); let input_type = &input.ident; let (block, fields) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => { let field_vec = unnamed_to_vec(fields); ( tuple_content(input_type, &field_vec, method_ident), field_vec, ) } Fields::Named(ref fields) => { let field_vec = named_to_vec(fields); ( struct_content(input_type, &field_vec, method_ident), field_vec, ) } _ => panic!(format!("Unit structs cannot use derive({})", trait_name)), }, _ => panic!(format!("Only structs can use derive({})", trait_name)), }; let scalar_ident = &Ident::new("__RhsT", Span::call_site()); let tys: &HashSet<_> = &get_field_types_iter(&fields).collect(); let tys2 = tys; let scalar_iter = iter::repeat(scalar_ident); let trait_path_iter = iter::repeat(trait_path); let type_where_clauses = quote! { where #(#tys: #trait_path_iter<#scalar_iter, Output=#tys2>),* }; let new_generics = add_where_clauses_for_new_ident(&input.generics, &fields, scalar_ident, type_where_clauses); let (impl_generics, _, where_clause) = new_generics.split_for_impl(); let (_, ty_generics, _) = input.generics.split_for_impl(); quote!( impl#impl_generics #trait_path<#scalar_ident> for #input_type#ty_generics #where_clause { type Output = #input_type#ty_generics; #[inline] fn #method_ident(self, rhs: #scalar_ident) -> #input_type#ty_generics { #block } } ) } fn tuple_content<'a, T: ToTokens>( input_type: &T, fields: &[&'a Field], method_ident: &Ident, ) -> TokenStream { let exprs = tuple_exprs(fields, method_ident); quote!(#input_type(#(#exprs),*)) } pub fn tuple_exprs(fields: &[&Field], method_ident: &Ident) -> Vec { number_idents(fields.len()) .iter() .map(|i| quote!(self.#i.#method_ident(rhs))) .collect() } fn struct_content<'a, T: ToTokens>( input_type: &T, fields: &[&'a Field], method_ident: &Ident, ) -> TokenStream { let exprs = struct_exprs(fields, method_ident); let field_names = field_idents(fields); quote!(#input_type{#(#field_names: #exprs),*}) } pub fn struct_exprs(fields: &[&Field], method_ident: &Ident) -> Vec { field_idents(fields) .iter() .map(|f| quote!(self.#f.#method_ident(rhs))) .collect() } derive_more-0.15.0/src/not_like.rs010064400017500001750000000133531347171250400152700ustar0000000000000000use proc_macro2::{Span, TokenStream}; use quote::ToTokens; use std::iter; use syn::{Data, DataEnum, DeriveInput, Field, Fields, Ident, Index}; use utils::{add_extra_type_param_bound_op_output, get_import_root, named_to_vec, unnamed_to_vec}; pub fn expand(input: &DeriveInput, trait_name: &str) -> TokenStream { let import_root = get_import_root(); let trait_ident = Ident::new(trait_name, Span::call_site()); let method_name = trait_name.to_lowercase(); let method_ident = &Ident::new(&method_name, Span::call_site()); let input_type = &input.ident; let generics = add_extra_type_param_bound_op_output(&input.generics, &trait_ident); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (output_type, block) = match input.data { Data::Struct(ref data_struct) => match data_struct.fields { Fields::Unnamed(ref fields) => ( quote!(#input_type#ty_generics), tuple_content(input_type, &unnamed_to_vec(fields), method_ident), ), Fields::Named(ref fields) => ( quote!(#input_type#ty_generics), struct_content(input_type, &named_to_vec(fields), method_ident), ), _ => panic!(format!("Unit structs cannot use derive({})", trait_name)), }, Data::Enum(ref data_enum) => enum_output_type_and_content(input, data_enum, method_ident), _ => panic!(format!( "Only structs and enums can use derive({})", trait_name )), }; quote!( impl#impl_generics #import_root::ops::#trait_ident for #input_type#ty_generics #where_clause { type Output = #output_type; #[inline] fn #method_ident(self) -> #output_type { #block } } ) } fn tuple_content( input_type: &T, fields: &[&Field], method_ident: &Ident, ) -> TokenStream { let mut exprs = vec![]; for i in 0..fields.len() { let i = Index::from(i); // generates `self.0.add()` let expr = quote!(self.#i.#method_ident()); exprs.push(expr); } quote!(#input_type(#(#exprs),*)) } fn struct_content(input_type: &Ident, fields: &[&Field], method_ident: &Ident) -> TokenStream { let mut exprs = vec![]; for field in fields { // It's safe to unwrap because struct fields always have an identifier let field_id = field.ident.as_ref(); // generates `x: self.x.not()` let expr = quote!(#field_id: self.#field_id.#method_ident()); exprs.push(expr) } quote!(#input_type{#(#exprs),*}) } fn enum_output_type_and_content( input: &DeriveInput, data_enum: &DataEnum, method_ident: &Ident, ) -> (TokenStream, TokenStream) { let input_type = &input.ident; let (_, ty_generics, _) = input.generics.split_for_impl(); let mut matches = vec![]; let mut method_iter = iter::repeat(method_ident); // If the enum contains unit types that means it can error. let has_unit_type = data_enum.variants.iter().any(|v| v.fields == Fields::Unit); for variant in &data_enum.variants { let subtype = &variant.ident; let subtype = quote!(#input_type::#subtype); match variant.fields { Fields::Unnamed(ref fields) => { // The patern that is outputted should look like this: // (Subtype(vars)) => Ok(TypePath(exprs)) let size = unnamed_to_vec(fields).len(); let vars: &Vec<_> = &(0..size) .map(|i| Ident::new(&format!("__{}", i), Span::call_site())) .collect(); let method_iter = method_iter.by_ref(); let mut body = quote!(#subtype(#(#vars.#method_iter()),*)); if has_unit_type { body = quote!(::std::result::Result::Ok(#body)) } let matcher = quote! { #subtype(#(#vars),*) => { #body } }; matches.push(matcher); } Fields::Named(ref fields) => { // The patern that is outputted should look like this: // (Subtype{a: __l_a, ...} => { // Ok(Subtype{a: __l_a.neg(__r_a), ...}) // } let field_vec = named_to_vec(fields); let size = field_vec.len(); let field_names: &Vec<_> = &field_vec .iter() .map(|f| f.ident.as_ref().unwrap()) .collect(); let vars: &Vec<_> = &(0..size) .map(|i| Ident::new(&format!("__{}", i), Span::call_site())) .collect(); let method_iter = method_iter.by_ref(); let mut body = quote!(#subtype{#(#field_names: #vars.#method_iter()),*}); if has_unit_type { body = quote!(::std::result::Result::Ok(#body)) } let matcher = quote! { #subtype{#(#field_names: #vars),*} => { #body } }; matches.push(matcher); } Fields::Unit => { let message = format!("Cannot {}() unit variants", method_ident.to_string()); matches.push(quote!(#subtype => ::std::result::Result::Err(#message))); } } } let body = quote!( match self { #(#matches),* } ); let output_type = if has_unit_type { quote!(::std::result::Result<#input_type#ty_generics, &'static str>) } else { quote!(#input_type#ty_generics) }; (output_type, body) } derive_more-0.15.0/src/try_into.rs010064400017500001750000000065351347171250400153370ustar0000000000000000use proc_macro2::TokenStream; use quote::ToTokens; use std::collections::HashMap; use syn::{Data, DataEnum, DeriveInput, Fields}; use utils::{field_idents, named_to_vec, numbered_vars, unnamed_to_vec}; /// Provides the hook to expand `#[derive(TryInto)]` into an implementation of `TryInto` pub fn expand(input: &DeriveInput, _: &str) -> TokenStream { match input.data { Data::Enum(ref data_enum) => enum_try_into(input, data_enum), _ => panic!("Only enums can derive TryInto"), } } fn enum_try_into(input: &DeriveInput, data_enum: &DataEnum) -> TokenStream { let mut variants_per_types = HashMap::new(); let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let input_type = &input.ident; for variant in &data_enum.variants { let original_types = match variant.fields { Fields::Unnamed(ref fields) => unnamed_to_vec(fields).iter().map(|f| &f.ty).collect(), Fields::Named(ref fields) => named_to_vec(fields).iter().map(|f| &f.ty).collect(), Fields::Unit => vec![], }; variants_per_types .entry(original_types) .or_insert_with(Vec::new) .push(variant); } let mut tokens = TokenStream::new(); for (ref original_types, ref variants) in variants_per_types { let mut matchers = vec![]; let vars = &numbered_vars(original_types.len(), ""); for variant in variants.iter() { let subtype = &variant.ident; let subtype = quote!(#input_type::#subtype); matchers.push(match variant.fields { Fields::Unnamed(_) => quote!(#subtype(#(#vars),*)), Fields::Named(ref fields) => { let field_vec = &named_to_vec(fields); let field_names = &field_idents(field_vec); quote!(#subtype{#(#field_names: #vars),*}) } Fields::Unit => quote!(#subtype), }); } let vars = if vars.len() == 1 { quote!(#(#vars)*) } else { quote!((#(#vars),*)) }; let output_type = if original_types.len() == 1 { format!("{}", quote!(#(#original_types)*)) } else { let types = original_types .iter() .map(|t| format!("{}", quote!(#t))) .collect::>(); format!("({})", types.join(", ")) }; let variants = variants .iter() .map(|v| format!("{}", v.ident)) .collect::>() .join(", "); let message = format!("Only {} can be converted to {}", variants, output_type); let try_from = quote!{ impl#impl_generics ::std::convert::TryFrom<#input_type#ty_generics> for (#(#original_types),*) #where_clause { type Error = &'static str; #[allow(unused_variables)] #[inline] fn try_from(value: #input_type#ty_generics) -> ::std::result::Result { match value { #(#matchers)|* => ::std::result::Result::Ok(#vars), _ => ::std::result::Result::Err(#message), } } } }; try_from.to_tokens(&mut tokens) } tokens } derive_more-0.15.0/src/utils.rs010064400017500001750000000066641347675034300146430ustar0000000000000000use proc_macro2::{Span, TokenStream}; use syn::{ parse_str, Field, FieldsNamed, FieldsUnnamed, GenericParam, Generics, Ident, Index, Type, TypeParamBound, WhereClause, }; pub fn get_import_root() -> TokenStream { #[cfg(not(feature = "no_std"))] return quote!(::std); #[cfg(feature = "no_std")] return quote!(::core); } pub fn numbered_vars(count: usize, prefix: &str) -> Vec { (0..count) .map(|i| Ident::new(&format!("__{}{}", prefix, i), Span::call_site())) .collect() } pub fn number_idents(count: usize) -> Vec { (0..count).map(Index::from).collect() } pub fn field_idents<'a>(fields: &'a [&'a Field]) -> Vec<&'a Ident> { fields .iter() .map(|f| { f.ident .as_ref() .expect("Tried to get field names of a tuple struct") }) .collect() } pub fn get_field_types_iter<'a>( fields: &'a [&'a Field], ) -> Box + 'a> { Box::new(fields.iter().map(|f| &f.ty)) } pub fn get_field_types<'a>(fields: &'a [&'a Field]) -> Vec<&'a Type> { get_field_types_iter(fields).collect() } pub fn add_extra_type_param_bound_op_output<'a>( generics: &'a Generics, trait_ident: &'a Ident, ) -> Generics { let mut generics = generics.clone(); for type_param in &mut generics.type_params_mut() { let type_ident = &type_param.ident; let bound: TypeParamBound = parse_str("e!(::std::ops::#trait_ident).to_string()).unwrap(); type_param.bounds.push(bound) } generics } pub fn add_extra_ty_param_bound_op<'a>(generics: &'a Generics, trait_ident: &'a Ident) -> Generics { add_extra_ty_param_bound(generics, "e!(::std::ops::#trait_ident)) } pub fn add_extra_ty_param_bound<'a>(generics: &'a Generics, bound: &'a TokenStream) -> Generics { let mut generics = generics.clone(); let bound: TypeParamBound = parse_str(&bound.to_string()).unwrap(); for type_param in &mut generics.type_params_mut() { type_param.bounds.push(bound.clone()) } generics } pub fn add_extra_generic_param(generics: &Generics, generic_param: TokenStream) -> Generics { let generic_param: GenericParam = parse_str(&generic_param.to_string()).unwrap(); let mut generics = generics.clone(); generics.params.push(generic_param); generics } pub fn add_extra_where_clauses(generics: &Generics, type_where_clauses: TokenStream) -> Generics { let mut type_where_clauses: WhereClause = parse_str(&type_where_clauses.to_string()).unwrap(); let mut new_generics = generics.clone(); if let Some(old_where) = new_generics.where_clause { type_where_clauses.predicates.extend(old_where.predicates) } new_generics.where_clause = Some(type_where_clauses); new_generics } pub fn add_where_clauses_for_new_ident<'a>( generics: &'a Generics, fields: &[&'a Field], type_ident: &Ident, type_where_clauses: TokenStream, ) -> Generics { let generic_param = if fields.len() > 1 { quote!(#type_ident: ::std::marker::Copy) } else { quote!(#type_ident) }; let generics = add_extra_where_clauses(generics, type_where_clauses); add_extra_generic_param(&generics, generic_param) } pub fn unnamed_to_vec(fields: &FieldsUnnamed) -> Vec<&Field> { fields.unnamed.iter().collect() } pub fn named_to_vec(fields: &FieldsNamed) -> Vec<&Field> { fields.named.iter().collect() } derive_more-0.15.0/.cargo_vcs_info.json0000644000000001120000000000000134500ustar00{ "git": { "sha1": "fac273aa6d6e358bbd96c670c02b487a8d7976f1" } }