Hot questions for Using Cap'n Proto in promise

Question:

I would like to try promise pipelining with Cap'n Proto C++ RPC but I don't know how to do it.

Here is my schema :

interface Test {
  getInt @0 () -> (intResult :Int32);
  increment @1 (intParam :Int32) -> (intResult :Int32);
}

Here is what I would like to do (pseudo-code) :

increment(getInt());

I tried to do something like that :

auto request1 = test.getIntRequest();
auto promise = request1.send();

auto request2 = test.incrementRequest();
request2.setIntParam(promise.getIntResult()) // HERE IS THE PROBLEM
auto promise2 = request2.send();

but it is not the good way to use promises. I hope you understand what I want to do.

Thank you.

EDIT : an other question : how to implement the methods on the server ?

I have written this code :

#include <kj/debug.h>
#include <capnp/ez-rpc.h>
#include <capnp/message.h>
#include <iostream>
#include "test.capnp.h"

using namespace std;


class TestI : virtual public Test::Server
{
public:
      TestI() {}
      ::kj::Promise<void> getInt(GetIntContext context) 
      {
            // ????
      }
      ::kj::Promise<void> increment(IncrementContext context) 
      {
            // ????
      }
};

class Int32BoxI : virtual public Int32Box::Server
{
private:
      int val = 12;
public:
      Int32BoxI(int value): val(value) {}
      ::kj::Promise<void> get(GetContext context)
      {
            context.getResults().setValue(this->val);
            return kj::READY_NOW;
      }
}

but I don't know how to implement getInt() and increment().


Answer:

The problem here is that you're trying to pipeline on an int, but pipelining only works with object references. You can solve this by wrapping the int in an object, like so:

interface Int32Box {
  get @0 () -> (value :Int32);
}

interface Test {
  getInt @0 () -> (intResult :Int32Box);
  increment @1 (intParam :Int32Box) -> (intResult :Int32Box);
}

Now your code will work as written.

Of course, now you have to additionally call .get() on the final Int32Box in order to read the value. Luckily, though, you can pipeline this call, so that it doesn't require any additional network round trips.

auto request1 = test.getIntRequest();
auto promise = request1.send();

auto request2 = test.incrementRequest();
request2.setIntParam(promise.getIntResult());
auto promise2 = request2.send();

auto request3 = promise2.getIntResult().getRequest();
auto promise3 = request3.send();

// This is the only wait!
int finalResult = promise3.wait().getValue();

The above sequence executes with only one network round trip.