Skip to content

Commit

Permalink
feat(packing): add packing to string and file support (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cohedrin authored and pbchekin committed Mar 12, 2018
1 parent 866aadb commit d3338bc
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 2 deletions.
39 changes: 39 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
FROM ubuntu:16.04

RUN apt-get update
RUN apt-get install -y software-properties-common python-software-properties
RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get -yq install gcc-7 g++-7 git curl make libssl-dev libreadline-dev zlib1g-dev

RUN update-alternatives --quiet \
--install /usr/bin/gcc gcc /usr/bin/gcc-7 10 \
--slave /usr/bin/g++ g++ /usr/bin/g++-7 \
--slave /usr/bin/gcov gcov /usr/bin/gcov-7
RUN update-alternatives --quiet --set gcc /usr/bin/gcc-7

RUN apt-get install -y bzip2
RUN apt-get install -y build-essential
# ruby
RUN git clone https://github.com/rbenv/rbenv.git /usr/local/.rbenv
ENV PATH /usr/local/.rbenv/bin:$PATH
RUN eval "$(rbenv init -)"

RUN git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
RUN echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
RUN export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"
RUN rbenv install 2.4.1 && rbenv global 2.4.1
RUN apt-get install -y ruby-full

RUN gem install bundler -v 1.16.0ex
RUN rbenv rehash

RUN curl -O https://capnproto.org/capnproto-c++-0.6.1.tar.gz \
&& tar zxf capnproto-c++-0.6.1.tar.gz \
&& cd capnproto-c++-0.6.1 \
&& ./configure \
&& make -j6 check \
&& make install

RUN ln -sf /usr/bin/g++-7 /usr/bin/g++ && ln -sf /usr/bin/gcc-7 /usr/bin/gcc

61 changes: 60 additions & 1 deletion ext/capn_proto/dynamic_struct_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "class_builder.h"
#include "exception.h"
#include "util.h"
#include "rb_str_output_stream.h"

namespace ruby_capn_proto {
using WrappedType = capnp::DynamicStruct::Builder;
Expand All @@ -18,6 +19,9 @@ namespace ruby_capn_proto {
defineAlloc(&alloc).
defineMethod("which", &which).
defineMethod("write", &write).
defineMethod("write_packed", &write_packed).
defineMethod("to_packed_string", &to_packed_string).
defineMethod("to_string", &to_string).
defineMethod("to_bytes", &to_bytes).
defineMethod("[]", &get).
defineMethod("[]=", &set).
Expand Down Expand Up @@ -148,7 +152,62 @@ namespace ruby_capn_proto {
}
}

VALUE DynamicStructBuilder::to_bytes(VALUE self) {
VALUE DynamicStructBuilder::write_packed(VALUE self, VALUE file) {
VALUE rb_fileno = rb_funcall(file, rb_intern("fileno"), 0);
int fileno = FIX2INT(rb_fileno);
if (!RTEST(rb_iv_get(self, "is_root"))) {
rb_raise(Exception::Class, "You can only call write_packed() on the message's root struct.");
}

capnp::MessageBuilder* message_builder = MallocMessageBuilder::unwrap(rb_iv_get(self, "parent"));
try {
capnp::writePackedMessageToFd(fileno, message_builder->getSegmentsForOutput());
return Qnil;
} catch (kj::Exception ex) {
return Exception::raise(ex);
}
}

VALUE DynamicStructBuilder::to_string(VALUE self, VALUE str) {
if (!RTEST(rb_iv_get(self, "is_root")))
{
rb_raise(Exception::Class, "You can only call write_packed() on the message's root struct.");
}

auto str_output = new RbStrOutputStream(str);
capnp::MessageBuilder *message_builder = MallocMessageBuilder::unwrap(rb_iv_get(self, "parent"));
try
{
capnp::writeMessage(*str_output, message_builder->getSegmentsForOutput());
return Qnil;
}
catch (kj::Exception ex)
{
return Exception::raise(ex);
}
}

VALUE DynamicStructBuilder::to_packed_string(VALUE self, VALUE str) {
if (!RTEST(rb_iv_get(self, "is_root")))
{
rb_raise(Exception::Class, "You can only call write_packed() on the message's root struct.");
}

auto str_output = new RbStrOutputStream(str);
capnp::MessageBuilder *message_builder = MallocMessageBuilder::unwrap(rb_iv_get(self, "parent"));
try
{
capnp::writePackedMessage(*str_output, message_builder->getSegmentsForOutput());
return Qnil;
}
catch (kj::Exception ex)
{
return Exception::raise(ex);
}
}

VALUE DynamicStructBuilder::to_bytes(VALUE self)
{
if (!RTEST(rb_iv_get(self, "is_root"))) {
rb_raise(Exception::Class, "You can only call to_bytes() on the message's root struct.");
}
Expand Down
3 changes: 3 additions & 0 deletions ext/capn_proto/dynamic_struct_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ namespace ruby_capn_proto {
static VALUE init(int argc, VALUE* argv, VALUE self);

static VALUE write(VALUE self, VALUE file);
static VALUE write_packed(VALUE self, VALUE file);
static VALUE to_packed_string(VALUE self, VALUE str);
static VALUE to_string(VALUE self, VALUE str);
static VALUE to_bytes(VALUE self);

static VALUE Class;
Expand Down
12 changes: 12 additions & 0 deletions ext/capn_proto/rb_str_output_stream.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include "ruby_capn_proto.h"
#include "rb_str_output_stream.h"

namespace ruby_capn_proto {
RbStrOutputStream::~RbStrOutputStream() noexcept(false) {}

void RbStrOutputStream::write(const void *buffer, size_t size)
{
const char *pos = reinterpret_cast<const char *>(buffer);
rb_str_cat(str, pos, size);
}
}
24 changes: 24 additions & 0 deletions ext/capn_proto/rb_str_output_stream.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef RB_STR_OUTPUT_STREAM_H
#define RB_STR_OUTPUT_STREAM_H

#include "ruby_capn_proto.h"
#include "kj/io.h"

namespace ruby_capn_proto
{
class RbStrOutputStream : public kj::OutputStream {
// An OutputStream wrapping string buffer

public:
explicit RbStrOutputStream(VALUE str) : str(str) {}
KJ_DISALLOW_COPY(RbStrOutputStream);
~RbStrOutputStream() noexcept(false);

void write(const void *buffer, size_t size) override;

private:
VALUE str;
};
}

#endif /* RB_STR_OUTPUT_STREAM_H */
2 changes: 1 addition & 1 deletion lib/capn_proto/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module CapnProto
VERSION = "0.0.1.alpha.8"
VERSION = "0.0.1.alpha.9"
end
21 changes: 21 additions & 0 deletions spec/capn_proto_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,27 @@ module AddressBook extend CapnProto::SchemaLoader
end
end

describe "#to_string" do
it "writes the message to a string" do
addresses = AddressBook::AddressBook.new_message
people = addresses.initPeople(1)
bob = people[0]
bob.name = "Bob"
bob.id = 123
str = ""
addresses.to_string(str)

tmp = Tempfile.new('test.bin')
tmp << str
tmp.rewind

addresses = AddressBook::AddressBook.read_from(tmp)
expect(addresses.people.size).to eq 1
expect(addresses.people.first.name).to eq "Bob"
expect(addresses.people.first.id).to eq 123
end
end

describe "Dynamic Structs" do
let(:addresses) { AddressBook::AddressBook.new_message }

Expand Down

0 comments on commit d3338bc

Please sign in to comment.