Skip to content

Commit

Permalink
prepare for 0.19 release
Browse files Browse the repository at this point in the history
  • Loading branch information
dwrensha committed Jan 14, 2024
1 parent 79e4af6 commit 6dbd38e
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 9 deletions.
139 changes: 139 additions & 0 deletions blog/_posts/2024-01-14-0.19-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
layout: post
title: 0.19 — setter ergonomics and faster reflection
author: dwrensha
---

As of today,
version 0.19 of [capnproto-rust](https://github.com/capnproto/capnproto-rust)
is [available on crates.io](https://crates.io/crates/capnp).

This release includes improved ergnomics and performance,
while also having a notable breaking change involving text fields.


## setter ergonomics

Suppose that we have the following struct defined in a Cap'n Proto schema file:

```capnp
struct Cookie {
fortune @0 :Text;
numbers @1 :List(UInt16);
}
```

With capnp-v0.18.0 (the previous release), to populate such a struct you would write Rust code like this:

```rust
let mut message = capnp::message::Builder::new_default();
let mut root: cookie::Builder = message.init_root();
root.set_fortune("This too shall pass.".into());
let mut numbers = root.init_numbers(6);
numbers.set(0, 4);
numbers.set(1, 8);
numbers.set(2, 15);
numbers.set(3, 16);
numbers.set(3, 23);
numbers.set(3, 42);
```

This is rather more verbose than you might hope.
The setter methods `set_fortune()` and `set_numbers()` are geared toward
accepting input from *other* Cap'n Proto messages, rather than
from Rust-native values.
When we want to call `set_fortune()` on a Rust-native `&str`,
we first need to convert it into a `capnp::text::Reader` via the `.into()` method.
Similarly, the `set_numbers()` method wants a `primitive_list::Reader<u16>`,
and there is no easy way for us to get one of those from a Rust-native `&[u16]`.
Therefore, we avoid that method altogether, and instead opt to use `init_numbers()`
and to invidually set each element of the list.


In capnp-v0.19.0, we can instead directly set these fields from Rust-native values:

```rust
let mut message = capnp::message::Builder::new_default();
let mut root: cookie::Builder = message.init_root();
root.set_fortune("This too shall pass.");
root.set_numbers(&[4, 8, 15, 16, 23, 42]);
```

This is possible because the setter methods have been generalized
to accept a value of type `impl SetterInput<T>`, as follows:

```rust

mod cookie {
impl <'a> Builder<'a> {
pub fn set_fortune(&mut self, impl SetterInput<capnp::text::Owned>) {
...
}
pub fn set_numbers(&mut self,
impl SetterInput<capnp::primitive_list::Owned<u16>>) {
...
}
}
}

```

The trait `SetterInput<capnp::text::Owned>` is implemented both by
`capnp::text::Reader` and by `&str`, and
the trait `SetterInput<capnp::primitive_list::Owned<u16>>`
is implemented by both `capnp::primitive_list::Reader<u16>`
and by `&[u16]`.

### breaking change

Unfortunately, this generalization does cause some breakage.
If we did not update the old line
```rust
root.set_fortune("This too shall pass.".into());
```
then it would now gives us a type error:

```
error[E0283]: type annotations needed
...
= note: multiple `impl`s satisfying `_: SetterInput<capnp::text::Owned>` found in the `capnp` crate:
- impl<'a> SetterInput<capnp::text::Owned> for &'a String;
- impl<'a> SetterInput<capnp::text::Owned> for &'a str;
- impl<'a> SetterInput<capnp::text::Owned> for capnp::text::Reader<'a>;
note: required by a bound in `cookie::Builder::<'a>::set_fortune`
```

The problem is that `.into()` does not know which type to target.
The fix is to remove the `.into()`.

Note that the need for such `.into()` calls was in fact only recently
introduced, in the release of
[version 0.18]({{site.baseurl}}/2023/09/04/0.18-release.html).
Probably we should have
delayed that release until we had a solution like the
the present `impl SetterInput` generalization,
thereby minimizing the churn of downstream code.


## faster reflection

The [0.17 release]({{site.baseurl}}/2023/05/08/run-time-reflection.html)
added support for run-time reflection,
including a `DynamicStruct` type that supports
looking up fields by name.
The initial implementation
worked by linearly scanning a struct's fields.
That works fine for small structs, but can
get expensive when there are a large number of fields.

In [#469](https://github.com/capnproto/capnproto-rust/pull/469),
[@quartox](https://github.com/quartox) updated
the implementation to use binary search,
resulting in a significant performance increase,
and matching the capnproto-c++ implementation.

This change involved add a new field to the static `RawStructSchema` value included
in the generated code for each Cap'n Proto type.

3 changes: 3 additions & 0 deletions capnp-futures/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## v0.19.0
Follow v0.19.0 release of other capnp crates.

## v0.18.2
- Fix overflow bug in read_message that could potentially lead to denial of service
attacks on 32-bit targets.
Expand Down
6 changes: 3 additions & 3 deletions capnp-futures/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "capnp-futures"
version = "0.19.0-alpha"
version = "0.19.0"
authors = [ "David Renshaw <drenshaw@gmail.com>" ]
license = "MIT"

Expand All @@ -12,7 +12,7 @@ edition = "2021"
keywords = ["async"]

[dependencies]
capnp = { version = "0.19.0-alpha", path = "../capnp" }
capnp = { version = "0.19.0", path = "../capnp" }

[dependencies.futures]
version = "0.3.0"
Expand All @@ -25,7 +25,7 @@ default-features = false
features = ["executor"]

[dev-dependencies]
capnp = { version = "0.19.0-alpha", path = "../capnp", features = ["quickcheck"] }
capnp = { version = "0.19.0", path = "../capnp", features = ["quickcheck"] }
quickcheck = "1"

[lints]
Expand Down
6 changes: 6 additions & 0 deletions capnp-rpc/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v0.19.0
Follow v0.19.0 release of other capnp crates.

## v0.18.0
Follow v0.19.0 release of other capnp crates.

## v0.17.0
- Rename `WeakCapabilityServerSet` to `CapabilityServerSet` and remove the old implmentation.

Expand Down
6 changes: 3 additions & 3 deletions capnp-rpc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "capnp-rpc"
version = "0.19.0-alpha"
version = "0.19.0"
authors = [ "David Renshaw <dwrenshaw@sandstorm.io>" ]
license = "MIT"
description = "implementation of the Cap'n Proto remote procedure call protocol"
Expand All @@ -19,8 +19,8 @@ default-features = false
features = ["std"]

[dependencies]
capnp-futures = { version = "0.19.0-alpha", path = "../capnp-futures" }
capnp = {version = "0.19.0-alpha", path = "../capnp"}
capnp-futures = { version = "0.19.0", path = "../capnp-futures" }
capnp = {version = "0.19.0", path = "../capnp"}

#[lints]
#workspace = true
Expand Down
11 changes: 11 additions & 0 deletions capnp/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## v0.19.0
- Use binary search instead of linear scan in DynamicStruct::get_named().
- Rename SetPointerBuilder to SetterInput.
- Add Receiver type parameter to SetterInput.
- Support setting text fields by text::Reader or &str, via the SetterInput tactic.
This will break code that uses the into() to convert from str to text::Reader
in the arguments of such methods.
- Also support setting primitive list fields by native Rust slices, and text list
fields by slices of AsRef<str>.
- Update embedded-io dependency to version 0.6.1.

## v0.18.13
- Add PartialEq impls for text::Reader <-> String.

Expand Down
2 changes: 1 addition & 1 deletion capnp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "capnp"
version = "0.19.0-alpha"
version = "0.19.0"
authors = [ "David Renshaw <dwrenshaw@gmail.com>" ]
license = "MIT"
description = "runtime library for Cap'n Proto data encoding"
Expand Down
4 changes: 4 additions & 0 deletions capnpc/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## v0.19.0
- Include new members_by_name field of RawStructSchema.
- Generalize text, primitive_list, and enum_list setters using impl SetterInput.

## v0.18.1
- Fix overly-restrictive lifetimes in setters of certain list fields.

Expand Down
4 changes: 2 additions & 2 deletions capnpc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "capnpc"
version = "0.19.0-alpha"
version = "0.19.0"
authors = [ "David Renshaw <dwrenshaw@gmail.com>" ]
license = "MIT"
description = "Cap'n Proto code generation"
Expand All @@ -25,7 +25,7 @@ path = "src/capnpc-rust-bootstrap.rs"


[dependencies.capnp]
version = "0.19.0-alpha"
version = "0.19.0"
path = "../capnp"

[lints]
Expand Down

0 comments on commit 6dbd38e

Please sign in to comment.