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?
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)));