Amusingly, I was just looking at this for a protocol. Kenton's suggestion to use List[Data] works, but it carries an unintended buffering problem. A message can have multiple segments, and a correct capn-proto implementation will extend its segment pool as needed to hold a large byte sequence, but if I read the encoding spec correctly, it cannot
send any of the segments until
all of the segments are available for framing. Which means that your big blob of data sits in client memory while you are loading it, and stays there until the message is fully transmitted . Segment release could be optimized by releasing segments as transmission proceeds, but that isn't required by the capn-proto specification, and it doesn't resolve the "load big blob into memory" problem.
One alternative is to introduce a builder pattern, something like this:
interface FileBuilder {
write @0 (d : Data) -> Int32; # Returns number of bytes written
close @1 () -> (file: File)
}
interface MyService {
createFile @0 () -> (builder; FileBuilder)
myInterestingCall @1 (... file: File, ...) -> (val: InterestingResult)
}
The advantage to this, mainly, is that the byte transmission is divided into a sequence of messages. On the service side, these can be stashed aside until the Close() call is made, at which point the file object is fabricated on the service and a File capability is returned to the client that can be included in other messages. Because of promise pipelining, this doesn't take as many round trips as you might think.
The main puzzle here, in my mind, is that the server needs to know when client-side capabilities. I don't remember seeing anything like a capability release protocol that advises the serving entity when the state associated with an ephemeral object can be released.