commit
55cf8abecb
54 changed files with 23717 additions and 462 deletions
@ -1,3 +0,0 @@ |
||||
[submodule "upb"] |
||||
path = upb |
||||
url = https://github.com/haberman/upb |
@ -0,0 +1,4 @@ |
||||
language: cpp |
||||
script: ./autogen.sh && ./configure && make distcheck |
||||
notifications: |
||||
email: false |
@ -0,0 +1,67 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package com.google.protobuf.nano; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Utility class for maps support. |
||||
*/ |
||||
public final class MapFactories { |
||||
public static interface MapFactory { |
||||
<K, V> Map<K, V> forMap(Map<K, V> oldMap); |
||||
} |
||||
|
||||
// NOTE(liujisi): The factory setter is temporarily marked as package private.
|
||||
// The way to provide customized implementations of maps for different
|
||||
// platforms are still under discussion. Mark it as private to avoid exposing
|
||||
// the API in proto3 alpha release.
|
||||
/* public */ static void setMapFactory(MapFactory newMapFactory) { |
||||
mapFactory = newMapFactory; |
||||
} |
||||
|
||||
public static MapFactory getMapFactory() { |
||||
return mapFactory; |
||||
} |
||||
|
||||
private static class DefaultMapFactory implements MapFactory { |
||||
public <K, V> Map<K, V> forMap(Map<K, V> oldMap) { |
||||
if (oldMap == null) { |
||||
return new HashMap<K, V>(); |
||||
} |
||||
return oldMap; |
||||
} |
||||
} |
||||
private static volatile MapFactory mapFactory = new DefaultMapFactory(); |
||||
|
||||
private MapFactories() {} |
||||
} |
@ -0,0 +1,70 @@ |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// https://developers.google.com/protocol-buffers/ |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// * Neither the name of Google Inc. nor the names of its |
||||
// contributors may be used to endorse or promote products derived from |
||||
// this software without specific prior written permission. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
package map_test; |
||||
|
||||
option java_package = "com.google.protobuf.nano"; |
||||
option java_outer_classname = "MapTestProto"; |
||||
|
||||
message TestMap { |
||||
message MessageValue { |
||||
int32 value = 1; |
||||
int32 value2 = 2; |
||||
} |
||||
enum EnumValue { |
||||
FOO = 0; |
||||
BAR = 1; |
||||
BAZ = 2; |
||||
QUX = 3; |
||||
} |
||||
|
||||
map<int32, int32> int32_to_int32_field = 1; |
||||
map<int32, string> int32_to_string_field = 2; |
||||
map<int32, bytes> int32_to_bytes_field = 3; |
||||
map<int32, EnumValue> int32_to_enum_field = 4; |
||||
map<int32, MessageValue> int32_to_message_field = 5; |
||||
map<string, int32> string_to_int32_field = 6; |
||||
map<bool, bool> bool_to_bool_field = 7; |
||||
|
||||
// Test all the other primitive types. As the key and value are not coupled in |
||||
// the implementation, we do not test all the combinations of key/value pairs, |
||||
// so that we can keep the number of test cases manageable |
||||
map<uint32, uint32> uint32_to_uint32_field = 11; |
||||
map<sint32, sint32> sint32_to_sint32_field = 12; |
||||
map<fixed32, fixed32> fixed32_to_fixed32_field = 13; |
||||
map<sfixed32, sfixed32> sfixed32_to_sfixed32_field = 14; |
||||
map<int64, int64> int64_to_int64_field = 15; |
||||
map<uint64, uint64> uint64_to_uint64_field = 16; |
||||
map<sint64, sint64> sint64_to_sint64_field = 17; |
||||
map<fixed64, fixed64> fixed64_to_fixed64_field = 18; |
||||
map<sfixed64, sfixed64> sfixed64_to_sfixed64_field = 19; |
||||
} |
@ -0,0 +1,35 @@ |
||||
# Protocol Buffers - Google's data interchange format |
||||
# Copyright 2008 Google Inc. All rights reserved. |
||||
# https://developers.google.com/protocol-buffers/ |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions are |
||||
# met: |
||||
# |
||||
# * Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# * Redistributions in binary form must reproduce the above |
||||
# copyright notice, this list of conditions and the following disclaimer |
||||
# in the documentation and/or other materials provided with the |
||||
# distribution. |
||||
# * Neither the name of Google Inc. nor the names of its |
||||
# contributors may be used to endorse or promote products derived from |
||||
# this software without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
# Needs to stay compatible with Python 2.5 due to GAE. |
||||
# |
||||
# Copyright 2007 Google Inc. All Rights Reserved. |
||||
|
||||
__version__ = '3.0.0-pre' |
@ -1,27 +0,0 @@ |
||||
# Description: |
||||
# An example package that contains nested protos that are imported from |
||||
# __init__.py. See testPackageInitializationImport in reflection_test.py for |
||||
# details. |
||||
|
||||
package( |
||||
default_visibility = ["//net/proto2/python/internal:__pkg__"], |
||||
) |
||||
|
||||
proto_library( |
||||
name = "inner_proto", |
||||
srcs = ["inner.proto"], |
||||
py_api_version = 2, |
||||
) |
||||
|
||||
proto_library( |
||||
name = "outer_proto", |
||||
srcs = ["outer.proto"], |
||||
py_api_version = 2, |
||||
deps = [":inner_proto"], |
||||
) |
||||
|
||||
py_library( |
||||
name = "import_test_package", |
||||
srcs = ["__init__.py"], |
||||
deps = [":outer_proto"], |
||||
) |
@ -0,0 +1,10 @@ |
||||
#!/usr/bin/ruby |
||||
|
||||
require 'mkmf' |
||||
|
||||
$CFLAGS += " -O3 -std=c99 -Wno-unused-function -DNDEBUG " |
||||
|
||||
$objs = ["protobuf.o", "defs.o", "storage.o", "message.o", |
||||
"repeated_field.o", "map.o", "encode_decode.o", "upb.o"] |
||||
|
||||
create_makefile("google/protobuf_c") |
@ -0,0 +1,805 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "protobuf.h" |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Basic map operations on top of upb's strtable.
|
||||
//
|
||||
// Note that we roll our own `Map` container here because, as for
|
||||
// `RepeatedField`, we want a strongly-typed container. This is so that any user
|
||||
// errors due to incorrect map key or value types are raised as close as
|
||||
// possible to the error site, rather than at some deferred point (e.g.,
|
||||
// serialization).
|
||||
//
|
||||
// We build our `Map` on top of upb_strtable so that we're able to take
|
||||
// advantage of the native_slot storage abstraction, as RepeatedField does.
|
||||
// (This is not quite a perfect mapping -- see the key conversions below -- but
|
||||
// gives us full support and error-checking for all value types for free.)
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Map values are stored using the native_slot abstraction (as with repeated
|
||||
// field values), but keys are a bit special. Since we use a strtable, we need
|
||||
// to store keys as sequences of bytes such that equality of those bytes maps
|
||||
// one-to-one to equality of keys. We store strings directly (i.e., they map to
|
||||
// their own bytes) and integers as native integers (using the native_slot
|
||||
// abstraction).
|
||||
|
||||
// Note that there is another tradeoff here in keeping string keys as native
|
||||
// strings rather than Ruby strings: traversing the Map requires conversion to
|
||||
// Ruby string values on every traversal, potentially creating more garbage. We
|
||||
// should consider ways to cache a Ruby version of the key if this becomes an
|
||||
// issue later.
|
||||
|
||||
// Forms a key to use with the underlying strtable from a Ruby key value. |buf|
|
||||
// must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to
|
||||
// construct a key byte sequence if needed. |out_key| and |out_length| provide
|
||||
// the resulting key data/length.
|
||||
#define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t)
|
||||
static void table_key(Map* self, VALUE key, |
||||
char* buf, |
||||
const char** out_key, |
||||
size_t* out_length) { |
||||
switch (self->key_type) { |
||||
case UPB_TYPE_BYTES: |
||||
case UPB_TYPE_STRING: |
||||
// Strings: use string content directly.
|
||||
Check_Type(key, T_STRING); |
||||
native_slot_validate_string_encoding(self->key_type, key); |
||||
*out_key = RSTRING_PTR(key); |
||||
*out_length = RSTRING_LEN(key); |
||||
break; |
||||
|
||||
case UPB_TYPE_BOOL: |
||||
case UPB_TYPE_INT32: |
||||
case UPB_TYPE_INT64: |
||||
case UPB_TYPE_UINT32: |
||||
case UPB_TYPE_UINT64: |
||||
native_slot_set(self->key_type, Qnil, buf, key); |
||||
*out_key = buf; |
||||
*out_length = native_slot_size(self->key_type); |
||||
break; |
||||
|
||||
default: |
||||
// Map constructor should not allow a Map with another key type to be
|
||||
// constructed.
|
||||
assert(false); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) { |
||||
switch (self->key_type) { |
||||
case UPB_TYPE_BYTES: |
||||
case UPB_TYPE_STRING: { |
||||
VALUE ret = rb_str_new(buf, length); |
||||
rb_enc_associate(ret, |
||||
(self->key_type == UPB_TYPE_BYTES) ? |
||||
kRubyString8bitEncoding : kRubyStringUtf8Encoding); |
||||
return ret; |
||||
} |
||||
|
||||
case UPB_TYPE_BOOL: |
||||
case UPB_TYPE_INT32: |
||||
case UPB_TYPE_INT64: |
||||
case UPB_TYPE_UINT32: |
||||
case UPB_TYPE_UINT64: |
||||
return native_slot_get(self->key_type, Qnil, buf); |
||||
|
||||
default: |
||||
assert(false); |
||||
return Qnil; |
||||
} |
||||
} |
||||
|
||||
static void* value_memory(upb_value* v) { |
||||
return (void*)(&v->val.uint64); |
||||
} |
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Map container type.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const rb_data_type_t Map_type = { |
||||
"Google::Protobuf::Map", |
||||
{ Map_mark, Map_free, NULL }, |
||||
}; |
||||
|
||||
VALUE cMap; |
||||
|
||||
Map* ruby_to_Map(VALUE _self) { |
||||
Map* self; |
||||
TypedData_Get_Struct(_self, Map, &Map_type, self); |
||||
return self; |
||||
} |
||||
|
||||
void Map_mark(void* _self) { |
||||
Map* self = _self; |
||||
|
||||
rb_gc_mark(self->value_type_class); |
||||
|
||||
if (self->value_type == UPB_TYPE_STRING || |
||||
self->value_type == UPB_TYPE_BYTES || |
||||
self->value_type == UPB_TYPE_MESSAGE) { |
||||
upb_strtable_iter it; |
||||
for (upb_strtable_begin(&it, &self->table); |
||||
!upb_strtable_done(&it); |
||||
upb_strtable_next(&it)) { |
||||
upb_value v = upb_strtable_iter_value(&it); |
||||
void* mem = value_memory(&v); |
||||
native_slot_mark(self->value_type, mem); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void Map_free(void* _self) { |
||||
Map* self = _self; |
||||
upb_strtable_uninit(&self->table); |
||||
xfree(self); |
||||
} |
||||
|
||||
VALUE Map_alloc(VALUE klass) { |
||||
Map* self = ALLOC(Map); |
||||
memset(self, 0, sizeof(Map)); |
||||
self->value_type_class = Qnil; |
||||
VALUE ret = TypedData_Wrap_Struct(klass, &Map_type, self); |
||||
return ret; |
||||
} |
||||
|
||||
static bool needs_typeclass(upb_fieldtype_t type) { |
||||
switch (type) { |
||||
case UPB_TYPE_MESSAGE: |
||||
case UPB_TYPE_ENUM: |
||||
return true; |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.new(key_type, value_type, value_typeclass = nil, init_hashmap = {}) |
||||
* => new map |
||||
* |
||||
* Allocates a new Map container. This constructor may be called with 2, 3, or 4 |
||||
* arguments. The first two arguments are always present and are symbols (taking |
||||
* on the same values as field-type symbols in message descriptors) that |
||||
* indicate the type of the map key and value fields. |
||||
* |
||||
* The supported key types are: :int32, :int64, :uint32, :uint64, :bool, |
||||
* :string, :bytes. |
||||
* |
||||
* The supported value types are: :int32, :int64, :uint32, :uint64, :bool, |
||||
* :string, :bytes, :enum, :message. |
||||
* |
||||
* The third argument, value_typeclass, must be present if value_type is :enum |
||||
* or :message. As in RepeatedField#new, this argument must be a message class |
||||
* (for :message) or enum module (for :enum). |
||||
* |
||||
* The last argument, if present, provides initial content for map. Note that |
||||
* this may be an ordinary Ruby hashmap or another Map instance with identical |
||||
* key and value types. Also note that this argument may be present whether or |
||||
* not value_typeclass is present (and it is unambiguously separate from |
||||
* value_typeclass because value_typeclass's presence is strictly determined by |
||||
* value_type). The contents of this initial hashmap or Map instance are |
||||
* shallow-copied into the new Map: the original map is unmodified, but |
||||
* references to underlying objects will be shared if the value type is a |
||||
* message type. |
||||
*/ |
||||
VALUE Map_init(int argc, VALUE* argv, VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
// We take either two args (:key_type, :value_type), three args (:key_type,
|
||||
// :value_type, "ValueMessageType"), or four args (the above plus an initial
|
||||
// hashmap).
|
||||
if (argc < 2 || argc > 4) { |
||||
rb_raise(rb_eArgError, "Map constructor expects 2, 3 or 4 arguments."); |
||||
} |
||||
|
||||
self->key_type = ruby_to_fieldtype(argv[0]); |
||||
self->value_type = ruby_to_fieldtype(argv[1]); |
||||
|
||||
// Check that the key type is an allowed type.
|
||||
switch (self->key_type) { |
||||
case UPB_TYPE_INT32: |
||||
case UPB_TYPE_INT64: |
||||
case UPB_TYPE_UINT32: |
||||
case UPB_TYPE_UINT64: |
||||
case UPB_TYPE_BOOL: |
||||
case UPB_TYPE_STRING: |
||||
case UPB_TYPE_BYTES: |
||||
// These are OK.
|
||||
break; |
||||
default: |
||||
rb_raise(rb_eArgError, "Invalid key type for map."); |
||||
} |
||||
|
||||
int init_value_arg = 2; |
||||
if (needs_typeclass(self->value_type) && argc > 2) { |
||||
self->value_type_class = argv[2]; |
||||
validate_type_class(self->value_type, self->value_type_class); |
||||
init_value_arg = 3; |
||||
} |
||||
|
||||
// Table value type is always UINT64: this ensures enough space to store the
|
||||
// native_slot value.
|
||||
if (!upb_strtable_init(&self->table, UPB_CTYPE_UINT64)) { |
||||
rb_raise(rb_eRuntimeError, "Could not allocate table."); |
||||
} |
||||
|
||||
if (argc > init_value_arg) { |
||||
Map_merge_into_self(_self, argv[init_value_arg]); |
||||
} |
||||
|
||||
return Qnil; |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.each(&block) |
||||
* |
||||
* Invokes &block on each |key, value| pair in the map, in unspecified order. |
||||
* Note that Map also includes Enumerable; map thus acts like a normal Ruby |
||||
* sequence. |
||||
*/ |
||||
VALUE Map_each(VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
upb_strtable_iter it; |
||||
for (upb_strtable_begin(&it, &self->table); |
||||
!upb_strtable_done(&it); |
||||
upb_strtable_next(&it)) { |
||||
|
||||
VALUE key = table_key_to_ruby( |
||||
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); |
||||
|
||||
upb_value v = upb_strtable_iter_value(&it); |
||||
void* mem = value_memory(&v); |
||||
VALUE value = native_slot_get(self->value_type, |
||||
self->value_type_class, |
||||
mem); |
||||
|
||||
rb_yield_values(2, key, value); |
||||
} |
||||
|
||||
return Qnil; |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.keys => [list_of_keys] |
||||
* |
||||
* Returns the list of keys contained in the map, in unspecified order. |
||||
*/ |
||||
VALUE Map_keys(VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
VALUE ret = rb_ary_new(); |
||||
upb_strtable_iter it; |
||||
for (upb_strtable_begin(&it, &self->table); |
||||
!upb_strtable_done(&it); |
||||
upb_strtable_next(&it)) { |
||||
|
||||
VALUE key = table_key_to_ruby( |
||||
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); |
||||
|
||||
rb_ary_push(ret, key); |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.values => [list_of_values] |
||||
* |
||||
* Returns the list of values contained in the map, in unspecified order. |
||||
*/ |
||||
VALUE Map_values(VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
VALUE ret = rb_ary_new(); |
||||
upb_strtable_iter it; |
||||
for (upb_strtable_begin(&it, &self->table); |
||||
!upb_strtable_done(&it); |
||||
upb_strtable_next(&it)) { |
||||
|
||||
upb_value v = upb_strtable_iter_value(&it); |
||||
void* mem = value_memory(&v); |
||||
VALUE value = native_slot_get(self->value_type, |
||||
self->value_type_class, |
||||
mem); |
||||
|
||||
rb_ary_push(ret, value); |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.[](key) => value |
||||
* |
||||
* Accesses the element at the given key. Throws an exception if the key type is |
||||
* incorrect. Returns nil when the key is not present in the map. |
||||
*/ |
||||
VALUE Map_index(VALUE _self, VALUE key) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH]; |
||||
const char* keyval = NULL; |
||||
size_t length = 0; |
||||
table_key(self, key, keybuf, &keyval, &length); |
||||
|
||||
upb_value v; |
||||
if (upb_strtable_lookup2(&self->table, keyval, length, &v)) { |
||||
void* mem = value_memory(&v); |
||||
return native_slot_get(self->value_type, self->value_type_class, mem); |
||||
} else { |
||||
return Qnil; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.[]=(key, value) => value |
||||
* |
||||
* Inserts or overwrites the value at the given key with the given new value. |
||||
* Throws an exception if the key type is incorrect. Returns the new value that |
||||
* was just inserted. |
||||
*/ |
||||
VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH]; |
||||
const char* keyval = NULL; |
||||
size_t length = 0; |
||||
table_key(self, key, keybuf, &keyval, &length); |
||||
|
||||
upb_value v; |
||||
void* mem = value_memory(&v); |
||||
native_slot_set(self->value_type, self->value_type_class, mem, value); |
||||
|
||||
// Replace any existing value by issuing a 'remove' operation first.
|
||||
upb_strtable_remove2(&self->table, keyval, length, NULL); |
||||
if (!upb_strtable_insert2(&self->table, keyval, length, v)) { |
||||
rb_raise(rb_eRuntimeError, "Could not insert into table"); |
||||
} |
||||
|
||||
// Ruby hashmap's :[]= method also returns the inserted value.
|
||||
return value; |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.has_key?(key) => bool |
||||
* |
||||
* Returns true if the given key is present in the map. Throws an exception if |
||||
* the key has the wrong type. |
||||
*/ |
||||
VALUE Map_has_key(VALUE _self, VALUE key) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH]; |
||||
const char* keyval = NULL; |
||||
size_t length = 0; |
||||
table_key(self, key, keybuf, &keyval, &length); |
||||
|
||||
if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) { |
||||
return Qtrue; |
||||
} else { |
||||
return Qfalse; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.delete(key) => old_value |
||||
* |
||||
* Deletes the value at the given key, if any, returning either the old value or |
||||
* nil if none was present. Throws an exception if the key is of the wrong type. |
||||
*/ |
||||
VALUE Map_delete(VALUE _self, VALUE key) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH]; |
||||
const char* keyval = NULL; |
||||
size_t length = 0; |
||||
table_key(self, key, keybuf, &keyval, &length); |
||||
|
||||
upb_value v; |
||||
if (upb_strtable_remove2(&self->table, keyval, length, &v)) { |
||||
void* mem = value_memory(&v); |
||||
return native_slot_get(self->value_type, self->value_type_class, mem); |
||||
} else { |
||||
return Qnil; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.clear |
||||
* |
||||
* Removes all entries from the map. |
||||
*/ |
||||
VALUE Map_clear(VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
// Uninit and reinit the table -- this is faster than iterating and doing a
|
||||
// delete-lookup on each key.
|
||||
upb_strtable_uninit(&self->table); |
||||
if (!upb_strtable_init(&self->table, UPB_CTYPE_INT64)) { |
||||
rb_raise(rb_eRuntimeError, "Unable to re-initialize table"); |
||||
} |
||||
return Qnil; |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.length |
||||
* |
||||
* Returns the number of entries (key-value pairs) in the map. |
||||
*/ |
||||
VALUE Map_length(VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
return ULL2NUM(upb_strtable_count(&self->table)); |
||||
} |
||||
|
||||
static VALUE Map_new_this_type(VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
VALUE new_map = Qnil; |
||||
VALUE key_type = fieldtype_to_ruby(self->key_type); |
||||
VALUE value_type = fieldtype_to_ruby(self->value_type); |
||||
if (self->value_type_class != Qnil) { |
||||
new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 3, |
||||
key_type, value_type, self->value_type_class); |
||||
} else { |
||||
new_map = rb_funcall(CLASS_OF(_self), rb_intern("new"), 2, |
||||
key_type, value_type); |
||||
} |
||||
return new_map; |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.dup => new_map |
||||
* |
||||
* Duplicates this map with a shallow copy. References to all non-primitive |
||||
* element objects (e.g., submessages) are shared. |
||||
*/ |
||||
VALUE Map_dup(VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
VALUE new_map = Map_new_this_type(_self); |
||||
Map* new_self = ruby_to_Map(new_map); |
||||
|
||||
upb_strtable_iter it; |
||||
for (upb_strtable_begin(&it, &self->table); |
||||
!upb_strtable_done(&it); |
||||
upb_strtable_next(&it)) { |
||||
|
||||
upb_value v = upb_strtable_iter_value(&it); |
||||
void* mem = value_memory(&v); |
||||
upb_value dup; |
||||
void* dup_mem = value_memory(&dup); |
||||
native_slot_dup(self->value_type, dup_mem, mem); |
||||
|
||||
if (!upb_strtable_insert2(&new_self->table, |
||||
upb_strtable_iter_key(&it), |
||||
upb_strtable_iter_keylength(&it), |
||||
dup)) { |
||||
rb_raise(rb_eRuntimeError, "Error inserting value into new table"); |
||||
} |
||||
} |
||||
|
||||
return new_map; |
||||
} |
||||
|
||||
// Used by Google::Protobuf.deep_copy but not exposed directly.
|
||||
VALUE Map_deep_copy(VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
VALUE new_map = Map_new_this_type(_self); |
||||
Map* new_self = ruby_to_Map(new_map); |
||||
|
||||
upb_strtable_iter it; |
||||
for (upb_strtable_begin(&it, &self->table); |
||||
!upb_strtable_done(&it); |
||||
upb_strtable_next(&it)) { |
||||
|
||||
upb_value v = upb_strtable_iter_value(&it); |
||||
void* mem = value_memory(&v); |
||||
upb_value dup; |
||||
void* dup_mem = value_memory(&dup); |
||||
native_slot_deep_copy(self->value_type, dup_mem, mem); |
||||
|
||||
if (!upb_strtable_insert2(&new_self->table, |
||||
upb_strtable_iter_key(&it), |
||||
upb_strtable_iter_keylength(&it), |
||||
dup)) { |
||||
rb_raise(rb_eRuntimeError, "Error inserting value into new table"); |
||||
} |
||||
} |
||||
|
||||
return new_map; |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.==(other) => boolean |
||||
* |
||||
* Compares this map to another. Maps are equal if they have identical key sets, |
||||
* and for each key, the values in both maps compare equal. Elements are |
||||
* compared as per normal Ruby semantics, by calling their :== methods (or |
||||
* performing a more efficient comparison for primitive types). |
||||
* |
||||
* Maps with dissimilar key types or value types/typeclasses are never equal, |
||||
* even if value comparison (for example, between integers and floats) would |
||||
* have otherwise indicated that every element has equal value. |
||||
*/ |
||||
VALUE Map_eq(VALUE _self, VALUE _other) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
// Allow comparisons to Ruby hashmaps by converting to a temporary Map
|
||||
// instance. Slow, but workable.
|
||||
if (TYPE(_other) == T_HASH) { |
||||
VALUE other_map = Map_new_this_type(_self); |
||||
Map_merge_into_self(other_map, _other); |
||||
_other = other_map; |
||||
} |
||||
|
||||
Map* other = ruby_to_Map(_other); |
||||
|
||||
if (self == other) { |
||||
return Qtrue; |
||||
} |
||||
if (self->key_type != other->key_type || |
||||
self->value_type != other->value_type || |
||||
self->value_type_class != other->value_type_class) { |
||||
return Qfalse; |
||||
} |
||||
if (upb_strtable_count(&self->table) != upb_strtable_count(&other->table)) { |
||||
return Qfalse; |
||||
} |
||||
|
||||
// For each member of self, check that an equal member exists at the same key
|
||||
// in other.
|
||||
upb_strtable_iter it; |
||||
for (upb_strtable_begin(&it, &self->table); |
||||
!upb_strtable_done(&it); |
||||
upb_strtable_next(&it)) { |
||||
|
||||
upb_value v = upb_strtable_iter_value(&it); |
||||
void* mem = value_memory(&v); |
||||
upb_value other_v; |
||||
void* other_mem = value_memory(&other_v); |
||||
|
||||
if (!upb_strtable_lookup2(&other->table, |
||||
upb_strtable_iter_key(&it), |
||||
upb_strtable_iter_keylength(&it), |
||||
&other_v)) { |
||||
// Not present in other map.
|
||||
return Qfalse; |
||||
} |
||||
|
||||
if (!native_slot_eq(self->value_type, mem, other_mem)) { |
||||
// Present, but value not equal.
|
||||
return Qfalse; |
||||
} |
||||
} |
||||
|
||||
return Qtrue; |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.hash => hash_value |
||||
* |
||||
* Returns a hash value based on this map's contents. |
||||
*/ |
||||
VALUE Map_hash(VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
st_index_t h = rb_hash_start(0); |
||||
VALUE hash_sym = rb_intern("hash"); |
||||
|
||||
upb_strtable_iter it; |
||||
for (upb_strtable_begin(&it, &self->table); |
||||
!upb_strtable_done(&it); |
||||
upb_strtable_next(&it)) { |
||||
VALUE key = table_key_to_ruby( |
||||
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); |
||||
|
||||
upb_value v = upb_strtable_iter_value(&it); |
||||
void* mem = value_memory(&v); |
||||
VALUE value = native_slot_get(self->value_type, |
||||
self->value_type_class, |
||||
mem); |
||||
|
||||
h = rb_hash_uint(h, NUM2LONG(rb_funcall(key, hash_sym, 0))); |
||||
h = rb_hash_uint(h, NUM2LONG(rb_funcall(value, hash_sym, 0))); |
||||
} |
||||
|
||||
return INT2FIX(h); |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.inspect => string |
||||
* |
||||
* Returns a string representing this map's elements. It will be formatted as |
||||
* "{key => value, key => value, ...}", with each key and value string |
||||
* representation computed by its own #inspect method. |
||||
*/ |
||||
VALUE Map_inspect(VALUE _self) { |
||||
Map* self = ruby_to_Map(_self); |
||||
|
||||
VALUE str = rb_str_new2("{"); |
||||
|
||||
bool first = true; |
||||
VALUE inspect_sym = rb_intern("inspect"); |
||||
|
||||
upb_strtable_iter it; |
||||
for (upb_strtable_begin(&it, &self->table); |
||||
!upb_strtable_done(&it); |
||||
upb_strtable_next(&it)) { |
||||
VALUE key = table_key_to_ruby( |
||||
self, upb_strtable_iter_key(&it), upb_strtable_iter_keylength(&it)); |
||||
|
||||
upb_value v = upb_strtable_iter_value(&it); |
||||
void* mem = value_memory(&v); |
||||
VALUE value = native_slot_get(self->value_type, |
||||
self->value_type_class, |
||||
mem); |
||||
|
||||
if (!first) { |
||||
str = rb_str_cat2(str, ", "); |
||||
} else { |
||||
first = false; |
||||
} |
||||
str = rb_str_append(str, rb_funcall(key, inspect_sym, 0)); |
||||
str = rb_str_cat2(str, "=>"); |
||||
str = rb_str_append(str, rb_funcall(value, inspect_sym, 0)); |
||||
} |
||||
|
||||
str = rb_str_cat2(str, "}"); |
||||
return str; |
||||
} |
||||
|
||||
/*
|
||||
* call-seq: |
||||
* Map.merge(other_map) => map |
||||
* |
||||
* Copies key/value pairs from other_map into a copy of this map. If a key is |
||||
* set in other_map and this map, the value from other_map overwrites the value |
||||
* in the new copy of this map. Returns the new copy of this map with merged |
||||
* contents. |
||||
*/ |
||||
VALUE Map_merge(VALUE _self, VALUE hashmap) { |
||||
VALUE dupped = Map_dup(_self); |
||||
return Map_merge_into_self(dupped, hashmap); |
||||
} |
||||
|
||||
static int merge_into_self_callback(VALUE key, VALUE value, VALUE self) { |
||||
Map_index_set(self, key, value); |
||||
return ST_CONTINUE; |
||||
} |
||||
|
||||
// Used only internally -- shared by #merge and #initialize.
|
||||
VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) { |
||||
if (TYPE(hashmap) == T_HASH) { |
||||
rb_hash_foreach(hashmap, merge_into_self_callback, _self); |
||||
} else if (RB_TYPE_P(hashmap, T_DATA) && RTYPEDDATA_P(hashmap) && |
||||
RTYPEDDATA_TYPE(hashmap) == &Map_type) { |
||||
|
||||
Map* self = ruby_to_Map(_self); |
||||
Map* other = ruby_to_Map(hashmap); |
||||
|
||||
if (self->key_type != other->key_type || |
||||
self->value_type != other->value_type || |
||||
self->value_type_class != other->value_type_class) { |
||||
rb_raise(rb_eArgError, "Attempt to merge Map with mismatching types"); |
||||
} |
||||
|
||||
upb_strtable_iter it; |
||||
for (upb_strtable_begin(&it, &other->table); |
||||
!upb_strtable_done(&it); |
||||
upb_strtable_next(&it)) { |
||||
|
||||
// Replace any existing value by issuing a 'remove' operation first.
|
||||
upb_value oldv; |
||||
upb_strtable_remove2(&self->table, |
||||
upb_strtable_iter_key(&it), |
||||
upb_strtable_iter_keylength(&it), |
||||
&oldv); |
||||
|
||||
upb_value v = upb_strtable_iter_value(&it); |
||||
upb_strtable_insert2(&self->table, |
||||
upb_strtable_iter_key(&it), |
||||
upb_strtable_iter_keylength(&it), |
||||
v); |
||||
} |
||||
} else { |
||||
rb_raise(rb_eArgError, "Unknown type merging into Map"); |
||||
} |
||||
return _self; |
||||
} |
||||
|
||||
// Internal method: map iterator initialization (used for serialization).
|
||||
void Map_begin(VALUE _self, Map_iter* iter) { |
||||
Map* self = ruby_to_Map(_self); |
||||
iter->self = self; |
||||
upb_strtable_begin(&iter->it, &self->table); |
||||
} |
||||
|
||||
void Map_next(Map_iter* iter) { |
||||
upb_strtable_next(&iter->it); |
||||
} |
||||
|
||||
bool Map_done(Map_iter* iter) { |
||||
return upb_strtable_done(&iter->it); |
||||
} |
||||
|
||||
VALUE Map_iter_key(Map_iter* iter) { |
||||
return table_key_to_ruby( |
||||
iter->self, |
||||
upb_strtable_iter_key(&iter->it), |
||||
upb_strtable_iter_keylength(&iter->it)); |
||||
} |
||||
|
||||
VALUE Map_iter_value(Map_iter* iter) { |
||||
upb_value v = upb_strtable_iter_value(&iter->it); |
||||
void* mem = value_memory(&v); |
||||
return native_slot_get(iter->self->value_type, |
||||
iter->self->value_type_class, |
||||
mem); |
||||
} |
||||
|
||||
void Map_register(VALUE module) { |
||||
VALUE klass = rb_define_class_under(module, "Map", rb_cObject); |
||||
rb_define_alloc_func(klass, Map_alloc); |
||||
cMap = klass; |
||||
rb_gc_register_address(&cMap); |
||||
|
||||
rb_define_method(klass, "initialize", Map_init, -1); |
||||
rb_define_method(klass, "each", Map_each, 0); |
||||
rb_define_method(klass, "keys", Map_keys, 0); |
||||
rb_define_method(klass, "values", Map_values, 0); |
||||
rb_define_method(klass, "[]", Map_index, 1); |
||||
rb_define_method(klass, "[]=", Map_index_set, 2); |
||||
rb_define_method(klass, "has_key?", Map_has_key, 1); |
||||
rb_define_method(klass, "delete", Map_delete, 1); |
||||
rb_define_method(klass, "clear", Map_clear, 0); |
||||
rb_define_method(klass, "length", Map_length, 0); |
||||
rb_define_method(klass, "dup", Map_dup, 0); |
||||
rb_define_method(klass, "==", Map_eq, 1); |
||||
rb_define_method(klass, "hash", Map_hash, 0); |
||||
rb_define_method(klass, "inspect", Map_inspect, 0); |
||||
rb_define_method(klass, "merge", Map_merge, 1); |
||||
rb_include_module(klass, rb_mEnumerable); |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,23 +0,0 @@ |
||||
#!/usr/bin/ruby |
||||
|
||||
require 'mkmf' |
||||
|
||||
upb_path = File.absolute_path(File.dirname($0)) + "/../../../upb" |
||||
libs = ["upb_pic", "upb.pb_pic", "upb.json_pic"] |
||||
system("cd #{upb_path}; make " + libs.map{|l| "lib/lib#{l}.a"}.join(" ")) |
||||
|
||||
$CFLAGS += " -O3 -std=c99 -Wno-unused-function -DNDEBUG" |
||||
|
||||
find_header("upb/upb.h", upb_path) or |
||||
raise "Can't find upb headers" |
||||
find_library("upb_pic", "upb_msgdef_new", upb_path + "/lib") or |
||||
raise "Can't find upb lib" |
||||
find_library("upb.pb_pic", "upb_pbdecoder_init", upb_path + "/lib") or |
||||
raise "Can't find upb.pb lib" |
||||
find_library("upb.json_pic", "upb_json_printer_init", upb_path + "/lib") or |
||||
raise "Can't find upb.pb lib" |
||||
|
||||
$objs = ["protobuf.o", "defs.o", "storage.o", "message.o", |
||||
"repeated_field.o", "encode_decode.o"] |
||||
|
||||
create_makefile("protobuf_c") |
@ -0,0 +1,24 @@ |
||||
class << Gem::Specification |
||||
def find_c_source(dir) |
||||
`cd #{dir}; git ls-files "*.c" "*.h" extconf.rb Makefile`.split |
||||
.map{|f| "#{dir}/#{f}"} |
||||
end |
||||
end |
||||
|
||||
Gem::Specification.new do |s| |
||||
s.name = "google-protobuf" |
||||
s.version = "3.0.0.alpha.2" |
||||
s.licenses = ["BSD"] |
||||
s.summary = "Protocol Buffers" |
||||
s.description = "Protocol Buffers are Google's data interchange format." |
||||
s.authors = ["Protobuf Authors"] |
||||
s.email = "protobuf@googlegroups.com" |
||||
s.require_paths = ["lib"] |
||||
s.extensions = ["ext/google/protobuf_c/extconf.rb"] |
||||
s.files = ["lib/google/protobuf.rb"] + |
||||
# extension C source |
||||
find_c_source("ext/google/protobuf_c") |
||||
s.test_files = ["tests/basic.rb", |
||||
"tests/stress.rb", |
||||
"tests/generated_code_test.rb"] |
||||
end |
@ -0,0 +1,67 @@ |
||||
syntax = "proto3"; |
||||
|
||||
package A.B.C; |
||||
|
||||
message TestMessage { |
||||
optional int32 optional_int32 = 1; |
||||
optional int64 optional_int64 = 2; |
||||
optional uint32 optional_uint32 = 3; |
||||
optional uint64 optional_uint64 = 4; |
||||
optional bool optional_bool = 5; |
||||
optional double optional_double = 6; |
||||
optional float optional_float = 7; |
||||
optional string optional_string = 8; |
||||
optional bytes optional_bytes = 9; |
||||
optional TestEnum optional_enum = 10; |
||||
optional TestMessage optional_msg = 11; |
||||
|
||||
repeated int32 repeated_int32 = 21; |
||||
repeated int64 repeated_int64 = 22; |
||||
repeated uint32 repeated_uint32 = 23; |
||||
repeated uint64 repeated_uint64 = 24; |
||||
repeated bool repeated_bool = 25; |
||||
repeated double repeated_double = 26; |
||||
repeated float repeated_float = 27; |
||||
repeated string repeated_string = 28; |
||||
repeated bytes repeated_bytes = 29; |
||||
repeated TestEnum repeated_enum = 30; |
||||
repeated TestMessage repeated_msg = 31; |
||||
|
||||
oneof my_oneof { |
||||
int32 oneof_int32 = 41; |
||||
int64 oneof_int64 = 42; |
||||
uint32 oneof_uint32 = 43; |
||||
uint64 oneof_uint64 = 44; |
||||
bool oneof_bool = 45; |
||||
double oneof_double = 46; |
||||
float oneof_float = 47; |
||||
string oneof_string = 48; |
||||
bytes oneof_bytes = 49; |
||||
TestEnum oneof_enum = 50; |
||||
TestMessage oneof_msg = 51; |
||||
} |
||||
|
||||
map<int32, string> map_int32_string = 61; |
||||
map<int64, string> map_int64_string = 62; |
||||
map<uint32, string> map_uint32_string = 63; |
||||
map<uint64, string> map_uint64_string = 64; |
||||
map<bool, string> map_bool_string = 65; |
||||
map<string, string> map_string_string = 66; |
||||
map<string, TestMessage> map_string_msg = 67; |
||||
map<string, TestEnum> map_string_enum = 68; |
||||
map<string, int32> map_string_int32 = 69; |
||||
map<string, bool> map_string_bool = 70; |
||||
|
||||
message NestedMessage { |
||||
optional int32 foo = 1; |
||||
} |
||||
|
||||
optional NestedMessage nested_message = 80; |
||||
} |
||||
|
||||
enum TestEnum { |
||||
Default = 0; |
||||
A = 1; |
||||
B = 2; |
||||
C = 3; |
||||
} |
@ -0,0 +1,74 @@ |
||||
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
# source: generated_code.proto |
||||
|
||||
require 'google/protobuf' |
||||
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do |
||||
add_message "A.B.C.TestMessage" do |
||||
optional :optional_int32, :int32, 1 |
||||
optional :optional_int64, :int64, 2 |
||||
optional :optional_uint32, :uint32, 3 |
||||
optional :optional_uint64, :uint64, 4 |
||||
optional :optional_bool, :bool, 5 |
||||
optional :optional_double, :double, 6 |
||||
optional :optional_float, :float, 7 |
||||
optional :optional_string, :string, 8 |
||||
optional :optional_bytes, :string, 9 |
||||
optional :optional_enum, :enum, 10, "A.B.C.TestEnum" |
||||
optional :optional_msg, :message, 11, "A.B.C.TestMessage" |
||||
repeated :repeated_int32, :int32, 21 |
||||
repeated :repeated_int64, :int64, 22 |
||||
repeated :repeated_uint32, :uint32, 23 |
||||
repeated :repeated_uint64, :uint64, 24 |
||||
repeated :repeated_bool, :bool, 25 |
||||
repeated :repeated_double, :double, 26 |
||||
repeated :repeated_float, :float, 27 |
||||
repeated :repeated_string, :string, 28 |
||||
repeated :repeated_bytes, :string, 29 |
||||
repeated :repeated_enum, :enum, 30, "A.B.C.TestEnum" |
||||
repeated :repeated_msg, :message, 31, "A.B.C.TestMessage" |
||||
map :map_int32_string, :int32, :string, 61 |
||||
map :map_int64_string, :int64, :string, 62 |
||||
map :map_uint32_string, :uint32, :string, 63 |
||||
map :map_uint64_string, :uint64, :string, 64 |
||||
map :map_bool_string, :bool, :string, 65 |
||||
map :map_string_string, :string, :string, 66 |
||||
map :map_string_msg, :string, :message, 67, "A.B.C.TestMessage" |
||||
map :map_string_enum, :string, :enum, 68, "A.B.C.TestEnum" |
||||
map :map_string_int32, :string, :int32, 69 |
||||
map :map_string_bool, :string, :bool, 70 |
||||
optional :nested_message, :message, 80, "A.B.C.TestMessage.NestedMessage" |
||||
oneof :my_oneof do |
||||
optional :oneof_int32, :int32, 41 |
||||
optional :oneof_int64, :int64, 42 |
||||
optional :oneof_uint32, :uint32, 43 |
||||
optional :oneof_uint64, :uint64, 44 |
||||
optional :oneof_bool, :bool, 45 |
||||
optional :oneof_double, :double, 46 |
||||
optional :oneof_float, :float, 47 |
||||
optional :oneof_string, :string, 48 |
||||
optional :oneof_bytes, :string, 49 |
||||
optional :oneof_enum, :enum, 50, "A.B.C.TestEnum" |
||||
optional :oneof_msg, :message, 51, "A.B.C.TestMessage" |
||||
end |
||||
end |
||||
add_message "A.B.C.TestMessage.NestedMessage" do |
||||
optional :foo, :int32, 1 |
||||
end |
||||
add_enum "A.B.C.TestEnum" do |
||||
value :Default, 0 |
||||
value :A, 1 |
||||
value :B, 2 |
||||
value :C, 3 |
||||
end |
||||
end |
||||
|
||||
module A |
||||
module B |
||||
module C |
||||
TestMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage").msgclass |
||||
TestMessage::NestedMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestMessage.NestedMessage").msgclass |
||||
TestEnum = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.B.C.TestEnum").enummodule |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,17 @@ |
||||
#!/usr/bin/ruby |
||||
|
||||
# generated_code.rb is in the same directory as this test. |
||||
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) |
||||
|
||||
require 'generated_code' |
||||
require 'test/unit' |
||||
|
||||
class GeneratedCodeTest < Test::Unit::TestCase |
||||
def test_generated_msg |
||||
# just test that we can instantiate the message. The purpose of this test |
||||
# is to ensure that the output of the code generator is valid Ruby and |
||||
# successfully creates message definitions and classes, not to test every |
||||
# aspect of the extension (basic.rb is for that). |
||||
m = A::B::C::TestMessage.new() |
||||
end |
||||
end |
@ -0,0 +1,87 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Provides a mechanism for mapping a descriptor to the
|
||||
// fully-qualified name of the corresponding Java class.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__ |
||||
|
||||
#include <string> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
class Descriptor; |
||||
class EnumDescriptor; |
||||
class FileDescriptor; |
||||
class ServiceDescriptor; |
||||
|
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
// Requires:
|
||||
// descriptor != NULL
|
||||
//
|
||||
// Returns:
|
||||
// The fully-qualified Java class name.
|
||||
string ClassName(const Descriptor* descriptor); |
||||
|
||||
// Requires:
|
||||
// descriptor != NULL
|
||||
//
|
||||
// Returns:
|
||||
// The fully-qualified Java class name.
|
||||
string ClassName(const EnumDescriptor* descriptor); |
||||
|
||||
// Requires:
|
||||
// descriptor != NULL
|
||||
//
|
||||
// Returns:
|
||||
// The fully-qualified Java class name.
|
||||
string ClassName(const FileDescriptor* descriptor); |
||||
|
||||
// Requires:
|
||||
// descriptor != NULL
|
||||
//
|
||||
// Returns:
|
||||
// The fully-qualified Java class name.
|
||||
string ClassName(const ServiceDescriptor* descriptor); |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_NAMES_H__
|
@ -0,0 +1,186 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/compiler/javanano/javanano_map_field.h> |
||||
#include <google/protobuf/compiler/javanano/javanano_helpers.h> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/wire_format.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace javanano { |
||||
|
||||
namespace { |
||||
|
||||
string TypeName(const Params& params, const FieldDescriptor* field, |
||||
bool boxed) { |
||||
JavaType java_type = GetJavaType(field); |
||||
switch (java_type) { |
||||
case JAVATYPE_MESSAGE: |
||||
return ClassName(params, field->message_type()); |
||||
case JAVATYPE_INT: |
||||
case JAVATYPE_LONG: |
||||
case JAVATYPE_FLOAT: |
||||
case JAVATYPE_DOUBLE: |
||||
case JAVATYPE_BOOLEAN: |
||||
case JAVATYPE_STRING: |
||||
case JAVATYPE_BYTES: |
||||
case JAVATYPE_ENUM: |
||||
if (boxed) { |
||||
return BoxedPrimitiveTypeName(java_type); |
||||
} else { |
||||
return PrimitiveTypeName(java_type); |
||||
} |
||||
// No default because we want the compiler to complain if any new JavaTypes
|
||||
// are added..
|
||||
} |
||||
|
||||
GOOGLE_LOG(FATAL) << "should not reach here."; |
||||
return ""; |
||||
} |
||||
|
||||
const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) { |
||||
GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); |
||||
const Descriptor* message = descriptor->message_type(); |
||||
GOOGLE_CHECK(message->options().map_entry()); |
||||
return message->FindFieldByName("key"); |
||||
} |
||||
|
||||
const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) { |
||||
GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); |
||||
const Descriptor* message = descriptor->message_type(); |
||||
GOOGLE_CHECK(message->options().map_entry()); |
||||
return message->FindFieldByName("value"); |
||||
} |
||||
|
||||
void SetMapVariables(const Params& params, |
||||
const FieldDescriptor* descriptor, map<string, string>* variables) { |
||||
const FieldDescriptor* key = KeyField(descriptor); |
||||
const FieldDescriptor* value = ValueField(descriptor); |
||||
(*variables)["name"] = |
||||
RenameJavaKeywords(UnderscoresToCamelCase(descriptor)); |
||||
(*variables)["number"] = SimpleItoa(descriptor->number()); |
||||
(*variables)["key_type"] = TypeName(params, key, false); |
||||
(*variables)["boxed_key_type"] = TypeName(params,key, true); |
||||
(*variables)["key_desc_type"] = |
||||
"TYPE_" + ToUpper(FieldDescriptor::TypeName(key->type())); |
||||
(*variables)["key_tag"] = SimpleItoa(internal::WireFormat::MakeTag(key)); |
||||
(*variables)["value_type"] = TypeName(params, value, false); |
||||
(*variables)["boxed_value_type"] = TypeName(params, value, true); |
||||
(*variables)["value_desc_type"] = |
||||
"TYPE_" + ToUpper(FieldDescriptor::TypeName(value->type())); |
||||
(*variables)["value_tag"] = SimpleItoa(internal::WireFormat::MakeTag(value)); |
||||
(*variables)["type_parameters"] = |
||||
(*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"]; |
||||
(*variables)["value_default"] = |
||||
value->type() == FieldDescriptor::TYPE_MESSAGE |
||||
? "new " + (*variables)["value_type"] + "()" |
||||
: "null"; |
||||
} |
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Params& params) |
||||
: FieldGenerator(params), descriptor_(descriptor) { |
||||
SetMapVariables(params, descriptor, &variables_); |
||||
} |
||||
|
||||
MapFieldGenerator::~MapFieldGenerator() {} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const { |
||||
printer->Print(variables_, |
||||
"public java.util.Map<$type_parameters$> $name$;\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateClearCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$name$ = null;\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"this.$name$ = com.google.protobuf.nano.InternalNano.mergeMapEntry(\n" |
||||
" input, this.$name$, mapFactory,\n" |
||||
" com.google.protobuf.nano.InternalNano.$key_desc_type$,\n" |
||||
" com.google.protobuf.nano.InternalNano.$value_desc_type$,\n" |
||||
" $value_default$,\n" |
||||
" $key_tag$, $value_tag$);\n" |
||||
"\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateSerializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (this.$name$ != null) {\n" |
||||
" com.google.protobuf.nano.InternalNano.serializeMapField(\n" |
||||
" output, this.$name$, $number$,\n" |
||||
" com.google.protobuf.nano.InternalNano.$key_desc_type$,\n" |
||||
" com.google.protobuf.nano.InternalNano.$value_desc_type$);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateSerializedSizeCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (this.$name$ != null) {\n" |
||||
" size += com.google.protobuf.nano.InternalNano.computeMapFieldSize(\n" |
||||
" this.$name$, $number$,\n" |
||||
" com.google.protobuf.nano.InternalNano.$key_desc_type$,\n" |
||||
" com.google.protobuf.nano.InternalNano.$value_desc_type$);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateEqualsCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (!com.google.protobuf.nano.InternalNano.equals(\n" |
||||
" this.$name$, other.$name$)) {\n" |
||||
" return false;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void MapFieldGenerator:: |
||||
GenerateHashCodeCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"result = 31 * result +\n" |
||||
" com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n"); |
||||
} |
||||
|
||||
} // namespace javanano
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,70 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <vector> |
||||
#include <google/protobuf/compiler/javanano/javanano_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace javanano { |
||||
|
||||
class MapFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit MapFieldGenerator( |
||||
const FieldDescriptor* descriptor, const Params& params); |
||||
~MapFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GenerateMembers(io::Printer* printer, bool lazy_init) const; |
||||
void GenerateClearCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateSerializationCode(io::Printer* printer) const; |
||||
void GenerateSerializedSizeCode(io::Printer* printer) const; |
||||
void GenerateEqualsCode(io::Printer* printer) const; |
||||
void GenerateHashCodeCode(io::Printer* printer) const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); |
||||
}; |
||||
|
||||
} // namespace javanano
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MAP_FIELD_H__
|
@ -0,0 +1,119 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <memory> |
||||
|
||||
#include <google/protobuf/compiler/ruby/ruby_generator.h> |
||||
#include <google/protobuf/compiler/command_line_interface.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
|
||||
#include <google/protobuf/testing/googletest.h> |
||||
#include <gtest/gtest.h> |
||||
#include <google/protobuf/testing/file.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace ruby { |
||||
namespace { |
||||
|
||||
string FindRubyTestDir() { |
||||
// Inspired by TestSourceDir() in src/google/protobuf/testing/googletest.cc.
|
||||
string prefix = "."; |
||||
while (!File::Exists(prefix + "/ruby/tests")) { |
||||
if (!File::Exists(prefix)) { |
||||
GOOGLE_LOG(FATAL) |
||||
<< "Could not find Ruby test directory. Please run tests from " |
||||
"somewhere within the protobuf source package."; |
||||
} |
||||
prefix += "/.."; |
||||
} |
||||
return prefix + "/ruby/tests"; |
||||
} |
||||
|
||||
// This test is a simple golden-file test over the output of the Ruby code
|
||||
// generator. When we make changes to the Ruby extension and alter the Ruby code
|
||||
// generator to use those changes, we should (i) manually test the output of the
|
||||
// code generator with the extension, and (ii) update the golden output above.
|
||||
// Some day, we may integrate build systems between protoc and the language
|
||||
// extensions to the point where we can do this test in a more automated way.
|
||||
|
||||
TEST(RubyGeneratorTest, GeneratorTest) { |
||||
string ruby_tests = FindRubyTestDir(); |
||||
|
||||
google::protobuf::compiler::CommandLineInterface cli; |
||||
cli.SetInputsAreProtoPathRelative(true); |
||||
|
||||
ruby::Generator ruby_generator; |
||||
cli.RegisterGenerator("--ruby_out", &ruby_generator, ""); |
||||
|
||||
// Copy generated_code.proto to the temporary test directory.
|
||||
string test_input; |
||||
GOOGLE_CHECK_OK(File::GetContents( |
||||
ruby_tests + "/generated_code.proto", |
||||
&test_input, |
||||
true)); |
||||
GOOGLE_CHECK_OK(File::SetContents( |
||||
TestTempDir() + "/generated_code.proto", |
||||
test_input, |
||||
true)); |
||||
|
||||
// Invoke the proto compiler (we will be inside TestTempDir() at this point).
|
||||
string ruby_out = "--ruby_out=" + TestTempDir(); |
||||
string proto_path = "--proto_path=" + TestTempDir(); |
||||
const char* argv[] = { |
||||
"protoc", |
||||
ruby_out.c_str(), |
||||
proto_path.c_str(), |
||||
"generated_code.proto", |
||||
}; |
||||
|
||||
EXPECT_EQ(0, cli.Run(4, argv)); |
||||
|
||||
// Load the generated output and compare to the expected result.
|
||||
string output; |
||||
GOOGLE_CHECK_OK(File::GetContents( |
||||
TestTempDir() + "/generated_code.rb", |
||||
&output, |
||||
true)); |
||||
string expected_output; |
||||
GOOGLE_CHECK_OK(File::GetContents( |
||||
ruby_tests + "/generated_code.rb", |
||||
&expected_output, |
||||
true)); |
||||
EXPECT_EQ(expected_output, output); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace ruby
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -1 +0,0 @@ |
||||
Subproject commit 56913be6bb57f81dbbf7baf9cc9a0a2cd1a36493 |
Loading…
Reference in new issue