0.19 — ergonomic setters and faster reflection
source link: https://dwrensha.github.io/capnproto-rust/2024/01/14/0.19-release.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
0.19 — ergonomic setters and faster reflection
0.19 — ergonomic setters and faster reflection
14 Jan 2024
As of today, version 0.19 of capnproto-rust is available on crates.io.
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:
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:
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:
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:
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
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.
Probably we should have
delayed that release until we had a solution like
the present impl SetterInput
generalization,
thereby minimizing the churn of downstream code.
faster reflection
The 0.17 release
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, @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.
-- posted by dwrensha
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK