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.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.travis.yml +14 -0
  4. data/.yardopts +7 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +5 -0
  7. data/LICENSE.txt +202 -0
  8. data/README.md +106 -0
  9. data/Rakefile +9 -0
  10. data/examples/enum.rb +30 -0
  11. data/examples/struct.rb +24 -0
  12. data/examples/union.rb +36 -0
  13. data/lib/xdr.rb +73 -0
  14. data/lib/xdr/array.rb +28 -0
  15. data/lib/xdr/bool.rb +24 -0
  16. data/lib/xdr/concerns/array_converter.rb +5 -0
  17. data/lib/xdr/concerns/converts_to_xdr.rb +67 -0
  18. data/lib/xdr/concerns/float_converter.rb +5 -0
  19. data/lib/xdr/concerns/integer_converter.rb +5 -0
  20. data/lib/xdr/concerns/reads_bytes.rb +8 -0
  21. data/lib/xdr/concerns/string_converter.rb +5 -0
  22. data/lib/xdr/double.rb +14 -0
  23. data/lib/xdr/dsl.rb +7 -0
  24. data/lib/xdr/dsl/enum.rb +24 -0
  25. data/lib/xdr/dsl/struct.rb +13 -0
  26. data/lib/xdr/dsl/union.rb +32 -0
  27. data/lib/xdr/enum.rb +48 -0
  28. data/lib/xdr/float.rb +14 -0
  29. data/lib/xdr/hyper.rb +14 -0
  30. data/lib/xdr/int.rb +14 -0
  31. data/lib/xdr/namespace.rb +26 -0
  32. data/lib/xdr/opaque.rb +28 -0
  33. data/lib/xdr/option.rb +30 -0
  34. data/lib/xdr/quadruple.rb +5 -0
  35. data/lib/xdr/rpc.rb +6 -0
  36. data/lib/xdr/rpc/record.rb +7 -0
  37. data/lib/xdr/rpc/record_reader.rb +16 -0
  38. data/lib/xdr/string.rb +36 -0
  39. data/lib/xdr/struct.rb +51 -0
  40. data/lib/xdr/struct_validator.rb +6 -0
  41. data/lib/xdr/union.rb +101 -0
  42. data/lib/xdr/union_validator.rb +7 -0
  43. data/lib/xdr/unsigned_hyper.rb +14 -0
  44. data/lib/xdr/unsigned_int.rb +14 -0
  45. data/lib/xdr/var_array.rb +38 -0
  46. data/lib/xdr/var_opaque.rb +36 -0
  47. data/lib/xdr/version.rb +3 -0
  48. data/lib/xdr/void.rb +14 -0
  49. data/payshares-xdr.gemspec +29 -0
  50. data/spec/lib/xdr/array_spec.rb +73 -0
  51. data/spec/lib/xdr/bool_spec.rb +43 -0
  52. data/spec/lib/xdr/concerns/converts_to_xdr_spec.rb +55 -0
  53. data/spec/lib/xdr/concerns/reads_bytes_spec.rb +31 -0
  54. data/spec/lib/xdr/double_spec.rb +38 -0
  55. data/spec/lib/xdr/dsl/enum_spec.rb +44 -0
  56. data/spec/lib/xdr/dsl/struct_spec.rb +29 -0
  57. data/spec/lib/xdr/dsl/union_spec.rb +22 -0
  58. data/spec/lib/xdr/enum_spec.rb +70 -0
  59. data/spec/lib/xdr/float_spec.rb +37 -0
  60. data/spec/lib/xdr/hyper_spec.rb +40 -0
  61. data/spec/lib/xdr/int_spec.rb +40 -0
  62. data/spec/lib/xdr/opaque_spec.rb +36 -0
  63. data/spec/lib/xdr/option_spec.rb +36 -0
  64. data/spec/lib/xdr/quadruple_spec.rb +14 -0
  65. data/spec/lib/xdr/rpc/record_reader_spec.rb +27 -0
  66. data/spec/lib/xdr/string_spec.rb +41 -0
  67. data/spec/lib/xdr/struct_spec.rb +101 -0
  68. data/spec/lib/xdr/union_spec.rb +248 -0
  69. data/spec/lib/xdr/unsigned_hyper_spec.rb +36 -0
  70. data/spec/lib/xdr/unsigned_int_spec.rb +36 -0
  71. data/spec/lib/xdr/var_array_spec.rb +71 -0
  72. data/spec/lib/xdr/var_opaque_spec.rb +43 -0
  73. data/spec/lib/xdr/void_spec.rb +46 -0
  74. data/spec/spec_helper.rb +15 -0
  75. data/spec/support/matchers/eq_bytes.rb +6 -0
  76. metadata +257 -0
