-
Notifications
You must be signed in to change notification settings - Fork 217
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
172 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters