Search code examples
c++c++11capnproto

How to get byte[] into capnp::Data


On the official website, there is a nice and relatively comprehensive example of how one could use CapnProto for C++ serialisation. What is missing, is how to handle the second Blob type capnp::Data, as only capnp::Text is covered.

Just for completeness, here is what the Schema Language says about the blob type:

Blobs: Text, Data

...

  • Text is always UTF-8 encoded and NUL-terminated.

  • Data is a completely arbitrary sequence of bytes.

So, if I have the following schema

struct Tiding {
    id @0 :Text;
    payload @1 :Data;
}

I can start building my message like this

::capnp::MallocMessageBuilder message;
Tiding::Builder tiding = message.initRoot<Tiding>();

tiding.setId("1");

At this point I got stuck. I can't do this:

typedef unsigned char byte;

byte data[100];
... //populate the array
tiding.setPayload(data)
//error: no viable conversion from 'byte [100]' to '::capnp::Data::Reader'

So I mucked around a bit and saw that capnp::Data is wrapping kj::ArrayPtr<const byte>, but I was unable to somehow get a hold of an ArrayPtr, much less use it to set the Payload field for my message.

I saw that there is a way to set the default value for the type Data (i.e. payload @5 :Data = 0x"a1 40 33";), but the schema language doesn't really translate to C++ in this case, so that also didn't help me.

I'd be grateful if somebody could point out what I am missing here. Also, how would I do this if I had List(Data) instead of just Data as the Payload in my schema?


Solution

  • A kj::ArrayPtr is fundamentally a pair of a pointer and a size.

    You can create one by calling kj::arrayPtr(), which takes two arguments: a pointer, and the array size. Example:

    byte buffer[256];
    kj::ArrayPtr<byte> bufferPtr = kj::arrayPtr(buffer, sizeof(buffer));
    

    kj::ArrayPtr has begin() and end() methods which return pointers, and a size() method. So you can convert back to pointer/size like:

    byte* ptr = bufferPtr.begin();
    size_t size = bufferPtr.size();
    

    Putting it all together, in your example, you want:

    tiding.setPayload(kj::arrayPtr(data, sizeof(data)));