mirror of
https://github.com/zap-proto/ruby.git
synced 2026-10-30 15:04:01 +00:00
Rebrand all ZAP-facing identifiers off Cap'n Proto: - module Capnp→Zap, ext binding namespace ruby_capn_proto→ruby_zap, header guard RUBY_CAPN_PROTO_H→RUBY_ZAP_H, entry point Init_zap, gem capn_proto→zap, schemas .capnp→.zap, media/logo, gemspec, README, spec, examples. Zero capnp/Cap'n Proto brand prose remains. Binding-namespace nuance (kept on purpose): the native ext links the upstream serialization runtime (libcapnp/kj). Its capnp:: C++ symbols and <capnp/...> headers are the linked library's real API — there is no zap:: namespace or libzap to retarget to yet — so those references, the -lcapnp/-lcapnpc/-lkj link flags, and the pycapnp dev-only fixture generators stay, each documented as the external dependency surface (retargets to <zap/...>/-lzap when the ZAP C++ runtime ships). Build/modernization: - extconf.rb: discover the runtime via dir_config + pkg_config so the ext builds against non-default prefixes (e.g. Homebrew), not just /usr/local. Native ext now compiles + links cleanly (zap.bundle). - ext: parenthesize `if (FIXNUM_P(x))` in the two dynamic builders — required since Ruby's FIXNUM_P macro no longer wraps its expansion (Ruby 4 build break). - Rakefile: put lib on $LOAD_PATH and load the gemspec via Gem::Specification.load; pin rake-compiler ~> 0.9; make the rspec rake task degrade with a clear message instead of aborting the whole Rakefile when the harness can't load. - gemspec: bump dev deps within-major (rspec ~> 2.14, rake ~> 13.0, rake-compiler ~> 0.9); add required_ruby_version. - .gitignore: ignore native-ext build artifacts (*.o, Makefile, mkmf.log, *.bundle.dSYM, *.gem). Verified: all spec/zap_spec.rb assertions pass against the compiled binding (write/read + to_bytes round-trips, unknown-field and out-of-bounds raise Zap::Exception, dynamic struct assign); the addressbook example decodes end-to-end.
124 lines
3.6 KiB
C++
124 lines
3.6 KiB
C++
#include "ruby_zap.h"
|
|
#include "dynamic_list_builder.h"
|
|
#include "dynamic_value_builder.h"
|
|
#include "dynamic_struct_reader.h"
|
|
#include "dynamic_struct_builder.h"
|
|
#include "exception.h"
|
|
#include "util.h"
|
|
#include "class_builder.h"
|
|
|
|
namespace ruby_zap {
|
|
using WrappedType = capnp::DynamicList::Builder;
|
|
VALUE DynamicListBuilder::Class;
|
|
|
|
void DynamicListBuilder::Init() {
|
|
ClassBuilder("DynamicListBuilder", rb_cObject).
|
|
defineAlloc(&alloc).
|
|
defineMethod("[]", &get).
|
|
defineMethod("[]=", &set).
|
|
defineMethod("size", &size).
|
|
store(&Class);
|
|
}
|
|
|
|
VALUE DynamicListBuilder::alloc(VALUE klass) {
|
|
return Data_Wrap_Struct(klass, NULL, free, ruby_xmalloc(sizeof(WrappedType)));
|
|
}
|
|
|
|
void DynamicListBuilder::free(WrappedType* p) {
|
|
p->~Builder();
|
|
ruby_xfree(p);
|
|
}
|
|
|
|
WrappedType* DynamicListBuilder::unwrap(VALUE self) {
|
|
WrappedType* p;
|
|
Data_Get_Struct(self, WrappedType, p);
|
|
return p;
|
|
}
|
|
|
|
VALUE DynamicListBuilder::create(WrappedType builder, VALUE parent) {
|
|
auto rb_obj = alloc(Class);
|
|
WrappedType* wrapped = unwrap(rb_obj);
|
|
*wrapped = kj::mv(builder);
|
|
|
|
rb_iv_set(rb_obj, "parent", parent);
|
|
|
|
return rb_obj;
|
|
}
|
|
|
|
VALUE DynamicListBuilder::size(VALUE self) {
|
|
return INT2FIX(unwrap(self)->size());
|
|
}
|
|
|
|
VALUE DynamicListBuilder::get(VALUE self, VALUE rb_index) {
|
|
try {
|
|
return _get(self, rb_index);
|
|
} catch (kj::Exception ex) {
|
|
return Exception::raise(ex);
|
|
}
|
|
}
|
|
|
|
VALUE DynamicListBuilder::_get(VALUE self, VALUE rb_index) {
|
|
auto builder = *unwrap(self);
|
|
auto size = builder.size();
|
|
|
|
unsigned long index;
|
|
if (Util::isNegative(rb_index)) {
|
|
index = NUM2LONG(rb_index) % builder.size();
|
|
} else {
|
|
index = NUM2ULONG(rb_index);
|
|
}
|
|
|
|
// return DynamicValueBuilder::to_ruby(builder.get(field), self);
|
|
return DynamicValueBuilder::to_ruby(builder[index], self);
|
|
}
|
|
|
|
VALUE DynamicListBuilder::set(VALUE self, VALUE rb_index, VALUE rb_obj) {
|
|
try {
|
|
return _set(self, rb_index, rb_obj);
|
|
} catch (kj::Exception ex) {
|
|
return Exception::raise(ex);
|
|
}
|
|
}
|
|
|
|
VALUE DynamicListBuilder::_set(VALUE self, VALUE rb_index, VALUE rb_obj) {
|
|
VALUE klass = rb_funcall(rb_obj, rb_intern("class"), 0);
|
|
|
|
unsigned long field;
|
|
if (Util::isNegative(rb_index)) {
|
|
field = NUM2LONG(rb_index) % unwrap(self)->size();
|
|
} else {
|
|
field = NUM2ULONG(rb_index);
|
|
}
|
|
|
|
// TODO: handle assigning lists (see _setDynamicField)
|
|
if (FIXNUM_P(rb_obj)) {
|
|
if (Util::isNegative(rb_obj)) {
|
|
unwrap(self)->set(field, NUM2LONG(rb_obj));
|
|
} else {
|
|
unwrap(self)->set(field, NUM2ULONG(rb_obj));
|
|
}
|
|
} else if (RB_TYPE_P(rb_obj, T_FLOAT)) {
|
|
unwrap(self)->set(field, RFLOAT_VALUE(rb_obj));
|
|
} else if (rb_obj == Qtrue || rb_obj == Qfalse) {
|
|
unwrap(self)->set(field, (rb_obj == Qtrue) ? true : false);
|
|
} else if (RB_TYPE_P(rb_obj, T_STRING)) {
|
|
// TODO: need to ensure that the UTF8 char buffer is null terminated.
|
|
// consider something similar to rb_string_value_cstr,
|
|
// which grows the the buffer if necessary.
|
|
capnp::DynamicValue::Reader tmp =
|
|
capnp::Text::Reader(RSTRING_PTR(rb_obj), RSTRING_LEN(rb_obj));
|
|
unwrap(self)->set(field, tmp);
|
|
} else if (NIL_P(rb_obj)) {
|
|
unwrap(self)->set(field, capnp::VOID);
|
|
} else if (rb_equal(klass, DynamicStructReader::Class)) {
|
|
unwrap(self)->set(field, *DynamicStructReader::unwrap(rb_obj));
|
|
} else if (rb_equal(klass, DynamicStructBuilder::Class)) {
|
|
unwrap(self)->set(field, (*DynamicStructBuilder::unwrap(rb_obj)).asReader());
|
|
} else {
|
|
// TODO: raise "Non primitive type"
|
|
}
|
|
|
|
return rb_obj;
|
|
}
|
|
}
|