Skip to content

Commit 1c2d758

Browse files
luisholandadwrensha
authored andcommitted
add support async fn in Server traits
With this commit changes how we generate the `Server` traits for interfaces. We now generate `async fn` compatible traits instead of methods returning `Promise`. The methods now receive `&self` instead of `&mut self`, which causes server implementations to need `RefCell`/`Cell` for mutable state, similar to what we have for `Send` servers in other RPC systems. This is slightly different from what was discussed in #577, because we don't actually have a `Rc<impl Server>` inside `Client`, but instead `Rc<ServerDispatch>`, making the receiver a `Rc<Self>` (which would allow easier background processing spawning) would require an extra allocation, pointer chasing, and ref-counting operations. From the changes in the examples, we can see that the code is significantly easier to understand, and `pry!` is almost never needed. The only case I truly needed to use it was when the code needed to manually create `Promise` due to a `RefMut` preventing use to use `async fn` (which could cause double borrows). In matters of breaking changes, this of course breaks every pre-existing implementation, but it should be an easy migration. In the crates themselves, `capnp::capability::Server` needed to be changed to receive `Rc<Self>` instead of `&mut self`, not only the `&mut` isn't necessary anymore but also receiving a `Rc<Self>` (which we already have where it is called) also allow us to make the generated methods for `Server` traits non-'static, which makes the `async fn` syntax significantly more useful. Also, some methods in `CapabilityServerSet` which exposed the internal `Rc<RefCell<Dispatcher>>` from `Client` needed to be changed to return just `Rc<Dispatcher>`. Also, given that we're using `async/await` in the generated code, they can't be compiled in editions 2015/2018 anymore. It may be possible to support them with some added complexity in the generated code, but I don't think it is worth it. Closes: #577
1 parent 43472cf commit 1c2d758

File tree

21 files changed

+512
-574
lines changed

21 files changed

+512
-574
lines changed

Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ members = [
1717
"benchmark",
1818
"capnpc/test",
1919
"capnpc/test/external-crate",
20-
"capnpc/test-edition-2015",
21-
"capnpc/test-edition-2018",
2220
"capnpc/test-edition-2021",
2321
"capnp-futures/test",
2422
"capnp-rpc/examples/hello-world",

capnp-rpc/examples/calculator/client.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,27 @@
2020
// THE SOFTWARE.
2121

2222
use crate::calculator_capnp::calculator;
23-
use capnp::capability::Promise;
24-
use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, RpcSystem};
23+
use capnp_rpc::{rpc_twoparty_capnp, twoparty, RpcSystem};
2524

2625
use futures::AsyncReadExt;
2726

2827
#[derive(Clone, Copy)]
2928
pub struct PowerFunction;
3029

