1

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?

Community
  • 1
  • 1
Dave
  • 1,784
  • 2
  • 23
  • 35
  • Aside: http://stackoverflow.com/questions/1725855/uint8-t-vs-unsigned-char (question is tagged c++11) – kfsone Jul 09 '16 at 19:49
  • I am aware of `uint8_t` but the unsigned char typedef is used inside CapnProto (KJ, actually), so I went with it. – Dave Jul 09 '16 at 20:11

1 Answers1

7

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)));
Kenton Varda
  • 41,353
  • 8
  • 121
  • 105
  • An answer by the author himself, awesome! Turns out I already had that, but my IDE (CLion, in this case) kept telling me that there is a `Type parameter mismatch: Class 'kj::ArrayPtr' is not compatible with class 'capnp::Data::Reader'`. Compiles and runs fine, though. I'm going to investigate and maybe file a bug. – Dave Jul 10 '16 at 18:29
  • Odd, there's definitely a constructor defined. BTW, I just realized there's also a `capnp::Data::Reader(ptr, size)` constructor which might confuse CLion less? – Kenton Varda Jul 10 '16 at 19:20
  • CLion Doesn't complain about the `capnp::Data::Reader(ptr, size)` constructor. Thanks! – Dave Jul 10 '16 at 20:05