@@ -0,0 +1,28 @@
1
+ class XDR::Opaque
2
+ include XDR::Concerns::ConvertsToXDR
3
+ include XDR::Concerns::StringConverter
4
+
5
+ singleton_class.send(:alias_method, :[], :new)
6
+
7
+ def initialize(length)
8
+ @length = length
9
+ @padding = padding_for length
10
+ end
11
+
12
+ def read(io)
13
+ # read and return @length bytes
14
+ # throw away @padding bytes
15
+ read_bytes(io, @length).tap{ read_bytes(io, @padding) }
16
+ end
17
+
18
+ def write(val,io)
19
+ length = val.bytesize
20
+
21
+ if val.length != @length
22
+ raise XDR::WriteError, "Value length is #{length}, must be #{@length}"
23
+ end
24
+
25
+ io.write val
26
+ io.write "\x00" * @padding
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ class XDR::Option
2
+ include XDR::Concerns::ConvertsToXDR
3
+
4
+ singleton_class.send(:alias_method, :[], :new)
5
+
6
+ attr_reader :child_type
7
+
8
+ def initialize(child_type)
9
+ #TODO, raise an error if child_type is not ConvertToXDR
10
+ @child_type = child_type
11
+ end
12
+
13
+ def write(val, io)
14
+ if val.present?
15
+ XDR::Bool.write(true, io)
16
+ @child_type.write(val, io)
17
+ else
18
+ XDR::Bool.write(false, io)
19
+ end
20
+ end
21
+
22
+ def read(io)
23
+ present = XDR::Bool.read(io)
24
+ @child_type.read(io) if present
25
+ end
26
+
27
+ def valid?(val)
28
+ val.nil? || @child_type.valid?(val)
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ module XDR::Quadruple
2
+ extend XDR::Concerns::ConvertsToXDR
3
+
4
+ # No support for quads, so we don't overide read/write
5
+ end
@@ -0,0 +1,6 @@
1
+ module XDR::RPC
2
+ extend ActiveSupport::Autoload
3
+
4
+ autoload :Record
5
+ autoload :RecordReader
6
+ end
@@ -0,0 +1,7 @@
1
+ XDR::RPC::Record = Struct.new(:last, :length, :content)
2
+
3
+ XDR::RPC::Record.class_eval do
4
+ def last?
5
+ self.last
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ class XDR::RPC::RecordReader
2
+ include XDR::Concerns::ReadsBytes
3
+
4
+ LAST_MASK = 0x80000000
5
+ LENGTH_MASK = 0x7FFFFFFF
6
+
7
+ def read(io)
8
+ header = read_bytes(io, 4).unpack("L>").first
9
+ length = header & LENGTH_MASK
10
+ last = (header & LAST_MASK) > 0
11
+ raw_content = read_bytes(io, length)
12
+ content = StringIO.new(raw_content)
13
+
14
+ XDR::RPC::Record.new(last, length, content)
15
+ end
16
+ end
@@ -0,0 +1,36 @@
1
+ class XDR::String
2
+ include XDR::Concerns::ConvertsToXDR
3
+ include XDR::Concerns::StringConverter
4
+
5
+ singleton_class.send(:alias_method, :[], :new)
6
+
7
+ def initialize(length=XDR::MAX_SIZE)
8
+ @length = length
9
+ end
10
+
11
+ def write(val, io)
12
+ length = val.bytesize
13
+
14
+ if length > @length
15
+ raise XDR::WriteError, "Value length #{length} exceeds max #{@length}"
16
+ end
17
+
18
+ XDR::Int.write(length, io)
19
+ io.write val
20
+ io.write "\x00" * padding_for(length)
21
+ end
22
+
23
+ def read(io)
24
+ length = XDR::Int.read(io)
25
+
26
+ if length > @length
27
+ raise XDR::ReadError, "String length #{length} is greater than max"
28
+ end
29
+
30
+ padding = padding_for length
31
+
32
+ # read and return length bytes
33
+ # throw away padding bytes
34
+ read_bytes(io, length).tap{ read_bytes(io, padding) }
35
+ end
36
+ end
@@ -0,0 +1,51 @@
1
+ require 'base64'
2
+
3
+ class XDR::Struct
4
+ include ActiveModel::Model
5
+ include ActiveModel::AttributeMethods
6
+
7
+ extend XDR::Concerns::ConvertsToXDR
8
+ extend XDR::DSL::Struct
9
+
10
+ class_attribute :fields
11
+ self.fields = ActiveSupport::OrderedHash.new
12
+
13
+ validates_with XDR::StructValidator
14
+
15
+ def self.read(io)
16
+ new.tap do |result|
17
+ fields.each do |name, type|
18
+ result.public_send("#{name}=", type.read(io))
19
+ end
20
+ end
21
+ end
22
+
23
+ def self.write(val, io)
24
+ fields.each do |name, type|
25
+ field_val = val.public_send(name)
26
+ type.write(field_val, io)
27
+ end
28
+ end
29
+
30
+ def self.valid?(val)
31
+ val.is_a?(self)
32
+ end
33
+
34
+ #
35
+ # Serializes struct to xdr, return a string of bytes
36
+ #
37
+ # @param format=:raw [Symbol] The encoding used for the bytes produces, one of (:raw, :hex, :base64)
38
+ #
39
+ # @return [String] The encoded bytes of this struct
40
+ def to_xdr(format=:raw)
41
+ raw = self.class.to_xdr(self)
42
+
43
+ case format
44
+ when :raw ; raw
45
+ when :hex ; raw.unpack("H*").first
46
+ when :base64 ; Base64.strict_encode64(raw)
47
+ else ;
48
+ raise ArgumentError, "Invalid format #{format.inspect}; must be :raw, :hex, or :base64"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,6 @@
1
+ class XDR::StructValidator < ActiveModel::Validator
2
+ def validate(struct)
3
+ # validate each field
4
+ # TODO
5
+ end
6
+ end
@@ -0,0 +1,101 @@
1
+ class XDR::Union
2
+ include ActiveModel::Model
3
+ include ActiveModel::AttributeMethods
4
+
5
+ extend XDR::Concerns::ConvertsToXDR
6
+ extend XDR::DSL::Union
7
+
8
+
9
+ class_attribute :arms
10
+ class_attribute :switches
11
+ class_attribute :switch_type
12
+ class_attribute :switch_name
13
+ attr_reader :switch
14
+ attr_reader :arm
15
+
16
+ self.arms = ActiveSupport::OrderedHash.new
17
+ self.switches = ActiveSupport::OrderedHash.new
18
+ self.switch_type = nil
19
+ self.switch_name = nil
20
+
21
+ attribute_method_suffix '!'
22
+
23
+ def self.arm_for_switch(switch)
24
+ raise XDR::InvalidSwitchError unless switch.is_a?(switch_type)
25
+
26
+ result = switches.fetch(switch, :switch_not_found)
27
+ result = switches.fetch(:default, :switch_not_found) if result == :switch_not_found
28
+
29
+ if result == :switch_not_found
30
+ raise XDR::InvalidSwitchError, "Bad switch: #{switch}"
31
+ end
32
+
33
+ result
34
+ end
35
+
36
+ def self.read(io)
37
+ switch = switch_type.read(io)
38
+ arm = arm_for_switch(switch)
39
+ arm_type = arms[arm] || XDR::Void
40
+ value = arm_type.read(io)
41
+ new(switch, value)
42
+ end
43
+
44
+ def self.write(val, io)
45
+ switch_type.write(val.switch, io)
46
+ arm_type = arms[val.arm] || XDR::Void
47
+ arm_type.write(val.get,io)
48
+ end
49
+
50
+ def self.valid?(val)
51
+ val.is_a?(self)
52
+ end
53
+
54
+ def initialize(switch=nil, value=:void)
55
+ @switch = nil
56
+ @arm = nil
57
+ @value = nil
58
+ set(switch, value) if switch
59
+ end
60
+
61
+ def to_xdr
62
+ self.class.to_xdr self
63
+ end
64
+
65
+ def set(switch, value=:void)
66
+ @switch = switch.is_a?(switch_type) ? switch : switch_type.from_name(switch)
67
+ @arm = self.class.arm_for_switch @switch
68
+
69
+ raise XDR::InvalidValueError unless valid_for_arm_type(value, @arm)
70
+
71
+ @value = value
72
+ rescue XDR::EnumNameError
73
+ raise XDR::InvalidSwitchError, "Bad switch: #{switch}"
74
+ end
75
+
76
+ def value
77
+ @value unless @value == :void
78
+ end
79
+
80
+ alias get value
81
+
82
+ def attribute!(attr)
83
+ if @arm.to_s != attr
84
+ raise XDR::ArmNotSetError, "#{attr} is not the set arm"
85
+ end
86
+
87
+ get
88
+ end
89
+
90
+ private
91
+ def valid_for_arm_type(value, arm)
92
+ arm_type = arms[@arm]
93
+
94
+ return value == :void if arm_type.nil?
95
+
96
+ arm_type.valid?(value)
97
+ end
98
+ end
99
+
100
+
101
+
@@ -0,0 +1,7 @@
1
+ class XDR::UnionValidator < ActiveModel::Validator
2
+ def validate(union)
3
+ # validate a discriminant is set
4
+ # validate the arm is compatible with the set discriminant
5
+ # TODO
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ module XDR::UnsignedHyper
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
@@ -0,0 +1,14 @@
1
+ module XDR::UnsignedInt
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,38 @@
1
+ class XDR::VarArray
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=XDR::MAX_SIZE)
8
+ @child_type = child_type
9
+ @length = length
10
+ end
11
+
12
+ def write(val, io)
13
+ length = val.length
14
+
15
+ if length > @length
16
+ raise XDR::WriteError, "Value length #{length} exceeds max #{@length}"
17
+ end
18
+
19
+ XDR::Int.write(length, io)
20
+ val.each do |member|
21
+ @child_type.write member, io
22
+ end
23
+ end
24
+
25
+ def read(io)
26
+ length = XDR::Int.read(io)
27
+
28
+ if length > @length
29
+ raise XDR::ReadError, "VarArray length #{length} is greater than max #{@length}"
30
+ end
31
+
32
+ length.times.map{ @child_type.read(io) }
33
+ end
34
+
35
+ def valid?(val)
36
+ super(val) && val.length <= @length
37
+ end
38
+ end
@@ -0,0 +1,36 @@
1
+ class XDR::VarOpaque
2
+ include XDR::Concerns::ConvertsToXDR
3
+ include XDR::Concerns::StringConverter
4
+
5
+ singleton_class.send(:alias_method, :[], :new)
6
+
7
+ def initialize(length=XDR::MAX_SIZE)
8
+ @length = length
9
+ end
10
+
11
+ def write(val, io)
12
+ length = val.bytesize
13
+
14
+ if length > @length
15
+ raise XDR::WriteError, "Value length #{length} exceeds max #{@length}"
16
+ end
17
+
18
+ XDR::Int.write(length, io)
19
+ io.write val
20
+ io.write "\x00" * padding_for(length)
21
+ end
22
+
23
+ def read(io)
24
+ length = XDR::Int.read(io)
25
+
26
+ if length > @length
27
+ raise XDR::ReadError, "VarOpaque length #{length}"
28
+ end
29
+
30
+ padding = padding_for length
31
+
32
+ # read and return length bytes
33
+ # throw away padding bytes
34
+ read_bytes(io, length).tap{ read_bytes(io, padding) }
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module XDR
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,14 @@
1
+ module XDR::Void
2
+ extend XDR::Concerns::ConvertsToXDR
3
+
4
+ def self.write(val, io)
5
+ end
6
+
7
+ def self.read(io)
8
+ :void
9
+ end
10
+
11
+ def self.valid?(val)
12
+ val == :void
13
+ end
14
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'xdr/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "payshares-xdr"
8
+ spec.version = XDR::VERSION
9
+ spec.authors = ["Kedia"]
10
+ spec.email = ["support@payshares.org"]
11
+ spec.summary = %q{Payshares XDR Helper Library}
12
+ spec.homepage = "https://github.com/payshares/ruby-payshares-xdr"
13
+ spec.license = "Apache 2.0"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "activesupport", "4.1.9"
21
+ spec.add_dependency "activemodel", "4.1.9"
22
+ spec.add_dependency "backports", "3.6.4"
23
+
24
+ spec.add_development_dependency "bundler", "1.17.3"
25
+ spec.add_development_dependency "rake", "10.4.2"
26
+ spec.add_development_dependency "rspec", "3.2.0"
27
+ spec.add_development_dependency "guard-rspec"
28
+ spec.add_development_dependency "simplecov"
29
+ end