3130
impl calculator::function::Server for PowerFunction {
32-
fn call(
33-
&mut self,
31+
async fn call(
32+
&self,
3433
params: calculator::function::CallParams,
3534
mut results: calculator::function::CallResults,
36-
) -> Promise<(), ::capnp::Error> {
37-
let params = pry!(pry!(params.get()).get_params());
35+
) -> Result<(), ::capnp::Error> {
36+
let params = params.get()?.get_params()?;
3837
if params.len() != 2 {
39-
Promise::err(::capnp::Error::failed(
38+
Err(::capnp::Error::failed(
4039
"Wrong number of parameters".to_string(),
4140
))
4241
} else {
4342
results.get().set_value(params.get(0).powf(params.get(1)));
44-
Promise::ok(())
43+
Ok(())
4544
}
4645
}
4746
}

capnp-rpc/examples/calculator/server.rs

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,18 @@
1919
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2020
// THE SOFTWARE.
2121

22+
use std::cell::RefCell;
23+
24+
use ::capnp::message::HeapAllocator;
25+
use capnp::capability::Promise;
2226
use capnp::primitive_list;
2327
use capnp::Error;
2428

25-
use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, RpcSystem};
29+
use ::capnp_rpc::ImbuedMessageBuilder;
30+
use capnp_rpc::pry;
31+
use capnp_rpc::{rpc_twoparty_capnp, twoparty, RpcSystem};
2632

2733
use crate::calculator_capnp::calculator;
28-
use capnp::capability::Promise;
2934

3035
use futures::future;
3136
use futures::{AsyncReadExt, FutureExt, TryFutureExt};
@@ -41,19 +46,19 @@ impl ValueImpl {
4146
}
4247

4348
impl calculator::value::Server for ValueImpl {
44-
fn read(
45-
&mut self,
49+
async fn read(
50+
&self,
4651
_params: calculator::value::ReadParams,
4752
mut results: calculator::value::ReadResults,
48-
) -> Promise<(), Error> {
53+
) -> Result<(), Error> {
4954
results.get().set_value(self.value);
50-
Promise::ok(())
55+
Ok(())
5156
}
5257
}
5358

5459
fn evaluate_impl(
55-
expression: calculator::expression::Reader,
56-
params: Option<primitive_list::Reader<f64>>,
60+
expression: calculator::expression::Reader<'_>,
61+
params: Option<primitive_list::Reader<'_, f64>>,
5762
) -> Promise<f64, Error> {
5863
match pry!(expression.which()) {
5964
calculator::expression::Literal(v) => Promise::ok(v),
@@ -92,43 +97,45 @@ fn evaluate_impl(
9297

9398
struct FunctionImpl {
9499
param_count: u32,
95-
body: ::capnp_rpc::ImbuedMessageBuilder<::capnp::message::HeapAllocator>,
100+
body: RefCell<ImbuedMessageBuilder<HeapAllocator>>,
96101
}
97102

98103
impl FunctionImpl {
99104
fn new(param_count: u32, body: calculator::expression::Reader) -> ::capnp::Result<Self> {
100-
let mut result = Self {
105+
let result = Self {
101106
param_count,
102-
body: ::capnp_rpc::ImbuedMessageBuilder::new(::capnp::message::HeapAllocator::new()),
107+
body: RefCell::new(ImbuedMessageBuilder::new(HeapAllocator::new())),
103108
};
104-
result.body.set_root(body)?;
109+
result.body.borrow_mut().set_root(body)?;
105110
Ok(result)
106111
}
107112
}
108113

109114
impl calculator::function::Server for FunctionImpl {
110-
fn call(
111-
&mut self,
115+
async fn call(
116+
&self,
112117
params: calculator::function::CallParams,
113118
mut results: calculator::function::CallResults,
114-
) -> Promise<(), Error> {
115-
let params = pry!(pry!(params.get()).get_params());
119+
) -> Result<(), Error> {
120+
let params = params.get()?.get_params()?;
116121
if params.len() != self.param_count {
117-
return Promise::err(Error::failed(format!(
122+
return Err(Error::failed(format!(
118123
"Expected {} parameters but got {}.",
119124
self.param_count,
120125
params.len()
121126
)));
122127
}
123128

124129
let eval = evaluate_impl(
125-
pry!(self.body.get_root::<calculator::expression::Builder>()).into_reader(),
130+
self.body
131+
.borrow_mut()
132+
.get_root::<calculator::expression::Builder>()?
133+
.into_reader(),
126134
Some(params),
127135
);
128-
Promise::from_future(async move {
129-
results.get().set_value(eval.await?);
130-
Ok(())
131-
})
136+
137+
results.get().set_value(eval.await?);
138+
Ok(())
132139
}
133140
}
134141

@@ -138,14 +145,14 @@ pub struct OperatorImpl {
138145
}
139146

140147
impl calculator::function::Server for OperatorImpl {
141-
fn call(
142-
&mut self,
148+
async fn call(
149+
&self,
143150
params: calculator::function::CallParams,
144151
mut results: calculator::function::CallResults,
145-
) -> Promise<(), Error> {
146-
let params = pry!(pry!(params.get()).get_params());
152+
) -> Result<(), Error> {
153+
let params = params.get()?.get_params()?;
147154
if params.len() != 2 {
148-
Promise::err(Error::failed("Wrong number of parameters.".to_string()))
155+
Err(Error::failed("Wrong number of parameters.".to_string()))
149156
} else {
150157
let v = match self.op {
151158
calculator::Operator::Add => params.get(0) + params.get(1),
@@ -154,50 +161,50 @@ impl calculator::function::Server for OperatorImpl {
154161
calculator::Operator::Divide => params.get(0) / params.get(1),
155162
};
156163
results.get().set_value(v);
157-
Promise::ok(())
164+
Ok(())
158165
}
159166
}
160167
}
161168

162169
struct CalculatorImpl;
163170

164171
impl calculator::Server for CalculatorImpl {
165-
fn evaluate(
166-
&mut self,
172+
async fn evaluate(
173+
&self,
167174
params: calculator::EvaluateParams,
168175
mut results: calculator::EvaluateResults,
169-
) -> Promise<(), Error> {
170-
Promise::from_future(async move {
171-
let v = evaluate_impl(params.get()?.get_expression()?, None).await?;
172-
results
173-
.get()
174-
.set_value(capnp_rpc::new_client(ValueImpl::new(v)));
175-
Ok(())
176-
})
176+
) -> Result<(), Error> {
177+
let v = evaluate_impl(params.get()?.get_expression()?, None).await?;
178+
results
179+
.get()
180+
.set_value(capnp_rpc::new_client(ValueImpl::new(v)));
181+
Ok(())
177182
}
178-
fn def_function(
179-
&mut self,
183+
184+
async fn def_function(
185+
&self,
180186
params: calculator::DefFunctionParams,
181187
mut results: calculator::DefFunctionResults,
182-
) -> Promise<(), Error> {
188+
) -> Result<(), Error> {
183189
results
184190
.get()
185-
.set_func(capnp_rpc::new_client(pry!(FunctionImpl::new(
186-
pry!(params.get()).get_param_count() as u32,
187-
pry!(pry!(params.get()).get_body())
188-
))));
189-
Promise::ok(())
191+
.set_func(capnp_rpc::new_client(FunctionImpl::new(
192+
params.get()?.get_param_count() as u32,
193+
params.get()?.get_body()?,
194+
)?));
195+
Ok(())
190196
}
191-
fn get_operator(
192-
&mut self,
197+
198+
async fn get_operator(
199+
&self,
193200
params: calculator::GetOperatorParams,
194201
mut results: calculator::GetOperatorResults,
195-
) -> Promise<(), Error> {
196-
let op = pry!(pry!(params.get()).get_op());
202+
) -> Result<(), Error> {
203+
let op = params.get()?.get_op()?;
197204
results
198205
.get()
199206
.set_func(capnp_rpc::new_client(OperatorImpl { op }));
200-
Promise::ok(())
207+
Ok(())
201208
}
202209
}
203210

capnp-rpc/examples/hello-world/server.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2020
// THE SOFTWARE.
2121

22-
use capnp::capability::Promise;
23-
use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, RpcSystem};
22+
use capnp_rpc::{rpc_twoparty_capnp, twoparty, RpcSystem};
2423

2524
use crate::hello_world_capnp::hello_world;
2625

@@ -30,17 +29,17 @@ use std::net::ToSocketAddrs;
3029
struct HelloWorldImpl;
3130

3231
impl hello_world::Server for HelloWorldImpl {
33-
fn say_hello(
34-
&mut self,
32+
async fn say_hello(
33+
&self,
3534
params: hello_world::SayHelloParams,
3635
mut results: hello_world::SayHelloResults,
37-
) -> Promise<(), ::capnp::Error> {
38-
let request = pry!(pry!(params.get()).get_request());
39-
let name = pry!(pry!(request.get_name()).to_str());
36+
) -> Result<(), ::capnp::Error> {
37+
let request = params.get()?.get_request()?;
38+
let name = request.get_name()?.to_str()?;
4039
let message = format!("Hello, {name}!");
4140
results.get().init_reply().set_message(message);
4241

43-
Promise::ok(())
42+
Ok(())
4443
}
4544
}
4645

capnp-rpc/examples/pubsub/client.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,23 @@
2020
// THE SOFTWARE.
2121

2222
use crate::pubsub_capnp::{publisher, subscriber};
23-
use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, RpcSystem};
23+
use capnp_rpc::{rpc_twoparty_capnp, twoparty, RpcSystem};
2424

25-
use capnp::capability::Promise;
2625
use futures::AsyncReadExt;
2726

2827
struct SubscriberImpl;
2928

3029
impl subscriber::Server<::capnp::text::Owned> for SubscriberImpl {
31-
fn push_message(
32-
&mut self,
30+
async fn push_message(
31+
&self,
3332
params: subscriber::PushMessageParams<::capnp::text::Owned>,
3433
_results: subscriber::PushMessageResults<::capnp::text::Owned>,
35-
) -> Promise<(), ::capnp::Error> {
34+
) -> Result<(), ::capnp::Error> {
3635
println!(
3736
"message from publisher: {}",
38-
pry!(pry!(pry!(params.get()).get_message()).to_str())
37+
params.get()?.get_message()?.to_str()?
3938
);
40-
Promise::ok(())
39+
Ok(())
4140
}
4241
}
4342

capnp-rpc/examples/pubsub/server.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,12 @@
1919
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2020
// THE SOFTWARE.
2121

22-
use std::cell::RefCell;
22+
use std::cell::{Cell, RefCell};
2323
use std::collections::HashMap;
2424
use std::rc::Rc;
2525

2626
use crate::pubsub_capnp::{publisher, subscriber, subscription};
27-
use capnp_rpc::{pry, rpc_twoparty_capnp, twoparty, RpcSystem};
28-
29-
use capnp::capability::Promise;
27+
use capnp_rpc::{rpc_twoparty_capnp, twoparty, RpcSystem};
3028

3129
use futures::{AsyncReadExt, FutureExt, StreamExt};
3230

@@ -68,7 +66,7 @@ impl Drop for SubscriptionImpl {
6866
impl subscription::Server for SubscriptionImpl {}
6967

7068
struct PublisherImpl {
71-
next_id: u64,
69+
next_id: Cell<u64>,
7270
subscribers: Rc<RefCell<SubscriberMap>>,
7371
}
7472

@@ -77,7 +75,7 @@ impl PublisherImpl {
7775
let subscribers = Rc::new(RefCell::new(SubscriberMap::new()));
7876
(
7977
Self {
80-
next_id: 0,
78+
next_id: Cell::new(0),
8179
subscribers: subscribers.clone(),
8280
},
8381
subscribers,
@@ -86,29 +84,29 @@ impl PublisherImpl {
8684
}
8785

8886
impl publisher::Server<::capnp::text::Owned> for PublisherImpl {
89-
fn subscribe(
90-
&mut self,
87+
async fn subscribe(
88+
&self,
9189
params: publisher::SubscribeParams<::capnp::text::Owned>,
9290
mut results: publisher::SubscribeResults<::capnp::text::Owned>,
93-
) -> Promise<(), ::capnp::Error> {
91+
) -> Result<(), ::capnp::Error> {
9492
println!("subscribe");
9593
self.subscribers.borrow_mut().subscribers.insert(
96-
self.next_id,
94+
self.next_id.get(),
9795
SubscriberHandle {
98-
client: pry!(pry!(params.get()).get_subscriber()),
96+
client: params.get()?.get_subscriber()?,
9997
requests_in_flight: 0,
10098
},
10199
);
102100

103101
results
104102
.get()
105103
.set_subscription(capnp_rpc::new_client(SubscriptionImpl::new(
106-
self.next_id,
104+
self.next_id.get(),
107105
self.subscribers.clone(),
108106
)));
109107

110-
self.next_id += 1;
111-
Promise::ok(())
108+
self.next_id.set(self.next_id.get() + 1);
109+
Ok(())
112110
}
113111
}
114112

0 commit comments

Comments
 (0)