payshares-xdr 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +14 -0
- data/.yardopts +7 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +202 -0
- data/README.md +106 -0
- data/Rakefile +9 -0
- data/examples/enum.rb +30 -0
- data/examples/struct.rb +24 -0
- data/examples/union.rb +36 -0
- data/lib/xdr.rb +73 -0
- data/lib/xdr/array.rb +28 -0
- data/lib/xdr/bool.rb +24 -0
- data/lib/xdr/concerns/array_converter.rb +5 -0
- data/lib/xdr/concerns/converts_to_xdr.rb +67 -0
- data/lib/xdr/concerns/float_converter.rb +5 -0
- data/lib/xdr/concerns/integer_converter.rb +5 -0
- data/lib/xdr/concerns/reads_bytes.rb +8 -0
- data/lib/xdr/concerns/string_converter.rb +5 -0
- data/lib/xdr/double.rb +14 -0
- data/lib/xdr/dsl.rb +7 -0
- data/lib/xdr/dsl/enum.rb +24 -0
- data/lib/xdr/dsl/struct.rb +13 -0
- data/lib/xdr/dsl/union.rb +32 -0
- data/lib/xdr/enum.rb +48 -0
- data/lib/xdr/float.rb +14 -0
- data/lib/xdr/hyper.rb +14 -0
- data/lib/xdr/int.rb +14 -0
- data/lib/xdr/namespace.rb +26 -0
- data/lib/xdr/opaque.rb +28 -0
- data/lib/xdr/option.rb +30 -0
- data/lib/xdr/quadruple.rb +5 -0
- data/lib/xdr/rpc.rb +6 -0
- data/lib/xdr/rpc/record.rb +7 -0
- data/lib/xdr/rpc/record_reader.rb +16 -0
- data/lib/xdr/string.rb +36 -0
- data/lib/xdr/struct.rb +51 -0
- data/lib/xdr/struct_validator.rb +6 -0
- data/lib/xdr/union.rb +101 -0
- data/lib/xdr/union_validator.rb +7 -0
- data/lib/xdr/unsigned_hyper.rb +14 -0
- data/lib/xdr/unsigned_int.rb +14 -0
- data/lib/xdr/var_array.rb +38 -0
- data/lib/xdr/var_opaque.rb +36 -0
- data/lib/xdr/version.rb +3 -0
- data/lib/xdr/void.rb +14 -0
- data/payshares-xdr.gemspec +29 -0
- data/spec/lib/xdr/array_spec.rb +73 -0
- data/spec/lib/xdr/bool_spec.rb +43 -0
- data/spec/lib/xdr/concerns/converts_to_xdr_spec.rb +55 -0
- data/spec/lib/xdr/concerns/reads_bytes_spec.rb +31 -0
- data/spec/lib/xdr/double_spec.rb +38 -0
- data/spec/lib/xdr/dsl/enum_spec.rb +44 -0
- data/spec/lib/xdr/dsl/struct_spec.rb +29 -0
- data/spec/lib/xdr/dsl/union_spec.rb +22 -0
- data/spec/lib/xdr/enum_spec.rb +70 -0
- data/spec/lib/xdr/float_spec.rb +37 -0
- data/spec/lib/xdr/hyper_spec.rb +40 -0
- data/spec/lib/xdr/int_spec.rb +40 -0
- data/spec/lib/xdr/opaque_spec.rb +36 -0
- data/spec/lib/xdr/option_spec.rb +36 -0
- data/spec/lib/xdr/quadruple_spec.rb +14 -0
- data/spec/lib/xdr/rpc/record_reader_spec.rb +27 -0
- data/spec/lib/xdr/string_spec.rb +41 -0
- data/spec/lib/xdr/struct_spec.rb +101 -0
- data/spec/lib/xdr/union_spec.rb +248 -0
- data/spec/lib/xdr/unsigned_hyper_spec.rb +36 -0
- data/spec/lib/xdr/unsigned_int_spec.rb +36 -0
- data/spec/lib/xdr/var_array_spec.rb +71 -0
- data/spec/lib/xdr/var_opaque_spec.rb +43 -0
- data/spec/lib/xdr/void_spec.rb +46 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/matchers/eq_bytes.rb +6 -0
- metadata +257 -0
data/lib/xdr.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require "xdr/version"
|
2
|
+
require "active_model"
|
3
|
+
require "active_support/concern"
|
4
|
+
require "active_support/dependencies/autoload"
|
5
|
+
require "active_support/core_ext/object/blank"
|
6
|
+
require "active_support/core_ext/object/try"
|
7
|
+
require "active_support/core_ext/module/attribute_accessors"
|
8
|
+
require "active_support/core_ext/class/attribute"
|
9
|
+
require "active_support/core_ext/hash/indifferent_access"
|
10
|
+
require "active_support/core_ext/string/inflections"
|
11
|
+
require "active_support/logger"
|
12
|
+
require "active_support/ordered_hash"
|
13
|
+
require "backports/2.1.0"
|
14
|
+
|
15
|
+
module XDR
|
16
|
+
extend ActiveSupport::Autoload
|
17
|
+
|
18
|
+
MAX_SIZE = 2**32 - 1
|
19
|
+
|
20
|
+
autoload :Namespace
|
21
|
+
autoload :RPC
|
22
|
+
autoload :DSL
|
23
|
+
|
24
|
+
# Compound Type
|
25
|
+
autoload :Struct
|
26
|
+
autoload :Union
|
27
|
+
autoload :Enum
|
28
|
+
|
29
|
+
# Primitive Types
|
30
|
+
autoload :Array
|
31
|
+
autoload :Option
|
32
|
+
autoload :Int
|
33
|
+
autoload :UnsignedInt
|
34
|
+
autoload :Hyper
|
35
|
+
autoload :UnsignedHyper
|
36
|
+
autoload :Float
|
37
|
+
autoload :Double
|
38
|
+
autoload :Quadruple
|
39
|
+
autoload :Bool
|
40
|
+
autoload :Opaque
|
41
|
+
autoload :VarOpaque
|
42
|
+
autoload :VarArray
|
43
|
+
autoload :String
|
44
|
+
autoload :Void
|
45
|
+
|
46
|
+
# Validators
|
47
|
+
autoload :StructValidator
|
48
|
+
autoload :UnionValidator
|
49
|
+
|
50
|
+
module Concerns
|
51
|
+
extend ActiveSupport::Autoload
|
52
|
+
autoload :ReadsBytes
|
53
|
+
autoload :ConvertsToXDR
|
54
|
+
autoload :IntegerConverter
|
55
|
+
autoload :FloatConverter
|
56
|
+
autoload :StringConverter
|
57
|
+
autoload :ArrayConverter
|
58
|
+
end
|
59
|
+
|
60
|
+
class Error < StandardError ; end
|
61
|
+
class ReadError < Error ; end
|
62
|
+
class EnumValueError < ReadError ; end
|
63
|
+
class EnumNameError < ReadError ; end
|
64
|
+
class WriteError < Error ; end
|
65
|
+
|
66
|
+
class InvalidSwitchError < Error ; end
|
67
|
+
class InvalidValueError < Error ; end
|
68
|
+
class ArmNotSetError < Error ; end
|
69
|
+
|
70
|
+
mattr_accessor :logger
|
71
|
+
self.logger = ActiveSupport::Logger.new(STDOUT)
|
72
|
+
self.logger.level = Logger::WARN
|
73
|
+
end
|
data/lib/xdr/array.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class XDR::Array
|
2
|
+
include XDR::Concerns::ConvertsToXDR
|
3
|
+
include XDR::Concerns::ArrayConverter
|
4
|
+
|
5
|
+
singleton_class.send(:alias_method, :[], :new)
|
6
|
+
|
7
|
+
def initialize(child_type, length)
|
8
|
+
@child_type = child_type
|
9
|
+
@length = length
|
10
|
+
end
|
11
|
+
|
12
|
+
def write(val, io)
|
13
|
+
raise XDR::WriteError, "val is not array" unless val.is_a?(Array)
|
14
|
+
raise XDR::WriteError, "array must be #{@length} long, was #{val.length}" if val.length != @length
|
15
|
+
|
16
|
+
@length.times do |i|
|
17
|
+
@child_type.write val[i], io
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def read(io)
|
22
|
+
@length.times.map{ @child_type.read(io) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid?(val)
|
26
|
+
super(val) && val.length == @length
|
27
|
+
end
|
28
|
+
end
|
data/lib/xdr/bool.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module XDR::Bool
|
2
|
+
extend XDR::Concerns::ConvertsToXDR
|
3
|
+
|
4
|
+
def self.write(val, io)
|
5
|
+
case val
|
6
|
+
when true ; XDR::Int.write(1, io)
|
7
|
+
when false ; XDR::Int.write(0, io)
|
8
|
+
else ; raise XDR::WriteError, "Invalid bool value: #{val}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.read(io)
|
13
|
+
val = XDR::Int.read(io)
|
14
|
+
case val
|
15
|
+
when 0 ; false
|
16
|
+
when 1 ; true
|
17
|
+
else ; raise XDR::ReadError, "Invalid bool value: #{val}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.valid?(val)
|
22
|
+
val == true || val == false
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module XDR::Concerns::ConvertsToXDR
|
2
|
+
include XDR::Concerns::ReadsBytes
|
3
|
+
|
4
|
+
#
|
5
|
+
# Serialized the provided `val` to xdr and writes it to `io`
|
6
|
+
#
|
7
|
+
# @param val [Object] The object to serialize
|
8
|
+
# @param io [IO] an IO object to write to
|
9
|
+
#
|
10
|
+
def write(val, io)
|
11
|
+
raise NotImplementedError, "implement in including class"
|
12
|
+
end
|
13
|
+
|
14
|
+
#
|
15
|
+
# Reads from the provided IO an instance of the implementing class
|
16
|
+
# @param io [IO] the io to read from
|
17
|
+
#
|
18
|
+
# @return [Object] the deserialized value
|
19
|
+
def read(io)
|
20
|
+
raise NotImplementedError, "implement in including class"
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Returns true if the value provided is compatible with this serializer class
|
25
|
+
#
|
26
|
+
# @param value [Object] the value to test
|
27
|
+
#
|
28
|
+
# @return [Boolean] true if valid, false otherwise
|
29
|
+
def valid?(value)
|
30
|
+
raise NotImplementedError, "implement in including class"
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Serialized the provided val to xdr, returning a string
|
35
|
+
# of the serialized data
|
36
|
+
#
|
37
|
+
# @param val [Object] the value to serialize
|
38
|
+
#
|
39
|
+
# @return [String] the produced bytes
|
40
|
+
def to_xdr(val)
|
41
|
+
StringIO.
|
42
|
+
new.
|
43
|
+
tap{|io| write(val, io)}.
|
44
|
+
string.force_encoding("ASCII-8BIT")
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Deserializes an object from the provided string of bytes
|
49
|
+
#
|
50
|
+
# @param string [String] the bytes to read from
|
51
|
+
#
|
52
|
+
# @return [Object] the deserialized value
|
53
|
+
def from_xdr(string)
|
54
|
+
io = StringIO.new(string)
|
55
|
+
read(io)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def padding_for(length)
|
60
|
+
case length % 4
|
61
|
+
when 0 ; 0
|
62
|
+
when 1 ; 3
|
63
|
+
when 2 ; 2
|
64
|
+
when 3 ; 1
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/xdr/double.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module XDR::Double
|
2
|
+
extend XDR::Concerns::ConvertsToXDR
|
3
|
+
extend XDR::Concerns::FloatConverter
|
4
|
+
|
5
|
+
def self.write(val, io)
|
6
|
+
raise XDR::WriteError unless valid?(val)
|
7
|
+
io.write [val].pack("G")
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.read(io)
|
11
|
+
read_bytes(io, 8).unpack("G").first
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/lib/xdr/dsl.rb
ADDED
data/lib/xdr/dsl/enum.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module XDR::DSL::Enum
|
2
|
+
|
3
|
+
def member(name, value)
|
4
|
+
raise ArgumentError, "#{self} is sealed" if self.sealed
|
5
|
+
raise ArgumentError, "#{value} is not Fixnum" unless value.is_a?(Fixnum)
|
6
|
+
raise ArgumentError, "#{value} is already used" unless
|
7
|
+
|
8
|
+
name = name.to_s.underscore
|
9
|
+
|
10
|
+
instance = new(name, value)
|
11
|
+
self.members = self.members.merge(name => instance)
|
12
|
+
self.by_value = self.by_value.merge(instance.value => instance)
|
13
|
+
|
14
|
+
class_eval <<-EOS, __FILE__, __LINE__
|
15
|
+
def self.#{name}
|
16
|
+
members["#{name}"]
|
17
|
+
end
|
18
|
+
EOS
|
19
|
+
end
|
20
|
+
|
21
|
+
def seal
|
22
|
+
self.sealed = true
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module XDR::DSL::Struct
|
2
|
+
def attribute(name, type)
|
3
|
+
|
4
|
+
unless type.is_a?(XDR::Concerns::ConvertsToXDR)
|
5
|
+
raise ArgumentError, "#{type} does not convert to xdr"
|
6
|
+
end
|
7
|
+
|
8
|
+
self.fields = self.fields.merge(name => type)
|
9
|
+
|
10
|
+
attr_accessor name
|
11
|
+
define_attribute_methods name
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module XDR::DSL::Union
|
2
|
+
def switch_on(type, name)
|
3
|
+
raise ArgumentError if self.switch_type.present?
|
4
|
+
self.switch_type = type
|
5
|
+
self.switch_name = name
|
6
|
+
|
7
|
+
alias_method name, :switch
|
8
|
+
end
|
9
|
+
|
10
|
+
def switch(switch, arm=nil)
|
11
|
+
raise ArgumentError, "`switch_on` not defined yet" if self.switch_type.nil?
|
12
|
+
|
13
|
+
switch = normalize_switch(switch)
|
14
|
+
self.switches = self.switches.merge(switch => arm)
|
15
|
+
end
|
16
|
+
|
17
|
+
def attribute(name, type)
|
18
|
+
raise ArgumentError, "#{type} does not convert to xdr" unless type.is_a?(XDR::Concerns::ConvertsToXDR)
|
19
|
+
|
20
|
+
self.arms = self.arms.merge(name => type)
|
21
|
+
define_attribute_methods name
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def normalize_switch(switch)
|
26
|
+
case switch
|
27
|
+
when self.switch_type ; switch
|
28
|
+
when :default ; switch
|
29
|
+
else ; self.switch_type.from_name(switch)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/xdr/enum.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
class XDR::Enum
|
2
|
+
extend XDR::Concerns::ConvertsToXDR
|
3
|
+
extend XDR::DSL::Enum
|
4
|
+
|
5
|
+
class_attribute :members
|
6
|
+
class_attribute :by_value
|
7
|
+
class_attribute :sealed
|
8
|
+
self.members = ActiveSupport::OrderedHash.new.with_indifferent_access
|
9
|
+
self.by_value = ActiveSupport::OrderedHash.new
|
10
|
+
self.sealed = false
|
11
|
+
|
12
|
+
def self.write(val, io)
|
13
|
+
raise XDR::WriteError, "Invalid enum value: #{val.inspect}" unless val.is_a?(self)
|
14
|
+
|
15
|
+
XDR::Int.write(val.value, io)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.read(io)
|
19
|
+
value = XDR::Int.read(io)
|
20
|
+
by_value[value].tap do |result|
|
21
|
+
raise XDR::EnumValueError, "Unknown #{name} member: #{value}" if result.blank?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.valid?(val)
|
26
|
+
val.is_a?(self)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.from_name(name)
|
30
|
+
normalized = name.to_s.underscore
|
31
|
+
members[normalized].tap do |r|
|
32
|
+
raise XDR::EnumNameError, "#{name} is not a member of #{self.name}" if r.blank?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :name
|
37
|
+
attr_reader :value
|
38
|
+
|
39
|
+
def initialize(name, value)
|
40
|
+
raise ArgumentError, "#{self.class} is sealed" if self.sealed
|
41
|
+
@name = name
|
42
|
+
@value = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
"#{self.class.name}.#{@name}(#{@value})"
|
47
|
+
end
|
48
|
+
end
|
data/lib/xdr/float.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module XDR::Float
|
2
|
+
extend XDR::Concerns::ConvertsToXDR
|
3
|
+
extend XDR::Concerns::FloatConverter
|
4
|
+
|
5
|
+
def self.write(val, io)
|
6
|
+
raise XDR::WriteError unless val.is_a?(Float)
|
7
|
+
io.write [val].pack("g")
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.read(io)
|
11
|
+
read_bytes(io, 4).unpack("g").first
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/lib/xdr/hyper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module XDR::Hyper
|
2
|
+
extend XDR::Concerns::ConvertsToXDR
|
3
|
+
extend XDR::Concerns::IntegerConverter
|
4
|
+
|
5
|
+
def self.write(val, io)
|
6
|
+
raise XDR::WriteError, "val is not Integer" unless val.is_a?(Integer)
|
7
|
+
# TODO: check bounds
|
8
|
+
io.write [val].pack("q>")
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.read(io)
|
12
|
+
read_bytes(io, 8).unpack("q>").first
|
13
|
+
end
|
14
|
+
end
|
data/lib/xdr/int.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module XDR::Int
|
2
|
+
extend XDR::Concerns::ConvertsToXDR
|
3
|
+
extend XDR::Concerns::IntegerConverter
|
4
|
+
|
5
|
+
def self.write(val, io)
|
6
|
+
raise XDR::WriteError, "val is not Integer" unless val.is_a?(Integer)
|
7
|
+
# TODO: check bounds
|
8
|
+
io.write [val].pack("l>")
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.read(io)
|
12
|
+
read_bytes(io, 4).unpack("l>").first
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#
|
2
|
+
# A thin wrapper around ActiveSupport::Autoload configured to always eager_load
|
3
|
+
# a child. By calling `load_all!` on the namespace module, all children will
|
4
|
+
# be eager loaded, allowing us to more easily operate in a multi-threaded
|
5
|
+
# environment.
|
6
|
+
#
|
7
|
+
module XDR::Namespace
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
extend ActiveSupport::Autoload
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def load_all!
|
16
|
+
constants.each do |const_name|
|
17
|
+
begin
|
18
|
+
const = const_get const_name
|
19
|
+
const.public_send :load_all! if const.respond_to? :load_all!
|
20
|
+
rescue NameError => e
|
21
|
+
raise e unless e.message =~ /uninitialized constant #{const_name}/
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|