default_struct_builder/lib.rs
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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
//! Generates builder methods of every field of a struct. It is meant to be used on structs that
//! implement `Default`. There is no separate builder struct generated and no need to call a
//! `build()` method at the end or `.unwrap()`.
//!
//! This crate is used by the crate `leptos-use` for the option structs that
//! can be passed to the various functions.
//!
//! ## Installation
//!
//! In your project folder run
//!
//! ```sh
//! cargo add default-struct-builder
//! ```
//!
//! ## Usage
//!
//! It is very easy to use:
//!
//! ```
//! use default_struct_builder::DefaultBuilder;
//!
//! #[derive(DefaultBuilder, Default)]
//! pub struct SomeOptions {
//! throttle: f64,
//!
//! #[builder(into)]
//! offset: Option<f64>,
//!
//! #[builder(skip)]
//! not_included: u32,
//! }
//! ```
//!
//! you can then use the struct like this:
//!
//! ```
//! # use default_struct_builder::DefaultBuilder;
//! #
//! # #[derive(DefaultBuilder, Default)]
//! # pub struct SomeOptions {
//! # throttle: f64,
//! #
//! # #[builder(into)]
//! # offset: Option<f64>,
//! #
//! # #[builder(skip)]
//! # not_included: u32,
//! # }
//! #
//! # fn main() {
//! let options = SomeOptions::default().offset(4.0);
//!
//! assert_eq!(options.offset, Some(4.0));
//! assert_eq!(options.throttle, 0.0);
//! assert_eq!(options.not_included, 0);
//! # }
//! ```
//!
//! ### Generics
//!
//! The macro is ready to be used on generic structs.
//!
//! ```
//! use default_struct_builder::DefaultBuilder;
//!
//! #[derive(DefaultBuilder, Default)]
//! pub struct SomeOptions<T>
//! where
//! T: Default,
//! {
//! some_field: T,
//! }
//! ```
//!
//! ### Doc comments
//!
//! All doc comments on fields are directly passed on to their generated setter methods.
//!
//! ## How it works
//!
//! The derive macro generates the following code:
//!
//! ```
//! # #[derive(Default)]
//! # pub struct SomeOptions {
//! # throttle: f64,
//! # offset: Option<f64>,
//! # not_included: u32,
//! # }
//! #
//! impl SomeOptions {
//! // setter methods are given that consume `self` and return a new `Self` with the field value changed
//! pub fn throttle(self, value: f64) -> Self {
//! Self {
//! throttle: value,
//! ..self
//! }
//! }
//!
//! // because `into` was specified this method is generic and calls `.into()` when setting the value
//! pub fn offset<T>(self, value: T) -> Self
//! where
//! T: Into<Option<f64>>,
//! {
//! Self {
//! offset: value.into(),
//! ..self
//! }
//! }
//!
//! // no method for field `not_included` because `skip` was specified
//! }
//! ```
//!
//! ### Generics
//!
//! In the case of a generic field the generated method is a bit more complex because by calling
//! the method the type of the type parameter can be different than before.
//!
//! Let's look at the following example.
//!
//! ```
//! use default_struct_builder::DefaultBuilder;
//!
//! #[derive(DefaultBuilder, Default)]
//! pub struct SomeOptions<T>
//! where
//! T: Default,
//! {
//! some_field: T,
//! other_field: i16,
//! }
//!
//! impl SomeOptions<f32> {
//! pub fn new() -> Self {
//! Self {
//! some_field: 42.0,
//! other_field: 0,
//! }
//! }
//! }
//! #
//! # fn main() {
//! # let options = SomeOptions::new().some_field("string");
//! # }
//! ```
//!
//! This generates the setter method below.
//!
//! ```
//! # pub struct SomeOptions<T>
//! # where
//! # T: Default,
//! # {
//! # some_field: T,
//! # other_field: i16,
//! # }
//! #
//! # impl SomeOptions<f32> {
//! # pub fn new() -> Self {
//! # Self {
//! # some_field: 42.0,
//! # other_field: 0,
//! # }
//! # }
//! # }
//! #
//! impl<T> SomeOptions<T>
//! where
//! T: Default,
//! {
//! pub fn some_field<NewT>(self, value: NewT) -> SomeOptions<NewT>
//! where
//! NewT: Default,
//! {
//! SomeOptions::<NewT> {
//! some_field: value,
//! other_field: self.other_field,
//! }
//! }
//! }
//!
//! fn main() {
//! let options = SomeOptions::new() // at first SomeOptions<f32>
//! .some_field("string"); // changed to SomeOptions<&str>
//! }
//! ```
//!
//! In cases where you don't want a generic field to be able to change the generic type you
//! can annotate it with `keep_type`.
//!
//! ```
//! # use default_struct_builder::DefaultBuilder;
//! #
//! #[derive(DefaultBuilder)]
//! struct SomeOptions<T> {
//! #[builder(keep_type)]
//! the_field: T,
//! }
//! ```
//!
//! this will generate a standard builder method as if `T` wasn't generic.
//!
//! ### `Box`, `Rc` and `Arc`
//!
//! The macro detects if a field is a `Box` (or `Rc` or `Arc`) and generates a builder method that
//! accepts the inner type (without `Box` or `Rc` or `Arc`) and adds the outer type in the body.
//!
//! In case it's a `Box<dyn Trait>` the builder method will have an argument of type
//! `impl Trait`. The same goes for `Rc` and `Arc`.
//!
//! If you want to prevent this auto un-wrapping you can use the `#[builder(keep_outer)]` attribute.
//!
//! ```
//! # use std::rc::Rc;
//! # use default_struct_builder::DefaultBuilder;
//! #
//! trait Test {}
//!
//! #[derive(DefaultBuilder)]
//! struct SomeOptions {
//! the_field: Box<dyn Test>,
//! other_field: Rc<String>,
//!
//! #[builder(keep_outer)]
//! keep: Box<String>,
//! }
//! ```
//!
//! This will generate the following code:
//!
//! ```
//! # use std::rc::Rc;
//! # use default_struct_builder::DefaultBuilder;
//! #
//! # trait Test {}
//! #
//! # struct SomeOptions {
//! # the_field: Box<dyn Test>,
//! # other_field: Rc<String>,
//! # keep: Box<String>,
//! # }
//! #
//! impl SomeOptions {
//! pub fn the_field(self, value: impl Test + 'static) -> Self {
//! Self {
//! the_field: Box::new(value),
//! ..self
//! }
//! }
//!
//! pub fn other_field(self, value: String) -> Self {
//! Self {
//! other_field: Rc::new(value),
//! ..self
//! }
//! }
//!
//! pub fn keep(self, value: Box<String>) -> Self {
//! Self {
//! keep: value,
//! ..self
//! }
//! }
//! }
//! ```
//!
//!
//! ## Related Work
//!
//! For more general purposes please check out the much more powerful
//! [`derive_builder` crate](https://github.com/colin-kiegel/rust-derive-builder).
mod builder;
use builder::DefaultBuilderDeriveInput;
use darling::FromDeriveInput;
use proc_macro::TokenStream;
use quote::ToTokens;
use syn::parse_macro_input;
#[proc_macro_derive(DefaultBuilder, attributes(builder))]
pub fn derive_builder(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as syn::DeriveInput);
let data = DefaultBuilderDeriveInput::from_derive_input(&input);
let stream = match data {
Ok(data) => data.into_token_stream(),
Err(err) => err.write_errors(),
};
stream.into()
}