sparsam 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +19 -0
- data/ext/extconf.rb +18 -0
- data/ext/ruby_hooks.c +96 -0
- data/ext/serializer.cpp +716 -0
- data/ext/serializer.h +101 -0
- data/ext/third-party/sparsepp/sparsepp/spp.h +4347 -0
- data/ext/third-party/sparsepp/sparsepp/spp_config.h +781 -0
- data/ext/third-party/sparsepp/sparsepp/spp_dlalloc.h +4023 -0
- data/ext/third-party/sparsepp/sparsepp/spp_memory.h +121 -0
- data/ext/third-party/sparsepp/sparsepp/spp_smartptr.h +76 -0
- data/ext/third-party/sparsepp/sparsepp/spp_stdint.h +16 -0
- data/ext/third-party/sparsepp/sparsepp/spp_timer.h +58 -0
- data/ext/third-party/sparsepp/sparsepp/spp_traits.h +122 -0
- data/ext/third-party/sparsepp/sparsepp/spp_utils.h +447 -0
- data/lib/sparsam.rb +10 -0
- data/lib/sparsam/base_class.rb +97 -0
- data/lib/sparsam/deserializer.rb +8 -0
- data/lib/sparsam/exceptions.rb +33 -0
- data/lib/sparsam/struct.rb +45 -0
- data/lib/sparsam/types.rb +108 -0
- data/lib/sparsam/union.rb +72 -0
- data/spec/gen-ruby/user_constants.rb +9 -0
- data/spec/gen-ruby/user_types.rb +106 -0
- data/spec/sparsam_spec.rb +304 -0
- data/spec/user.thrift +62 -0
- metadata +172 -0
data/lib/sparsam.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'sparsam/types'
|
3
|
+
|
4
|
+
module Sparsam
|
5
|
+
class BaseClass
|
6
|
+
class AccessorNames < Struct.new(:reader, :writer); end
|
7
|
+
|
8
|
+
def self.generate_field_syms(klass)
|
9
|
+
field_syms = {}
|
10
|
+
klass::FIELDS.each do |_, field_info|
|
11
|
+
name = field_info[:name].to_sym
|
12
|
+
accessors = AccessorNames.new(name, :"#{name}=")
|
13
|
+
field_syms[name] = accessors
|
14
|
+
field_syms[name.to_s] = accessors
|
15
|
+
end
|
16
|
+
|
17
|
+
klass.const_set(
|
18
|
+
:FIELD_SYMS,
|
19
|
+
field_syms
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.generate_accessors(klass)
|
24
|
+
klass::FIELDS.each do |field_key, field_info|
|
25
|
+
field_accessor(klass, field_key, field_info)
|
26
|
+
qmark_isset_method(klass, field_info)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# TODO(Ben Hughes): Do we ever use those, these are an unexpected
|
31
|
+
# definition of predicate accessors
|
32
|
+
def self.qmark_isset_method(klass, field_info)
|
33
|
+
field_name = field_info[:name]
|
34
|
+
|
35
|
+
klass.class_eval(<<-EOF, __FILE__, __LINE__)
|
36
|
+
def #{field_name}?
|
37
|
+
!#{field_name}.nil?
|
38
|
+
end
|
39
|
+
EOF
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.generate_default_values(klass)
|
43
|
+
fields_with_default_values = {}
|
44
|
+
klass::FIELDS.each do |fid, field_def|
|
45
|
+
unless field_def[:default].nil?
|
46
|
+
fields_with_default_values[field_def[:name]] = field_def[:default].freeze
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
if fields_with_default_values.empty?
|
51
|
+
klass.const_set(
|
52
|
+
:DEFAULT_VALUES,
|
53
|
+
nil
|
54
|
+
)
|
55
|
+
else
|
56
|
+
klass.const_set(
|
57
|
+
:DEFAULT_VALUES,
|
58
|
+
fields_with_default_values
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.init_thrift_struct(klass)
|
64
|
+
generate_accessors(klass)
|
65
|
+
generate_field_syms(klass)
|
66
|
+
Sparsam.cache_fields(klass)
|
67
|
+
generate_default_values(klass)
|
68
|
+
klass.class_eval(<<-EOF, __FILE__, __LINE__)
|
69
|
+
def struct_fields
|
70
|
+
FIELDS
|
71
|
+
end
|
72
|
+
EOF
|
73
|
+
end
|
74
|
+
|
75
|
+
def serialize(prot = Sparsam::CompactProtocol)
|
76
|
+
validate
|
77
|
+
s = Sparsam::Serializer.new(prot, "")
|
78
|
+
s.serialize(self.class, self)
|
79
|
+
end
|
80
|
+
|
81
|
+
def validate(mode = Sparsam::NORMAL)
|
82
|
+
Sparsam.validate(self.class, self, mode)
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def name_to_accessors(name)
|
88
|
+
self.class::FIELD_SYMS[name]
|
89
|
+
end
|
90
|
+
|
91
|
+
def each_field
|
92
|
+
struct_fields.each do |fid, data|
|
93
|
+
yield fid, data
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
|
3
|
+
module Sparsam
|
4
|
+
class Exception < StandardError
|
5
|
+
def initialize(msg)
|
6
|
+
super
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class MissingMandatory < Exception
|
11
|
+
def initialize(msg)
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TypeMismatch < Exception
|
17
|
+
def initialize(msg)
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class UnionException < Exception
|
23
|
+
def initialize(msg)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class UnknownTypeException < Exception
|
29
|
+
def initialize(msg)
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
require 'sparsam/base_class'
|
3
|
+
|
4
|
+
module Sparsam
|
5
|
+
class Struct < ::Sparsam::BaseClass
|
6
|
+
include ::Sparsam::StructInitialization
|
7
|
+
|
8
|
+
def ==(other)
|
9
|
+
return true if other.equal?(self)
|
10
|
+
return false unless other.instance_of?(self.class)
|
11
|
+
|
12
|
+
each_field do |fid, info|
|
13
|
+
reader = name_to_accessors(info[:name]).reader
|
14
|
+
return false unless send(reader) == other.send(reader)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
alias_method :eql?, :==
|
18
|
+
|
19
|
+
def self.field_accessor(klass, field_key, field_info)
|
20
|
+
field_name = field_info[:name]
|
21
|
+
klass.class_eval(<<-EOF, __FILE__, __LINE__)
|
22
|
+
attr_accessor :'#{field_name}'
|
23
|
+
EOF
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def assign_defaults(defaults)
|
29
|
+
defaults.each do |name, default_value|
|
30
|
+
accessors = name_to_accessors(name)
|
31
|
+
send(accessors.writer, default_value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def assign_from_arg(d)
|
36
|
+
d.each do |name, value|
|
37
|
+
accessors = name_to_accessors(name)
|
38
|
+
unless accessors
|
39
|
+
raise Sparsam::Exception, "Unknown key given to #{self.class}.new: #{name}"
|
40
|
+
end
|
41
|
+
send(accessors.writer, value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
require 'set'
|
3
|
+
require 'sparsam/exceptions'
|
4
|
+
|
5
|
+
module Sparsam
|
6
|
+
module Types
|
7
|
+
STOP = 0
|
8
|
+
VOID = 1
|
9
|
+
BOOL = 2
|
10
|
+
BYTE = 3
|
11
|
+
DOUBLE = 4
|
12
|
+
I16 = 6
|
13
|
+
I32 = 8
|
14
|
+
I64 = 10
|
15
|
+
STRING = 11
|
16
|
+
STRUCT = 12
|
17
|
+
MAP = 13
|
18
|
+
SET = 14
|
19
|
+
LIST = 15
|
20
|
+
|
21
|
+
COLLECTIONS = Set.new([
|
22
|
+
SET,
|
23
|
+
LIST,
|
24
|
+
MAP,
|
25
|
+
]).freeze
|
26
|
+
end
|
27
|
+
|
28
|
+
# Deprecated type checking
|
29
|
+
|
30
|
+
def self.check_type(value, field, name, skip_nil = true)
|
31
|
+
return if value.nil? && skip_nil
|
32
|
+
|
33
|
+
valid =
|
34
|
+
case field[:type]
|
35
|
+
when Types::VOID
|
36
|
+
nil === value
|
37
|
+
when Types::BOOL
|
38
|
+
true === value || false === value
|
39
|
+
when Types::BYTE, Types::I16, Types::I32, Types::I64
|
40
|
+
Integer === value
|
41
|
+
when Types::DOUBLE
|
42
|
+
Float === value
|
43
|
+
when Types::STRING
|
44
|
+
String === value
|
45
|
+
when Types::STRUCT
|
46
|
+
Struct === value || Union === value
|
47
|
+
when Types::MAP
|
48
|
+
Hash === value
|
49
|
+
when Types::SET
|
50
|
+
Set === value
|
51
|
+
when Types::LIST
|
52
|
+
Array === value
|
53
|
+
else
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
unless valid
|
58
|
+
raise TypeMismatch, "Expected #{type_name(field[:type])}, " \
|
59
|
+
"received #{value.class} for field #{name}"
|
60
|
+
end
|
61
|
+
|
62
|
+
# check elements now
|
63
|
+
case field[:type]
|
64
|
+
when Types::MAP
|
65
|
+
# This is still allocations per MAP, but better than per map entry
|
66
|
+
key_str = "#{name}.key"
|
67
|
+
value_str = "#{name}.value"
|
68
|
+
|
69
|
+
value.each_pair do |k, v|
|
70
|
+
check_type(k, field[:key], key_str, false)
|
71
|
+
check_type(v, field[:value], value_str, false)
|
72
|
+
end
|
73
|
+
when Types::SET, Types::LIST
|
74
|
+
element_str = "#{name}.element"
|
75
|
+
|
76
|
+
value.each do |el|
|
77
|
+
check_type(el, field[:element], element_str, false)
|
78
|
+
end
|
79
|
+
when Types::STRUCT
|
80
|
+
unless field[:class] == value.class
|
81
|
+
raise TypeMismatch, "Expected #{field[:class]}, received #{value.class} for field #{name}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
TYPE_NAME_SYM_MAPPING = Types.constants.each_with_object({}) do |const, h|
|
87
|
+
h[Types.const_get(const)] = const.to_sym
|
88
|
+
end
|
89
|
+
|
90
|
+
TYPE_NAME_MAPPING = TYPE_NAME_SYM_MAPPING.each_with_object({}) do |(k, const), h|
|
91
|
+
h[k] = "Types::#{const}".freeze
|
92
|
+
end.freeze
|
93
|
+
|
94
|
+
def self.type_name_sym(type)
|
95
|
+
TYPE_NAME_SYM_MAPPING[type]
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.type_name(type)
|
99
|
+
TYPE_NAME_MAPPING[type]
|
100
|
+
end
|
101
|
+
|
102
|
+
module MessageTypes
|
103
|
+
CALL = 1
|
104
|
+
REPLY = 2
|
105
|
+
EXCEPTION = 3
|
106
|
+
ONEWAY = 4
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
require 'sparsam/base_class'
|
3
|
+
|
4
|
+
module Sparsam
|
5
|
+
class Union < ::Sparsam::BaseClass
|
6
|
+
def initialize(name = nil, value = nil)
|
7
|
+
if name
|
8
|
+
if name.is_a? Hash
|
9
|
+
if name.size > 1
|
10
|
+
raise ::Sparsam::UnionException,
|
11
|
+
"#{self.class} cannot be instantiated with more than one field!"
|
12
|
+
end
|
13
|
+
value = name.values.first
|
14
|
+
name = name.keys.first
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
if name
|
19
|
+
accessors = name_to_accessors(name)
|
20
|
+
unless accessors
|
21
|
+
raise Sparsam::Exception, "Unknown key given to #{self.class}.new: #{name}"
|
22
|
+
end
|
23
|
+
|
24
|
+
send(accessors.writer, value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def ==(other)
|
29
|
+
other.equal?(self) ||
|
30
|
+
other.instance_of?(self.class) &&
|
31
|
+
@setfield == other.get_set_field &&
|
32
|
+
get_value == other.get_value
|
33
|
+
end
|
34
|
+
alias_method :eql?, :==
|
35
|
+
|
36
|
+
def hash
|
37
|
+
[self.class.name, @setfield, get_value].hash
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_set_field
|
41
|
+
@setfield
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_value
|
45
|
+
if @setfield
|
46
|
+
send(name_to_accessors(@setfield).reader)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.field_accessor(klass, field_key, field_info)
|
51
|
+
field_name = field_info[:name]
|
52
|
+
klass.class_eval(<<-EOF, __FILE__, __LINE__)
|
53
|
+
def #{field_name}
|
54
|
+
if :'#{field_name}' == @setfield
|
55
|
+
instance_variable_get(:'@#{field_name}')
|
56
|
+
else
|
57
|
+
raise ::Sparsam::UnionException, "#{field_name} is not union's set field"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def #{field_name}=(value)
|
62
|
+
if @setfield
|
63
|
+
remove_instance_variable(:"@\#{@setfield}")
|
64
|
+
end
|
65
|
+
|
66
|
+
@setfield = :'#{field_name}'
|
67
|
+
instance_variable_set(:'@#{field_name}', value)
|
68
|
+
end
|
69
|
+
EOF
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
#
|
2
|
+
# Autogenerated by Thrift Compiler (0.1.0)
|
3
|
+
#
|
4
|
+
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'sparsam'
|
8
|
+
|
9
|
+
module Magic
|
10
|
+
Black = 0
|
11
|
+
White = 1
|
12
|
+
Red = 2
|
13
|
+
Blue = 3
|
14
|
+
Green = 4
|
15
|
+
VALUE_MAP = {0 => "Black", 1 => "White", 2 => "Red", 3 => "Blue", 4 => "Green"}
|
16
|
+
VALID_VALUES = Set.new([Black, White, Red, Blue, Green]).freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
class US < ::Sparsam::Struct
|
20
|
+
FIELDS = {
|
21
|
+
1 => {:type => ::Sparsam::Types::I32, :name => 'id_i32', :optional => true},
|
22
|
+
2 => {:type => ::Sparsam::Types::STRING, :name => 'id_s', :default => %q"id_s default", :binary => true, :optional => true},
|
23
|
+
3 => {:type => ::Sparsam::Types::SET, :name => 'string_set', :element => {:type => ::Sparsam::Types::STRING}, :optional => true},
|
24
|
+
4 => {:type => ::Sparsam::Types::SET, :name => 'int_set', :element => {:type => ::Sparsam::Types::I32}, :optional => true}
|
25
|
+
}
|
26
|
+
|
27
|
+
init_thrift_struct(self)
|
28
|
+
end
|
29
|
+
|
30
|
+
class UN < ::Sparsam::Union
|
31
|
+
FIELDS = {
|
32
|
+
1 => {:type => ::Sparsam::Types::I32, :name => 'id_i32', :optional => true},
|
33
|
+
2 => {:type => ::Sparsam::Types::STRING, :name => 'id_s', :optional => true}
|
34
|
+
}
|
35
|
+
|
36
|
+
init_thrift_struct(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
class SS < ::Sparsam::Struct
|
40
|
+
FIELDS = {
|
41
|
+
1 => {:type => ::Sparsam::Types::I32, :name => 'id_i32', :optional => true},
|
42
|
+
2 => {:type => ::Sparsam::Types::STRING, :name => 'id_s', :optional => true},
|
43
|
+
3 => {:type => ::Sparsam::Types::STRUCT, :name => 'us_i', :class => ::US, :optional => true},
|
44
|
+
4 => {:type => ::Sparsam::Types::SET, :name => 'us_s', :element => {:type => ::Sparsam::Types::STRUCT, :class => ::US}, :optional => true},
|
45
|
+
5 => {:type => ::Sparsam::Types::LIST, :name => 's_l', :element => {:type => ::Sparsam::Types::STRING}, :optional => true},
|
46
|
+
6 => {:type => ::Sparsam::Types::MAP, :name => 'mappy', :key => {:type => ::Sparsam::Types::I32}, :value => {:type => ::Sparsam::Types::STRING}, :optional => true},
|
47
|
+
7 => {:type => ::Sparsam::Types::BYTE, :name => 'byte_field', :optional => true},
|
48
|
+
8 => {:type => ::Sparsam::Types::STRUCT, :name => 'un_field', :class => ::UN, :optional => true},
|
49
|
+
9 => {:type => ::Sparsam::Types::I32, :name => 'magic_field', :optional => true, :enum_class => ::Magic},
|
50
|
+
10 => {:type => ::Sparsam::Types::MAP, :name => 'troll', :key => {:type => ::Sparsam::Types::I32}, :value => {:type => ::Sparsam::Types::MAP, :key => {:type => ::Sparsam::Types::I32}, :value => {:type => ::Sparsam::Types::I32}}, :optional => true}
|
51
|
+
}
|
52
|
+
|
53
|
+
init_thrift_struct(self)
|
54
|
+
end
|
55
|
+
|
56
|
+
class MiniRequired < ::Sparsam::Struct
|
57
|
+
FIELDS = {
|
58
|
+
1 => {:type => ::Sparsam::Types::I32, :name => 'id_i32'}
|
59
|
+
}
|
60
|
+
|
61
|
+
init_thrift_struct(self)
|
62
|
+
end
|
63
|
+
|
64
|
+
class EasilyInvalid < ::Sparsam::Struct
|
65
|
+
FIELDS = {
|
66
|
+
1 => {:type => ::Sparsam::Types::STRUCT, :name => 'tail', :class => ::EasilyInvalid, :optional => true},
|
67
|
+
2 => {:type => ::Sparsam::Types::SET, :name => 's_self', :element => {:type => ::Sparsam::Types::STRUCT, :class => ::EasilyInvalid}, :optional => true},
|
68
|
+
3 => {:type => ::Sparsam::Types::LIST, :name => 'l_self', :element => {:type => ::Sparsam::Types::STRUCT, :class => ::EasilyInvalid}, :optional => true},
|
69
|
+
4 => {:type => ::Sparsam::Types::MAP, :name => 'mappy1', :key => {:type => ::Sparsam::Types::STRUCT, :class => ::EasilyInvalid}, :value => {:type => ::Sparsam::Types::I32}, :optional => true},
|
70
|
+
5 => {:type => ::Sparsam::Types::MAP, :name => 'mappy2', :key => {:type => ::Sparsam::Types::I32}, :value => {:type => ::Sparsam::Types::STRUCT, :class => ::EasilyInvalid}, :optional => true},
|
71
|
+
6 => {:type => ::Sparsam::Types::MAP, :name => 'mappy3', :key => {:type => ::Sparsam::Types::STRUCT, :class => ::EasilyInvalid}, :value => {:type => ::Sparsam::Types::STRUCT, :class => ::EasilyInvalid}, :optional => true},
|
72
|
+
7 => {:type => ::Sparsam::Types::LIST, :name => 'sure', :element => {:type => ::Sparsam::Types::MAP, :key => {:type => ::Sparsam::Types::SET, :element => {:type => ::Sparsam::Types::I32}}, :value => {:type => ::Sparsam::Types::MAP, :key => {:type => ::Sparsam::Types::I32}, :value => {:type => ::Sparsam::Types::SET, :element => {:type => ::Sparsam::Types::LIST, :element => {:type => ::Sparsam::Types::MAP, :key => {:type => ::Sparsam::Types::STRUCT, :class => ::EasilyInvalid}, :value => {:type => ::Sparsam::Types::STRING}}}}}}, :optional => true},
|
73
|
+
8 => {:type => ::Sparsam::Types::STRUCT, :name => 'required_stuff', :class => ::MiniRequired, :optional => true},
|
74
|
+
9 => {:type => ::Sparsam::Types::I32, :name => 'id_i32', :optional => true}
|
75
|
+
}
|
76
|
+
|
77
|
+
init_thrift_struct(self)
|
78
|
+
end
|
79
|
+
|
80
|
+
class NotSS < ::Sparsam::Struct
|
81
|
+
FIELDS = {
|
82
|
+
1 => {:type => ::Sparsam::Types::STRING, :name => 'id_s', :optional => true},
|
83
|
+
3 => {:type => ::Sparsam::Types::I32, :name => 'id_i32', :optional => true}
|
84
|
+
}
|
85
|
+
|
86
|
+
init_thrift_struct(self)
|
87
|
+
end
|
88
|
+
|
89
|
+
class NotSS_plus < ::Sparsam::Struct
|
90
|
+
FIELDS = {
|
91
|
+
1 => {:type => ::Sparsam::Types::STRING, :name => 'id_s', :optional => true},
|
92
|
+
2 => {:type => ::Sparsam::Types::STRING, :name => 'id_s2', :optional => true},
|
93
|
+
3 => {:type => ::Sparsam::Types::I32, :name => 'id_i32', :optional => true}
|
94
|
+
}
|
95
|
+
|
96
|
+
init_thrift_struct(self)
|
97
|
+
end
|
98
|
+
|
99
|
+
class Nothing < ::Sparsam::Struct
|
100
|
+
FIELDS = {
|
101
|
+
|
102
|
+
}
|
103
|
+
|
104
|
+
init_thrift_struct(self)
|
105
|
+
end
|
106
|
+
|