1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
//! # Typed Builder //! //! This crate provides a custom derive for `TypedBuilder`. `TypedBuilder` is not a real type - //! deriving it will generate a `::builder()` method on your struct that will return a compile-time //! checked builder. Set the fields using setters with the same name as the struct's fields that //! accept `Into` types for the type of the field, and call `.build()` when you are done to create //! your object. //! //! Trying to set the same fields twice will generate a compile-time error. Trying to build without //! setting one of the fields will also generate a compile-time error - unless that field is marked //! as `#[default]`, in which case the `::default()` value of it's type will be picked. If you want //! to set a different default, use `#[default="..."]` - note that it has to be encoded in a //! string, so `1` is `#[default="1"]` and `"hello"` is `#[default="\"hello\""]`. //! //! # Examples //! //! ``` //! #[macro_use] //! extern crate typed_builder; //! //! #[derive(PartialEq, TypedBuilder)] //! struct Foo { //! // Mandatory Field: //! x: i32, //! //! // #[default] without parameter - use the type's default //! #[default] //! y: Option<i32>, //! //! // Or you can set the default(encoded as string) //! #[default="20"] //! z: i32, //! } //! //! fn main() { //! assert!( //! Foo::builder().x(1).y(2).z(3).build() //! == Foo { x: 1, y: Some(2), z: 3 }); //! //! // Change the order of construction: //! assert!( //! Foo::builder().z(1).x(2).y(3).build() //! == Foo { x: 2, y: Some(3), z: 1 }); //! //! // Optional fields are optional: //! assert!( //! Foo::builder().x(1).build() //! == Foo { x: 1, y: None, z: 20 }); //! //! // This will not compile - because we did not set x: //! // Foo::builder().build(); //! //! // This will not compile - because we set y twice: //! // Foo::builder().x(1).y(2).y(3); //! } //! ``` extern crate proc_macro; extern crate syn; #[macro_use] extern crate quote; use proc_macro::TokenStream; mod util; mod field_info; mod struct_info; #[doc(hidden)] #[proc_macro_derive(TypedBuilder, attributes(default))] pub fn derive_typed_builder(input: TokenStream) -> TokenStream { let ast = syn::parse_derive_input(&input.to_string()).unwrap(); impl_my_derive(&ast).parse().unwrap() } fn impl_my_derive(ast: &syn::DeriveInput) -> quote::Tokens { match ast.body { syn::Body::Struct(syn::VariantData::Struct(ref body)) => { let struct_info = struct_info::StructInfo::new(&ast, body); let builder_creation = struct_info.builder_creation_impl(); let conversion_helper = struct_info.conversion_helper_impl(); let fields = struct_info.fields.iter().map(|f| struct_info.field_impl(f)); let build_method = struct_info.build_method_impl(); quote!{ #builder_creation #conversion_helper #( #fields )* #build_method } }, syn::Body::Struct(syn::VariantData::Unit) => panic!("SmartBuilder is not supported for unit types"), syn::Body::Struct(syn::VariantData::Tuple(_)) => panic!("SmartBuilder is not supported for tuples"), syn::Body::Enum(_) => panic!("SmartBuilder is not supported for enums"), } }