From be7b42427e246e7f927e34831a8d99a2df417b5b Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 3 Nov 2024 19:05:18 +0000 Subject: [PATCH 01/16] Add custom methods documentation --- bon/Cargo.toml | 40 +-- .../typestate-api/builders-type-signature.md | 2 +- .../src/guide/typestate-api/custom-methods.md | 292 +++++++++++++++++- 3 files changed, 294 insertions(+), 40 deletions(-) diff --git a/bon/Cargo.toml b/bon/Cargo.toml index 71f42c6a..49dcc9cd 100644 --- a/bon/Cargo.toml +++ b/bon/Cargo.toml @@ -63,44 +63,8 @@ alloc = [] default = ["std"] std = ["alloc"] -# Opts in to the higher MSRV 1.79.0. In this version, Rust stabilized the syntax -# for bounds in associated type position which can be used to make bounds on generic -# associated types implied. See the release announcement for more: -# https://blog.rust-lang.org/2024/06/13/Rust-1.79.0.htmlbounds-in-associated-type-position -# -# This feature is useful for the trait `IsComplete` generated by the builder macros. -# When this feature is enabled, the builder macros use the new syntax for bounds in -# associated type position, which enables implied `IsSet` bounds for the type state -# of required members. -# -# To understand how this can be used consider the following example: -# -# ```rust -# #[derive(bon::Builder)] -# struct Example { -# a: u32, -# b: Option, -# } -# -# use example_builder::{IsUnset, IsComplete}; -# -# impl ExampleBuilder { -# fn build_with_default_b(self) -> Example -# where -# State: IsComplete, -# State::B: IsUnset, -# { -# self.b(42).build() -# } -# } -# ``` -# -# This code wouldn't compile without this feature enabled, because `State: IsComplete` -# wouldn't automatically imply `State::A: IsSet`, so the builder type state returned -# after `self.b()` doesn't imply that the member `a` is set, and thus `build()` -# can't be called. -# -# Huge thanks to @harudagondi for suggesting the name of this cargo feature! +# See the explanation of what this feature does in the docs here: +# https://bon-rs.com/guide/typestate-api/custom-methods#implied-bounds implied-bounds = ["bon-macros/implied-bounds"] # 🔬 Experimental! There may be breaking changes to this feature between *minor* releases, diff --git a/website/src/guide/typestate-api/builders-type-signature.md b/website/src/guide/typestate-api/builders-type-signature.md index db40d891..39d66cbf 100644 --- a/website/src/guide/typestate-api/builders-type-signature.md +++ b/website/src/guide/typestate-api/builders-type-signature.md @@ -108,4 +108,4 @@ If there is a mix of named and anonymous lifetimes or named generic types and `i Now you know the mechanics of how a builder's type is built, so you can denote it when it's returned from a function or stored in a struct. -However, to be able to write useful custom methods on the builder, you'll need to know the `trait`s behind the type states. Go to the next page to learn more. +However, to be able to write useful custom methods on the builder, you'll need to know the traits behind the type states. Go to the next page to learn more. diff --git a/website/src/guide/typestate-api/custom-methods.md b/website/src/guide/typestate-api/custom-methods.md index 15b8acc6..cf56635f 100644 --- a/website/src/guide/typestate-api/custom-methods.md +++ b/website/src/guide/typestate-api/custom-methods.md @@ -1,4 +1,294 @@ # Custom Methods +On this page, you'll learn how to add custom methods to the builder type 💪. -- TODO: add custom methods to the builder type 💪 +This page assumes you've read the previous [Builder's Type Signature](./builders-type-signature) page. If you haven't already, please do. + +## `State` and `IsUnset` traits + +When a builder transitions from one type state to another, the compiler must ensure the transition is valid. For example, once a setter is called, calling it again must not be possible. + +The generated builder's state module contains a trait called `IsUnset`, which is used to restrict the possible typestates when calling a setter. + +There is also a trait called `State`, that stores the type states for every member of the builder in its associated types. + +Enough talking, let's see how it works in practice. + +```rust +use bon::Builder; + +#[derive(Builder)] +struct Example { + x1: u32, +} +``` + +This code generates the following setters: + +```rust ignore +// Import traits and type states from the generated module +use example_builder::{State, IsUnset, SetX1}; + +impl ExampleBuilder { + fn x1(self, value: u32) -> ExampleBuilder> + where // [!code highlight] + S::X1: IsUnset // [!code highlight] + { /**/ } +} +``` + +The main thing here is `where S::X1: IsUnset`. This `where` bound allows only the typestates that don't contain `SetX1<...>` anywhere in the layers of state transitions. In this case, only `Empty` typestate implements `S::X1: IsUnset`. + +If we were to have other members, their `Set{OtherMember}` transitions would also implement `S::X1: IsUnset` unless the underlying `S` contains a `SetX1` somewhere in it. + +## Custom Setters + +Now that you know the `State` and `IsUnset` traits you can write a custom `impl` block for the builder that defines custom setters. + +```rust +use bon::Builder; + +#[derive(Builder)] +struct Example { + // Make the default generated setter private, and rename + // it so it doesn't collide with our custom method name + #[builder(setters(vis = "", name = x1_internal))] + x1: u32 +} + +use example_builder::{State, IsUnset, SetX1}; + +impl ExampleBuilder { + fn x1(self, value: u32) -> ExampleBuilder> + where + S::X1: IsUnset, + { + self.x1_internal(value * 2) + } +} + +let value = Example::builder() + .x1(3) + .build(); + +assert_eq!(value.x1, 6); +``` + +This is a simple example of how you can write a custom setter. + +You could achieve the same with a [Custom Conversion](../basics/custom-conversions) via `#[builder(with)]`. However, the beauty of this design is that the `impl` block has no magic macros involved. It's rather simple and easy to read. + +Also, with this approach, you can make the setter `unsafe`, `async` or even let it set several members. + +### Set Several Members In One Setter + +I recommend you try doing this yourself to test your intuition of the typestate API. + +The goal is to make the following work: + +```rust compile_fail +use bon::Builder; + +#[derive(Builder)] +struct Example { + x1: u32, + x2: u32, +} + +let value = Example::builder() + .x1_and_x2(1, 2) + .build(); + +assert_eq!(value.x1, 1); +assert_eq!(value.x2, 2); +``` + +::: details Expand to see the solution 👀 + +```rust +use bon::Builder; + +#[derive(Builder)] +struct Example { + #[builder(setters(vis = ""))] // [!code focus] + x1: u32, // [!code focus] + + #[builder(setters(vis = ""))] // [!code focus] + x2: u32, // [!code focus] +} + +use example_builder::{State, IsUnset, SetX1, SetX2}; // [!code focus] + // [!code focus] +impl ExampleBuilder { // [!code focus] + fn x1_and_x2(self, x1: u32, x2: u32) -> ExampleBuilder>> // [!code focus] + where // [!code focus] + S::X1: IsUnset, // [!code focus] + S::X2: IsUnset, // [!code focus] + { // [!code focus] + self.x1(x1).x2(x2) // [!code focus] + } // [!code focus] +} // [!code focus] + + +let value = Example::builder() + .x1_and_x2(1, 2) + .build(); + +assert_eq!(value.x1, 1); +assert_eq!(value.x2, 2); +``` + +Pay attention that the type state in the return type of the setter is `SetX2>`. If you mess it up, the compiler error will help you by showing the exact type of the typestate there. + +For example, when first writing this solution I mistakenly wrote `SetX2`, and the compiler was helpful enough to correct me: + +```rust ignore +self.x1(x1).x2(x2) +^^^^^^^^^^^^^^^^^^ expected `ExampleBuilder>`, + found `ExampleBuilder>>` +``` + +::: + +## `IsSet` trait + +There is a counterpart to the `IsUnset` trait called `IsSet`. Ideally, we'd use negative trait impls and have `!IsSet` syntax, but this language feature is [not stable yet](https://github.com/rust-lang/rust/issues/68318). Therefore, `IsSet` and `IsUnset` are two separate traits, and they are implemented for mutually exclusive type states. + +By the name of the `IsSet` trait, you've already probably figured out that it is implemented for type states where a particular member was set. This is useful for trait bounds on the finishing function. It must be callable only when all required members are set. + +Let's see how it *could* work in practice before we discuss the `IsComplete` trait. + +```rust +use bon::Builder; + +#[derive(Builder)] +struct Example { + x1: u32, + x2: Option, +} +``` + +This code *could* generate the following finishing function: + +```rust ignore +use example_builder::{State, IsSet}; + +impl ExampleBuilder { + fn build(self) -> Example + where + S::X1: IsSet, + { /**/ } +} +``` + +Notice how the `build` method requires only `x1` to be set. It doesn't care if `x2` was set or not, because `x2` is optional. + +This `where S::X1: IsSet` is the core pillar of type safety. This way, the `build()` method knows it is always called with `x1` set and it doesn't have to do runtime validations: no `Result`, no `panic!()`. + +## `IsComplete` trait + +The problem with the approach described higher that uses only the `IsSet` trait is that the number of bounds in the `where` clause of the finishing function grows with the number of required members. + +Why is this a problem? Imagine you'd want to write a function, that accepts a closure that takes and returns a builder with all required members filled. + +```rust +use bon::Builder; + +#[derive(Builder)] +struct ExampleParams { + x1: u32, + x2: u32, + x3: Option, +} + +// Our goal is to have this API +example(|builder| builder.x1(1).x2(2)); + +// Below is how we could achieve this + +// Import traits from the generated module +use example_params_builder::{State, IsSet}; + +fn example(f: impl FnOnce(ExampleParamsBuilder) -> ExampleParamsBuilder) +where + S: State, + S::X1: IsSet, // [!code highlight] + S::X2: IsSet, // [!code highlight] +{ + let builder = f(ExampleParams::builder()); + let params = builder.build(); +} +``` + +This doesn't scale well, because you need to write `S::{Member}: IsSet` for every required member. So, `where` bounds here are coupled with the number of required members and their names. + +You can simplify this code by using the trait `IsComplete`. This trait is defined literally like this in the generated code: + +```rust ignore +trait IsComplete: State {} + +impl IsComplete for S +where + S::X1: IsSet, + S::X2: IsSet, +{} +``` + +Thus, instead of writing `S::{Member}: IsSet` you can write a single bound `S: IsComplete`: + +```rust ignore +fn example(/**/) +where + S: State, + S::X1: IsSet, // [!code --] + S::X2: IsSet, // [!code --] + S: IsComplete // [!code ++] +``` + +## Implied Bounds + +Rust `1.79.0` added [associated trait bounds](https://blog.rust-lang.org/2024/06/13/Rust-1.79.0.htmlbounds-in-associated-type-position) syntax, which can be used to make bounds on generic associated types implied. + +This feature is useful for the trait `IsComplete`. If you enable the `implied-bounds` cargo feature, builder macros use the new syntax for bounds in +associated type position, which enables implied `IsSet` bounds for the type state +of required members. + +The definition of the trait `IsComplete` changes like this: + +```rust ignore +trait IsComplete: State {} // [!code --] +trait IsComplete: State {} // [!code ++] +``` + +To understand how this is useful consider the following example: + +```rust +#[derive(bon::Builder)] +struct Example { + x1: u32, + x2: Option, +} + +use example_builder::{IsUnset, IsComplete}; + +impl ExampleBuilder { + fn build_with_default_x2(self) -> Example + where + State: IsComplete, + State::X2: IsUnset, + { + self.x2(42).build() + } +} +``` + +This code wouldn't compile without the `implied-bounds` cargo feature enabled. Without it, `State: IsComplete` +doesn't automatically imply `State::X1: IsSet`, so the builder type state returned +after `self.x2()` doesn't imply that the member `x1` is set, and thus `build()` +can't be called. + +This is implemented as a cargo feature to make sure `bon` maintains a lower MSRV by default. If you need this, then enable this in your `Cargo.toml`, but beware that it increases your MSRV to `1.79.0`: + +```toml +bon = { version = "..." , features = ["implied-bounds"] } +``` From 000c58203120eb26f47dfd08238ceeaa3f5c9219 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 3 Nov 2024 19:29:51 +0000 Subject: [PATCH 02/16] Add `state_mod` docs --- bon-macros/src/builder/builder_gen/models.rs | 5 ++- website/src/reference/builder.md | 1 + .../src/reference/builder/member/setters.md | 6 +++ .../builder/top-level/builder_type.md | 10 +++-- .../reference/builder/top-level/finish_fn.md | 6 +++ .../reference/builder/top-level/start_fn.md | 6 +++ .../reference/builder/top-level/state_mod.md | 42 ++++++++++++++++++- 7 files changed, 70 insertions(+), 6 deletions(-) diff --git a/bon-macros/src/builder/builder_gen/models.rs b/bon-macros/src/builder/builder_gen/models.rs index d2d1f82e..c0d5c667 100644 --- a/bon-macros/src/builder/builder_gen/models.rs +++ b/bon-macros/src/builder/builder_gen/models.rs @@ -291,7 +291,10 @@ impl BuilderGenCtx { .map(SpannedKey::into_value) .unwrap_or_else(|| { let docs = format!( - "Tools for manipulating the type state of [`{}`].", + "Tools for manipulating the type state of [`{}`].\n\ + \n\ + See the [detailed guide](https://bon-rs.com/guide/typestate-api) \ + that describes how all the pieces here fit together.", builder_type.ident ); diff --git a/website/src/reference/builder.md b/website/src/reference/builder.md index 48a5b1b6..848de166 100644 --- a/website/src/reference/builder.md +++ b/website/src/reference/builder.md @@ -18,6 +18,7 @@ These attributes are placed on top of a `struct` or `fn` declaration. | [`finish_fn`](./builder/top-level/finish_fn) | Overrides name, visibility and docs for the finishing function | [`on`](./builder/top-level/on) | Applies member attributes to all members matching a type pattern | [`start_fn`](./builder/top-level/start_fn) | Overrides name, visibility and docs for the starting function +| [`state_mod`](./builder/top-level/state_mod) | Overrides name, visibility and docs for the builder's [typestate API](../guide/typestate-api) module ## Member Attributes diff --git a/website/src/reference/builder/member/setters.md b/website/src/reference/builder/member/setters.md index cfdd1279..b0e2ad7a 100644 --- a/website/src/reference/builder/member/setters.md +++ b/website/src/reference/builder/member/setters.md @@ -82,3 +82,9 @@ The default visibility is the same as the visibility of the [`builder_type`](../ ## `doc` Simple documentation is generated by default. The syntax of this attribute expects a block with doc comments. + +```attr +doc { + /// Doc comments +} +``` diff --git a/website/src/reference/builder/top-level/builder_type.md b/website/src/reference/builder/top-level/builder_type.md index 8ee1c999..7270d199 100644 --- a/website/src/reference/builder/top-level/builder_type.md +++ b/website/src/reference/builder/top-level/builder_type.md @@ -1,7 +1,3 @@ ---- -outline: deep ---- - # `builder_type` **Applies to:** @@ -53,6 +49,12 @@ The default visibility is the same as the visibility of the underlying `struct` Simple documentation is generated by default. The syntax of this attribute expects a block with doc comments. +```attr +doc { + /// Doc comments +} +``` + ## Examples ::: code-group diff --git a/website/src/reference/builder/top-level/finish_fn.md b/website/src/reference/builder/top-level/finish_fn.md index dc57ee0b..578daf6a 100644 --- a/website/src/reference/builder/top-level/finish_fn.md +++ b/website/src/reference/builder/top-level/finish_fn.md @@ -51,6 +51,12 @@ The default visibility is the same as the visibility of the [`builder_type`](./b Simple documentation is generated by default. The syntax of this attribute expects a block with doc comments. +```attr +doc { + /// Doc comments +} +``` + ## Examples ::: code-group diff --git a/website/src/reference/builder/top-level/start_fn.md b/website/src/reference/builder/top-level/start_fn.md index 2cbf9b21..066f55bc 100644 --- a/website/src/reference/builder/top-level/start_fn.md +++ b/website/src/reference/builder/top-level/start_fn.md @@ -53,6 +53,12 @@ The default visibility is the same as the visibility of the [`builder_type`](./b Simple documentation is generated by default. The syntax of this attribute expects a block with doc comments. +```attr +doc { + /// Doc comments +} +``` + ## Examples ::: code-group diff --git a/website/src/reference/builder/top-level/state_mod.md b/website/src/reference/builder/top-level/state_mod.md index c3b15e19..47d4c5b2 100644 --- a/website/src/reference/builder/top-level/state_mod.md +++ b/website/src/reference/builder/top-level/state_mod.md @@ -1,5 +1,45 @@ # `state_mod` -TODO: add docs +**Applies to:** + +Overrides name, visibility and docs for the builder's [typestate API](../guide/typestate-api) module. + +**Short syntax** configures just the *name*. + +```attr +#[builder(state_mod = custom_name)] +``` + +**Long syntax** provides more flexibility. All keys are optional. + +```attr +#[builder( + state_mod( + name = custom_name, + vis = "pub(crate)", + doc { + /// Custom docs + } + ) +)] +``` + +## `name` + +The default name for the builder typestate API module is a `snake_case` version from the name of the [`builder_type`](./builder_type#name). + +## `vis` + +The visibility must be enclosed with quotes. Use `""` or [`"pub(self)"`](https://doc.rust-lang.org/reference/visibility-and-privacy.html#pubin-path-pubcrate-pubsuper-and-pubself) for private visibility. + +The default visibility is private. This ensures the builder's type can not be named outside of the module where it was generated. See the [Typestate API](../../../guide/typestate-api) guide for details. ## `doc` + +Simple documentation is generated by default. The syntax of this attribute expects a block with doc comments. + +```attr +doc { + /// Doc comments +} +``` From 7d00e6633fd448f258920e0a75a26c5a60134ae0 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 3 Nov 2024 22:50:51 +0000 Subject: [PATCH 03/16] Publish bon-cli --- Cargo.lock | 56 ++++++++++++++------ bon-cli/Cargo.toml | 8 +-- website/src/reference/builder.md | 10 ++-- website/src/reference/builder/member/with.md | 11 +++- 4 files changed, 58 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebcf9cc1..3830ef5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,7 +87,7 @@ dependencies = [ [[package]] name = "bon-cli" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", "ra_ap_parser", @@ -109,6 +109,15 @@ dependencies = [ "syn", ] +[[package]] +name = "borsh" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "cfg_aliases", +] + [[package]] name = "buildstructor" version = "0.5.4" @@ -148,6 +157,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "ciborium" version = "0.2.2" @@ -731,9 +746,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.63.0" +version = "0.73.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdf98bb457b47b9ae4aeebf867d0ca440c86925e0b6381658c4a02589748c9d" +checksum = "119bc05b5b6bc3e7f5b67ce8b8080e185da94bd83c447f91b6b3f3ecf60cbab1" dependencies = [ "unicode-properties", "unicode-xid", @@ -741,15 +756,15 @@ dependencies = [ [[package]] name = "ra_ap_limit" -version = "0.0.233" +version = "0.0.241" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f413cec7ebae9832a6f58ba055cb759d682ed0c9a66224ae09b2aa1962d8782" +checksum = "f9b1b7a869e1a2b68ff8490ff8d3af23b518f83ba41f93192dee0336c0af9b55" [[package]] name = "ra_ap_parser" -version = "0.0.233" +version = "0.0.241" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54fcf2c5b72af3e20e2fe41582fea9f2147e49bf1dbdfea51193c8e284b7f322" +checksum = "d2756858e7851f05d6a9119ecb51b10b7ec85414ea06ab6e20e06fd4a0a64599" dependencies = [ "drop_bomb", "ra-ap-rustc_lexer", @@ -759,9 +774,9 @@ dependencies = [ [[package]] name = "ra_ap_stdx" -version = "0.0.233" +version = "0.0.241" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6609b238dea78fc46d847b9f9177b39f92137d7ef73e5e6b062196326705590f" +checksum = "e743e2c0495f0f1292865d30f7a56349a27f9ceeb61f7b743c96b6ca134e5f76" dependencies = [ "always-assert", "crossbeam-channel", @@ -774,9 +789,9 @@ dependencies = [ [[package]] name = "ra_ap_syntax" -version = "0.0.233" +version = "0.0.241" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e2abef0d98f554288b767e7b4b0377fde75728142d08f7b17d268c2639f8cb" +checksum = "9754a818cc20ad5d0acdc2f316082d5ca166ee22db82f5b8d502ba2d5dcc2492" dependencies = [ "cov-mark", "either", @@ -787,7 +802,7 @@ dependencies = [ "ra_ap_stdx", "ra_ap_text_edit", "rowan", - "rustc-hash", + "rustc-hash 2.0.0", "smol_str", "tracing", "triomphe", @@ -795,9 +810,9 @@ dependencies = [ [[package]] name = "ra_ap_text_edit" -version = "0.0.233" +version = "0.0.241" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6be2047bedda5b44c8d8775036cbf8d01dd99c06756524f20991c4249a1bb6ec" +checksum = "a5f89e975e82f5efe2682bc2c03dda28ad57b0bfd33f64b5831674a25204072b" dependencies = [ "itertools 0.12.1", "text-size", @@ -861,7 +876,7 @@ dependencies = [ "countme", "hashbrown", "memoffset", - "rustc-hash", + "rustc-hash 1.1.0", "text-size", ] @@ -887,6 +902,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustversion" version = "1.0.17" @@ -950,10 +971,11 @@ dependencies = [ [[package]] name = "smol_str" -version = "0.2.2" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" dependencies = [ + "borsh", "serde", ] diff --git a/bon-cli/Cargo.toml b/bon-cli/Cargo.toml index 8b757f33..ebf73851 100644 --- a/bon-cli/Cargo.toml +++ b/bon-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bon-cli" -version = "0.1.0" +version = "0.2.0" description = "Dev tool for working with the `bon` crate" @@ -9,7 +9,7 @@ homepage = "https://bon-rs.com/" license = "MIT OR Apache-2.0" repository = "https://github.com/elastio/bon" -publish = false +publish = true [[bin]] doc = false @@ -21,6 +21,6 @@ workspace = true [dependencies] anyhow = "1.0" -ra_ap_parser = "=0.0.233" -ra_ap_syntax = "=0.0.233" +ra_ap_parser = "=0.0.241" +ra_ap_syntax = "=0.0.241" walkdir = "2.5" diff --git a/website/src/reference/builder.md b/website/src/reference/builder.md index 848de166..cdff5476 100644 --- a/website/src/reference/builder.md +++ b/website/src/reference/builder.md @@ -10,8 +10,8 @@ Generate builders from structs via `#[derive(Builder)]`, free functions via `#[b These attributes are placed on top of a `struct` or `fn` declaration. -| Attribute | Short description -| -- | -- | +| Attribute | Short description +|----------------------------------------------------|--------------------- | [`builder_type`](./builder/top-level/builder_type) | Overrides name, visibility and docs for the builder struct | [`crate`](./builder/top-level/crate) | Overrides path to `bon` crate referenced in the generated code | [`derive`](./builder/top-level/derive) | Generates additional derives for the builder struct itself @@ -24,8 +24,8 @@ These attributes are placed on top of a `struct` or `fn` declaration. These attributes are placed on a `struct` field or `fn` argument. -| Attribute | Short description -| -- | -- | +| Attribute | Short description +|----------------------------------------------------|--------------------- | [`default`](./builder/member/default) | Makes the member optional with a default value | [`finish_fn`](./builder/member/finish_fn) | Makes the member a positional argument on the finishing function | [`into`](./builder/member/into) | Changes the signature of the setters to accept `impl Into` @@ -35,7 +35,7 @@ These attributes are placed on a `struct` field or `fn` argument. | [`skip`](./builder/member/skip) | Skips generating setters for the member | [`start_fn`](./builder/member/start_fn) | Makes the member a positional argument on the starting function | [`transparent`](./builder/member/transparent) | Disables `Option` special handling, makes the member required -| [`with`](./builder/member/with) | ??????? TODO: ADD DOCS ?????? +| [`with`](./builder/member/with) | Overrides setters' signature and applies a custom conversion ## Examples diff --git a/website/src/reference/builder/member/with.md b/website/src/reference/builder/member/with.md index 545df081..1fff0b74 100644 --- a/website/src/reference/builder/member/with.md +++ b/website/src/reference/builder/member/with.md @@ -2,8 +2,17 @@ **Applies to:** -TODO: add docs (update the short descriptions on the parent page) +Overrides setters' signature and applies a custom conversion. +You can specify the signature and the conversion either with the closure syntax or with a [well-known function](#well-known-functions) + +| Form | Meaning +|-----------------------------------------------------------------------------------|---------------------------- +| `#[builder(with = \|...\| body)]` | Custom *infallible* closure +| #[builder(with = \|...\| -> \*Result<_[, E]>)] { body })] | Custom *fallible* closure +| `#[builder(with = well_known_function)]` | One of the [well-known functions](#well-known-functions) + +## Closure syntax If the closure accepts a single parameter `T`, then the `maybe_` setter accepts `Option`. Tuple is unnecessary in this case. From 9b2e5a5be938243cc2b2278c50ba70d01a9ffb4e Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 3 Nov 2024 23:36:36 +0000 Subject: [PATCH 04/16] Add prettier --- website/package-lock.json | 16 +++++++++ website/package.json | 1 + website/src/reference/builder/member/with.md | 34 +++++++++++++++++--- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index cacbda17..63150ca2 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -18,6 +18,7 @@ "htmlparser2": "^9.1.0", "leven": "^4.0.0", "medium-zoom": "^1.1.0", + "prettier": "^3.3.3", "ts-node": "^10.9.2", "ts-pattern": "^5.5.0", "vitepress": "^1.4.5" @@ -2525,6 +2526,21 @@ "url": "https://opencollective.com/preact" } }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/property-information": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", diff --git a/website/package.json b/website/package.json index 51a11a5f..b51eec3b 100644 --- a/website/package.json +++ b/website/package.json @@ -17,6 +17,7 @@ "htmlparser2": "^9.1.0", "leven": "^4.0.0", "medium-zoom": "^1.1.0", + "prettier": "^3.3.3", "ts-node": "^10.9.2", "ts-pattern": "^5.5.0", "vitepress": "^1.4.5" diff --git a/website/src/reference/builder/member/with.md b/website/src/reference/builder/member/with.md index 1fff0b74..19d23697 100644 --- a/website/src/reference/builder/member/with.md +++ b/website/src/reference/builder/member/with.md @@ -9,11 +9,36 @@ You can specify the signature and the conversion either with the closure syntax | Form | Meaning |-----------------------------------------------------------------------------------|---------------------------- | `#[builder(with = \|...\| body)]` | Custom *infallible* closure -| #[builder(with = \|...\| -> \*Result<_[, E]>)] { body })] | Custom *fallible* closure +| #[builder(with = \|...\| -> \*Result<_[, E]> { body })] | Custom *fallible* closure | `#[builder(with = well_known_function)]` | One of the [well-known functions](#well-known-functions) ## Closure syntax +The simplest form of the custom closure is an *infallible* closure. It *must not* have a return type annotation and it *must* return the value of the *underlying* member's type. If the member is of type `Option` without [`#[builder(transparent)]`](./transparent), then the *underlying* member's type is `T`. + +```rust +use bon::Builder; + +struct Point { + x: u32, + y: u32, +} + +#[derive(Builder)] +struct Example { + #[builder(with = |x: u32, y: u32| Point { x, y })] + point: Point, +} + +let value = Example::builder() + .point(2, 3) + .build(); + +assert_eq!(value.point.x, 2); +assert_eq!(value.point.y, 3); +``` + + If the closure accepts a single parameter `T`, then the `maybe_` setter accepts `Option`. Tuple is unnecessary in this case. You can use `impl Trait` for parameters in the closure, even though you can't in the usual Rust code. @@ -27,10 +52,6 @@ You can use `impl Trait` for parameters in the closure, even though you can't in Example::builder().maybe_x2(Some((4, 2))); ``` --> - -## Well-Known Functions - - ## Fallible setters You can add a return type annotation to the closure to signify that it's fallible. In this case a fallible setter will be generated. @@ -55,3 +76,6 @@ fn main() -> Result<(), ParseIntError> { Ok(()) } ``` + + +## Well-Known Functions From d26facc105682c7b5708aa484d95453b3d2eb3cb Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 3 Nov 2024 23:41:06 +0000 Subject: [PATCH 05/16] Move prettier to the workspace root --- package-lock.json | 27 +++++++++++++++++++++++++++ package.json | 5 +++++ website/package-lock.json | 16 ---------------- website/package.json | 1 - 4 files changed, 32 insertions(+), 17 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..9171c449 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,27 @@ +{ + "name": "bon", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "prettier": "^3.3.3" + } + }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..c2436a9f --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "prettier": "^3.3.3" + } +} diff --git a/website/package-lock.json b/website/package-lock.json index 63150ca2..cacbda17 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -18,7 +18,6 @@ "htmlparser2": "^9.1.0", "leven": "^4.0.0", "medium-zoom": "^1.1.0", - "prettier": "^3.3.3", "ts-node": "^10.9.2", "ts-pattern": "^5.5.0", "vitepress": "^1.4.5" @@ -2526,21 +2525,6 @@ "url": "https://opencollective.com/preact" } }, - "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/property-information": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", diff --git a/website/package.json b/website/package.json index b51eec3b..51a11a5f 100644 --- a/website/package.json +++ b/website/package.json @@ -17,7 +17,6 @@ "htmlparser2": "^9.1.0", "leven": "^4.0.0", "medium-zoom": "^1.1.0", - "prettier": "^3.3.3", "ts-node": "^10.9.2", "ts-pattern": "^5.5.0", "vitepress": "^1.4.5" From 359da5b0a086098527278bacb72b38448650fd48 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 4 Nov 2024 00:42:40 +0000 Subject: [PATCH 06/16] Configure prettier --- .githooks/pre-commit | 20 ++++++++++++++++++++ .gitignore | 2 ++ .prettierignore | 1 + .prettierrc.toml | 1 + website/infra/.terraform.lock.hcl | 19 ------------------- website/src/reference/builder/member/with.md | 14 ++++++-------- 6 files changed, 30 insertions(+), 27 deletions(-) create mode 100644 .githooks/pre-commit create mode 100644 .prettierignore create mode 100644 .prettierrc.toml diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100644 index 00000000..031a1c98 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +FILES=$(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\\ |g') +[ -z "$FILES" ] && exit 0 + +echo "[prettier]" + +# Prettify all selected files +echo "$FILES" | xargs ./node_modules/.bin/prettier --ignore-unknown --write + +echo "[cargo fmt]" + +cargo fmt + +# Add back the modified/prettified files to staging +echo "$FILES" | xargs git add + +exit 0 diff --git a/.gitignore b/.gitignore index 48323c98..b710162e 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ terraform.tfstate* # Terraform variables usually contain sensitive information terraform.tfvars terraform.tfvars.json + +*dbg* diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..dd1e3432 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +website/infra/bootstrap/user_data.yml diff --git a/.prettierrc.toml b/.prettierrc.toml new file mode 100644 index 00000000..bfa46553 --- /dev/null +++ b/.prettierrc.toml @@ -0,0 +1 @@ +#:schema https://json.schemastore.org/prettierrc diff --git a/website/infra/.terraform.lock.hcl b/website/infra/.terraform.lock.hcl index 50ec017a..fef885dc 100644 --- a/website/infra/.terraform.lock.hcl +++ b/website/infra/.terraform.lock.hcl @@ -21,25 +21,6 @@ provider "registry.terraform.io/hashicorp/cloudinit" { ] } -provider "registry.terraform.io/hashicorp/null" { - version = "3.2.3" - hashes = [ - "h1:+AnORRgFbRO6qqcfaQyeX80W0eX3VmjadjnUFUJTiXo=", - "zh:22d062e5278d872fe7aed834f5577ba0a5afe34a3bdac2b81f828d8d3e6706d2", - "zh:23dead00493ad863729495dc212fd6c29b8293e707b055ce5ba21ee453ce552d", - "zh:28299accf21763ca1ca144d8f660688d7c2ad0b105b7202554ca60b02a3856d3", - "zh:55c9e8a9ac25a7652df8c51a8a9a422bd67d784061b1de2dc9fe6c3cb4e77f2f", - "zh:756586535d11698a216291c06b9ed8a5cc6a4ec43eee1ee09ecd5c6a9e297ac1", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:9d5eea62fdb587eeb96a8c4d782459f4e6b73baeece4d04b4a40e44faaee9301", - "zh:a6355f596a3fb8fc85c2fb054ab14e722991533f87f928e7169a486462c74670", - "zh:b5a65a789cff4ada58a5baffc76cb9767dc26ec6b45c00d2ec8b1b027f6db4ed", - "zh:db5ab669cf11d0e9f81dc380a6fdfcac437aea3d69109c7aef1a5426639d2d65", - "zh:de655d251c470197bcbb5ac45d289595295acb8f829f6c781d4a75c8c8b7c7dd", - "zh:f5c68199f2e6076bce92a12230434782bf768103a427e9bb9abee99b116af7b5", - ] -} - provider "registry.terraform.io/hetznercloud/hcloud" { version = "1.48.1" constraints = "~> 1.48.1" diff --git a/website/src/reference/builder/member/with.md b/website/src/reference/builder/member/with.md index 19d23697..69d9f657 100644 --- a/website/src/reference/builder/member/with.md +++ b/website/src/reference/builder/member/with.md @@ -6,15 +6,15 @@ Overrides setters' signature and applies a custom conversion. You can specify the signature and the conversion either with the closure syntax or with a [well-known function](#well-known-functions) -| Form | Meaning -|-----------------------------------------------------------------------------------|---------------------------- -| `#[builder(with = \|...\| body)]` | Custom *infallible* closure -| #[builder(with = \|...\| -> \*Result<_[, E]> { body })] | Custom *fallible* closure -| `#[builder(with = well_known_function)]` | One of the [well-known functions](#well-known-functions) +| Form | Meaning | +| ---------------------------------------------------------------------------------- | -------------------------------------------------------- | +| `#[builder(with = \|...\| body)]` | Custom _infallible_ closure | +| #[builder(with = \|...\| -> \*Result<\_[, E]> { body })] | Custom _fallible_ closure | +| `#[builder(with = well_known_function)]` | One of the [well-known functions](#well-known-functions) | ## Closure syntax -The simplest form of the custom closure is an *infallible* closure. It *must not* have a return type annotation and it *must* return the value of the *underlying* member's type. If the member is of type `Option` without [`#[builder(transparent)]`](./transparent), then the *underlying* member's type is `T`. +The simplest form of the custom closure is an _infallible_ closure. It _must not_ have a return type annotation and it _must_ return the value of the _underlying_ member's type. If the member is of type `Option` without [`#[builder(transparent)]`](./transparent), then the _underlying_ member's type is `T`. ```rust use bon::Builder; @@ -38,7 +38,6 @@ assert_eq!(value.point.x, 2); assert_eq!(value.point.y, 3); ``` - If the closure accepts a single parameter `T`, then the `maybe_` setter accepts `Option`. Tuple is unnecessary in this case. You can use `impl Trait` for parameters in the closure, even though you can't in the usual Rust code. @@ -77,5 +76,4 @@ fn main() -> Result<(), ParseIntError> { } ``` - ## Well-Known Functions From 126aafb0eaaa033d550c909eb48af224b21cebcd Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 4 Nov 2024 00:45:19 +0000 Subject: [PATCH 07/16] Add init.sh --- scripts/init.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 scripts/init.sh diff --git a/scripts/init.sh b/scripts/init.sh new file mode 100755 index 00000000..6df82a0b --- /dev/null +++ b/scripts/init.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Script to initialize the repo for development. + +set -euxo pipefail + +# Install prettier +npm ci + +# Install the pre-commit hook +ln -s ../../.githooks/pre-commit .git/hooks/pre-commit From 55d9e85e1b96c86df556c15ce182196dae4bfba0 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 4 Nov 2024 00:50:06 +0000 Subject: [PATCH 08/16] Make hook executable --- .githooks/pre-commit | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .githooks/pre-commit diff --git a/.githooks/pre-commit b/.githooks/pre-commit old mode 100644 new mode 100755 From 126f3e94f7773afef84e598acd5aaba426a51c44 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 4 Nov 2024 00:52:18 +0000 Subject: [PATCH 09/16] Better hook --- .githooks/pre-commit | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 031a1c98..cb7322cd 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -5,12 +5,12 @@ set -euo pipefail FILES=$(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\\ |g') [ -z "$FILES" ] && exit 0 -echo "[prettier]" +echo "> prettier (changed files only)" # Prettify all selected files echo "$FILES" | xargs ./node_modules/.bin/prettier --ignore-unknown --write -echo "[cargo fmt]" +echo "> cargo fmt (all files)" cargo fmt From 300b2e9af79b7c28e9e02b102bf437c5980d6618 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 4 Nov 2024 00:53:04 +0000 Subject: [PATCH 10/16] Add taplo fmt to the hook --- .githooks/pre-commit | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.githooks/pre-commit b/.githooks/pre-commit index cb7322cd..5e7d1b7a 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -14,6 +14,10 @@ echo "> cargo fmt (all files)" cargo fmt +echo "> taplo fmt (all files)" + +taplo fmt + # Add back the modified/prettified files to staging echo "$FILES" | xargs git add From 987eb18dee25e550df7b2fe57dcf192d5a727d51 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 4 Nov 2024 00:54:04 +0000 Subject: [PATCH 11/16] Update Ignores --- .prettierignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.prettierignore b/.prettierignore index dd1e3432..ad308b42 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,5 @@ +# This file uses terraform's templating syntax rather than YML, so prettier can't parse it website/infra/bootstrap/user_data.yml + +# Leading whitespace there is intentional as the place for the main issue body +.github/issue_template.md From d95f1b875f2b59ce4ecb9ab4e411008413efc8b4 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Mon, 4 Nov 2024 01:17:05 +0000 Subject: [PATCH 12/16] Apply prettier --- .github/workflows/release.yml | 6 +- README.v3.md | 4 +- benchmarks/compilation/README.md | 2 +- benchmarks/compilation/results.md | 24 +- benchmarks/runtime/README.md | 4 +- website/.vitepress/config.mts | 2 +- .../theme/components/PageFooter.vue | 27 +- .../theme/components/PageHeader.vue | 24 +- .../theme/components/VersionSwitcher.vue | 50 +- website/.vitepress/theme/index.ts | 8 +- .../.vitepress/theme/layouts/CustomLayout.vue | 20 +- website/.vitepress/theme/utils/formatDate.ts | 4 +- website/.vitepress/theme/utils/getSorted.ts | 12 +- website/data/posts.data.ts | 4 +- website/infra/README.md | 5 +- website/infra/bootstrap/docker-daemon.json | 12 +- .../blog/bon-builder-generator-v2-release.md | 13 +- website/src/blog/bon-builder-v2-1-release.md | 17 +- website/src/blog/bon-builder-v2-2-release.md | 9 +- website/src/blog/bon-builder-v2-3-release.md | 12 +- ...-to-do-named-function-arguments-in-rust.md | 6 +- ...e-weird-of-function-local-types-in-rust.md | 6 +- website/src/changelog.md | 179 +++--- website/src/guide/basics/documenting.md | 20 +- website/src/guide/basics/optional-members.md | 9 +- website/src/guide/internal/contributing.md | 5 +- website/src/guide/misc/alternatives.md | 44 +- website/src/guide/misc/benchmarks.md | 38 +- .../src/guide/patterns/fallible-builders.md | 2 +- .../patterns/into-conversions-in-depth.md | 19 +- .../typestate-api/builders-type-signature.md | 5 +- .../src/guide/typestate-api/custom-methods.md | 4 +- website/src/index.md | 36 +- website/src/reference/builder.md | 42 +- .../src/reference/builder/member/default.md | 17 +- .../src/reference/builder/member/setters.md | 8 +- .../reference/builder/member/transparent.md | 9 +- .../builder/top-level/builder_type.md | 14 +- .../src/reference/builder/top-level/crate.md | 12 +- .../src/reference/builder/top-level/derive.md | 4 +- .../reference/builder/top-level/finish_fn.md | 14 +- website/src/reference/builder/top-level/on.md | 7 +- .../reference/builder/top-level/start_fn.md | 23 +- .../reference/builder/top-level/state_mod.md | 2 +- website/src/v1/guide/alternatives.md | 34 +- website/src/v1/guide/benchmarks.md | 38 +- website/src/v1/guide/documenting.md | 4 +- website/src/v1/guide/into-conversions.md | 19 +- website/src/v1/guide/limitations.md | 1 - website/src/v1/guide/optional-members.md | 1 - website/src/v1/guide/overview.md | 47 +- website/src/v1/reference/builder.md | 41 +- website/src/v2/guide/alternatives.md | 40 +- website/src/v2/guide/benchmarks.md | 38 +- website/src/v2/guide/documenting.md | 4 +- website/src/v2/guide/internal/contributing.md | 5 +- website/src/v2/guide/overview.md | 15 +- .../v2/guide/patterns/fallible-builders.md | 2 +- .../patterns/into-conversions-in-depth.md | 19 +- website/src/v2/guide/positional-members.md | 9 +- website/src/v2/reference/builder.md | 8 +- website/tsconfig.json | 6 +- website/validate-links.mts | 538 ++++++++++-------- 63 files changed, 852 insertions(+), 801 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6322ce38..e9c876f9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,9 +10,9 @@ on: workflow_dispatch: env: - CARGO_TERM_COLOR: always - RUST_BACKTRACE: 1 - CARGO_INCREMENTAL: 0 + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + CARGO_INCREMENTAL: 0 jobs: release-rust-crates: diff --git a/README.v3.md b/README.v3.md index 3071ffb0..2784bc0e 100644 --- a/README.v3.md +++ b/README.v3.md @@ -43,7 +43,6 @@ - # Overview @@ -182,7 +181,7 @@ Builders generated by `bon`'s macros use the typestate pattern to ensure all req If something is wrong, a compile error will be created. No matter how you use the generated builder a panic is never possible. | ⭐ Don't forget to give our repo a [star on Github ⭐](https://github.com/elastio/bon)! | -| --- | +| --------------------------------------------------------------------------------------- | ## What's Next? @@ -209,7 +208,6 @@ If you can't figure something out, consult the docs and maybe use the `🔍 Sear ## Socials - diff --git a/benchmarks/compilation/README.md b/benchmarks/compilation/README.md index 085c455e..d66c1a5a 100644 --- a/benchmarks/compilation/README.md +++ b/benchmarks/compilation/README.md @@ -6,7 +6,7 @@ This is a collection of compilation time benchmarks for the code generated by `b If you'd like to run the benchmarks yourself, first you need to install the following: -- [`hyperfine`](https://github.com/sharkdp/hyperfine) CLI +- [`hyperfine`](https://github.com/sharkdp/hyperfine) CLI If you are on Linux, just run the following commands to install the dependencies: diff --git a/benchmarks/compilation/results.md b/benchmarks/compilation/results.md index a9a5ad25..5af1cb01 100644 --- a/benchmarks/compilation/results.md +++ b/benchmarks/compilation/results.md @@ -1,12 +1,12 @@ -| Command | Mean [s] | Min [s] | Max [s] | Relative | -|:---|---:|---:|---:|---:| -| `structs_100_fields_10 bon` | 2.319 ± 0.021 | 2.278 | 2.350 | 22.80 ± 2.99 | -| `structs_100_fields_10 bon-overwritable` | 2.240 ± 0.021 | 2.203 | 2.274 | 22.03 ± 2.89 | -| `structs_100_fields_10 typed-builder` | 1.849 ± 0.011 | 1.838 | 1.878 | 18.18 ± 2.38 | -| `structs_100_fields_10 derive_builder` | 1.022 ± 0.016 | 0.995 | 1.043 | 10.05 ± 1.32 | -| `structs_100_fields_10 ` | 0.104 ± 0.012 | 0.088 | 0.124 | 1.02 ± 0.18 | -| `structs_10_fields_50 bon` | 2.063 ± 0.017 | 2.044 | 2.100 | 20.28 ± 2.66 | -| `structs_10_fields_50 bon-overwritable` | 2.029 ± 0.029 | 1.998 | 2.102 | 19.95 ± 2.62 | -| `structs_10_fields_50 typed-builder` | 2.076 ± 0.016 | 2.048 | 2.101 | 20.41 ± 2.67 | -| `structs_10_fields_50 derive_builder` | 0.432 ± 0.016 | 0.400 | 0.458 | 4.25 ± 0.58 | -| `structs_10_fields_50 ` | 0.102 ± 0.013 | 0.084 | 0.130 | 1.00 | +| Command | Mean [s] | Min [s] | Max [s] | Relative | +| :--------------------------------------- | ------------: | ------: | ------: | -----------: | +| `structs_100_fields_10 bon` | 2.319 ± 0.021 | 2.278 | 2.350 | 22.80 ± 2.99 | +| `structs_100_fields_10 bon-overwritable` | 2.240 ± 0.021 | 2.203 | 2.274 | 22.03 ± 2.89 | +| `structs_100_fields_10 typed-builder` | 1.849 ± 0.011 | 1.838 | 1.878 | 18.18 ± 2.38 | +| `structs_100_fields_10 derive_builder` | 1.022 ± 0.016 | 0.995 | 1.043 | 10.05 ± 1.32 | +| `structs_100_fields_10 ` | 0.104 ± 0.012 | 0.088 | 0.124 | 1.02 ± 0.18 | +| `structs_10_fields_50 bon` | 2.063 ± 0.017 | 2.044 | 2.100 | 20.28 ± 2.66 | +| `structs_10_fields_50 bon-overwritable` | 2.029 ± 0.029 | 1.998 | 2.102 | 19.95 ± 2.62 | +| `structs_10_fields_50 typed-builder` | 2.076 ± 0.016 | 2.048 | 2.101 | 20.41 ± 2.67 | +| `structs_10_fields_50 derive_builder` | 0.432 ± 0.016 | 0.400 | 0.458 | 4.25 ± 0.58 | +| `structs_10_fields_50 ` | 0.102 ± 0.013 | 0.084 | 0.130 | 1.00 | diff --git a/benchmarks/runtime/README.md b/benchmarks/runtime/README.md index 2c26674a..e1637cc0 100644 --- a/benchmarks/runtime/README.md +++ b/benchmarks/runtime/README.md @@ -6,8 +6,8 @@ This is a collection of runtime benchmarks for the code generated by `bon` crate If you'd like to run the benchmarks yourself, first you need to install the following: -- `Valgrind`. Its `cachegrind` component is used by [`iai`](https://github.com/bheisler/iai) benchmark to display the instruction counts and cache/RAM hits. -- `cargo-asm`. It's used to get the resulting assembly code for the benchmarked functions. +- `Valgrind`. Its `cachegrind` component is used by [`iai`](https://github.com/bheisler/iai) benchmark to display the instruction counts and cache/RAM hits. +- `cargo-asm`. It's used to get the resulting assembly code for the benchmarked functions. If you are on Ubuntu or Debian, just run the following commands to install the dependencies: diff --git a/website/.vitepress/config.mts b/website/.vitepress/config.mts index aeaa51c0..487e1bb4 100644 --- a/website/.vitepress/config.mts +++ b/website/.vitepress/config.mts @@ -170,7 +170,7 @@ export default defineConfig({ { text: "Custom Methods", link: "/guide/typestate-api/custom-methods", - } + }, ], }, { diff --git a/website/.vitepress/theme/components/PageFooter.vue b/website/.vitepress/theme/components/PageFooter.vue index 6eb1551a..a912eaf1 100644 --- a/website/.vitepress/theme/components/PageFooter.vue +++ b/website/.vitepress/theme/components/PageFooter.vue @@ -1,32 +1,35 @@