capnp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ class Capnp::Message
7
+ extend T::Sig
8
+ extend T::Helpers
9
+ abstract!
10
+
11
+ sig { abstract.params(id: Integer).returns(Capnp::Segment) }
12
+ def segment(id)
13
+ end
14
+
15
+ sig { returns(Capnp::Reference) }
16
+ def root
17
+ segment(0).to_reference
18
+ end
19
+
20
+ # Takes a reference to a far pointer and returns a reference to the word(s) it targets
21
+ sig { params(far_pointer_ref: Capnp::Reference).returns(T.nilable([Capnp::Reference, T::Boolean])) }
22
+ private def dereference_far_pointer(far_pointer_ref)
23
+ # Grab lower and upper 32 bits of the pointer as signed integers
24
+ pointer_data = far_pointer_ref.read_bytes(0, Capnp::WORD_SIZE)
25
+ offset_words, segment_id = T.cast(pointer_data.unpack("L<L<"), [Integer, Integer])
26
+
27
+ # Return if the pointer is not a far pointer
28
+ return nil unless (offset_words & 0b11) == 2
29
+
30
+ # Get a reference to the targeted word(s)
31
+ target_offset = (offset_words >> 3) * Capnp::WORD_SIZE
32
+ single_far_pointer = (offset_words & 0b100).zero?
33
+ target_size = single_far_pointer ? 8 : 16
34
+ segment = segment(segment_id)
35
+
36
+ # TODO: Reconsider this check
37
+ raise Capnp::Error.new("Invalid offset #{target_offset} for segment #{segment_id} in far pointer") if segment.size <= target_offset + target_size
38
+
39
+ [segment.to_reference.offset_position(target_offset), single_far_pointer]
40
+ end
41
+
42
+ sig { params(pointer_ref: Capnp::Reference).returns([Capnp::Reference, T.nilable(Capnp::Reference)]) }
43
+ def dereference_pointer(pointer_ref)
44
+ target_ref, single_far_pointer = dereference_far_pointer(pointer_ref)
45
+
46
+ # Return if the pointer is not a far pointer
47
+ return pointer_ref, nil if target_ref.nil?
48
+
49
+ # Check if the target is a single far pointer
50
+ # If so, the first word is the new pointer
51
+ return target_ref, nil if single_far_pointer
52
+
53
+ # The first word is a far pointer to a block of content
54
+ content_ref, single_far_pointer = dereference_far_pointer(target_ref)
55
+ raise Capnp::Error.new("First word of double far pointer is not a far pointer") if content_ref.nil?
56
+ raise Capnp::Error.new("Double far pointer pointing to another double far pointer") unless single_far_pointer
57
+
58
+ # The second word is the new pointer
59
+ target_ref = target_ref.offset_position(Capnp::WORD_SIZE)
60
+ [target_ref, content_ref]
61
+ end
62
+ end
@@ -0,0 +1,50 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require_relative "message"
6
+
7
+ class Capnp::StreamMessage < Capnp::Message
8
+ extend T::Sig
9
+
10
+ sig { params(buffer: Capnp::SliceableBuffer).void }
11
+ def initialize(buffer)
12
+ # Extract number of segments
13
+ number_of_segments = buffer.read_u32(0) + 1
14
+
15
+ # Calculate size of the message header
16
+ offset = 4 * (number_of_segments + 1)
17
+ offset += 4 if number_of_segments.even?
18
+
19
+ # Check that the buffer is large enough for all segment sizes
20
+ raise Capnp::Error.new("Not enough segment sizes provided") if buffer.size <= offset
21
+
22
+ # Create segments
23
+ segments = (1..number_of_segments).map do |ix|
24
+ # Get segment size in bytes
25
+ segment_size = buffer.read_u32(ix * 4) * Capnp::WORD_SIZE
26
+
27
+ # Check that the buffer is large enough for the segment
28
+ raise Capnp::Error.new("Buffer smaller than provided segment sizes") if buffer.size < offset + segment_size
29
+
30
+ # Create segment
31
+ slice = buffer.slice(offset, segment_size)
32
+ segment = Capnp::Segment.new(self, slice)
33
+
34
+ offset += segment_size
35
+ segment
36
+ end
37
+
38
+ @segments = T.let(segments, T::Array[Capnp::Segment])
39
+ end
40
+
41
+ sig { returns(T::Array[Capnp::Segment]) }
42
+ attr_reader :segments
43
+
44
+ sig { override.params(id: Integer).returns(Capnp::Segment) }
45
+ def segment(id)
46
+ segment = @segments[id]
47
+ raise Capnp::Error.new("Unknown Segment ID #{id}") if segment.nil?
48
+ segment
49
+ end
50
+ end
@@ -0,0 +1,100 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require_relative "buffer/buffer"
6
+
7
+ class Capnp::Reference
8
+ extend T::Sig
9
+
10
+ sig { params(segment: Capnp::Segment, position: Integer).void }
11
+ def initialize(segment, position)
12
+ @segment = segment
13
+ @position = position
14
+ end
15
+
16
+ EMPTY = T.let(
17
+ Capnp::Reference.new(
18
+ Capnp::FlatMessage.new(Capnp::StringBuffer.new("")).segment(0),
19
+ 0
20
+ ),
21
+ Capnp::Reference
22
+ )
23
+
24
+ NULL_POINTER = T.let(
25
+ Capnp::Reference.new(
26
+ Capnp::FlatMessage.new(Capnp::StringBuffer.new("\x00\x00\x00\x00\x00\x00\x00\x00")).segment(0),
27
+ 0
28
+ ),
29
+ Capnp::Reference
30
+ )
31
+
32
+ sig { returns(Capnp::Segment) }
33
+ attr_reader :segment
34
+
35
+ sig { returns(Integer) }
36
+ attr_reader :position
37
+
38
+ sig { overridable.params(offset: Integer).returns(Capnp::Reference) }
39
+ def offset_position(offset) = self.class.new(@segment, @position + offset)
40
+
41
+ sig { params(offset: Integer, length: Integer).returns(String) }
42
+ def read_string(offset, length)
43
+ @segment.read_string(@position + offset, length)
44
+ end
45
+
46
+ sig { params(offset: Integer, length: Integer).returns(String) }
47
+ def read_bytes(offset, length)
48
+ @segment.read_bytes(@position + offset, length)
49
+ end
50
+
51
+ sig { params(offset: Integer).returns(Integer) }
52
+ def read_u8(offset)
53
+ @segment.read_u8(@position + offset)
54
+ end
55
+
56
+ sig { params(offset: Integer).returns(Integer) }
57
+ def read_u16(offset)
58
+ @segment.read_u16(@position + offset)
59
+ end
60
+
61
+ sig { params(offset: Integer).returns(Integer) }
62
+ def read_u32(offset)
63
+ @segment.read_u32(@position + offset)
64
+ end
65
+
66
+ sig { params(offset: Integer).returns(Integer) }
67
+ def read_u64(offset)
68
+ @segment.read_u64(@position + offset)
69
+ end
70
+
71
+ sig { params(offset: Integer).returns(Integer) }
72
+ def read_s8(offset)
73
+ @segment.read_s8(@position + offset)
74
+ end
75
+
76
+ sig { params(offset: Integer).returns(Integer) }
77
+ def read_s16(offset)
78
+ @segment.read_s16(@position + offset)
79
+ end
80
+
81
+ sig { params(offset: Integer).returns(Integer) }
82
+ def read_s32(offset)
83
+ @segment.read_s32(@position + offset)
84
+ end
85
+
86
+ sig { params(offset: Integer).returns(Integer) }
87
+ def read_s64(offset)
88
+ @segment.read_s64(@position + offset)
89
+ end
90
+
91
+ sig { params(offset: Integer).returns(Float) }
92
+ def read_f32(offset)
93
+ @segment.read_f32(@position + offset)
94
+ end
95
+
96
+ sig { params(offset: Integer).returns(Float) }
97
+ def read_f64(offset)
98
+ @segment.read_f64(@position + offset)
99
+ end
100
+ end
@@ -0,0 +1,89 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ class Capnp::Segment
7
+ extend T::Sig
8
+
9
+ include Capnp::Buffer
10
+
11
+ sig { params(message: Capnp::Message, buffer: Capnp::Buffer).void }
12
+ def initialize(message, buffer)
13
+ @message = message
14
+ @buffer = buffer
15
+ end
16
+
17
+ sig { returns(Capnp::Message) }
18
+ attr_reader :message
19
+
20
+ sig { override.params(offset: Integer, length: Integer).returns(String) }
21
+ def read_string(offset, length)
22
+ @buffer.read_string(offset, length)
23
+ end
24
+
25
+ sig { override.params(offset: Integer, length: Integer).returns(String) }
26
+ def read_bytes(offset, length)
27
+ @buffer.read_bytes(offset, length)
28
+ end
29
+
30
+ sig { override.params(offset: Integer).returns(Integer) }
31
+ def read_u8(offset)
32
+ @buffer.read_u8(offset)
33
+ end
34
+
35
+ sig { override.params(offset: Integer).returns(Integer) }
36
+ def read_u16(offset)
37
+ @buffer.read_u16(offset)
38
+ end
39
+
40
+ sig { override.params(offset: Integer).returns(Integer) }
41
+ def read_u32(offset)
42
+ @buffer.read_u32(offset)
43
+ end
44
+
45
+ sig { override.params(offset: Integer).returns(Integer) }
46
+ def read_u64(offset)
47
+ @buffer.read_u64(offset)
48
+ end
49
+
50
+ sig { override.params(offset: Integer).returns(Integer) }
51
+ def read_s8(offset)
52
+ @buffer.read_s8(offset)
53
+ end
54
+
55
+ sig { override.params(offset: Integer).returns(Integer) }
56
+ def read_s16(offset)
57
+ @buffer.read_s16(offset)
58
+ end
59
+
60
+ sig { override.params(offset: Integer).returns(Integer) }
61
+ def read_s32(offset)
62
+ @buffer.read_s32(offset)
63
+ end
64
+
65
+ sig { override.params(offset: Integer).returns(Integer) }
66
+ def read_s64(offset)
67
+ @buffer.read_s64(offset)
68
+ end
69
+
70
+ sig { override.params(offset: Integer).returns(Float) }
71
+ def read_f32(offset)
72
+ @buffer.read_f32(offset)
73
+ end
74
+
75
+ sig { override.params(offset: Integer).returns(Float) }
76
+ def read_f64(offset)
77
+ @buffer.read_f64(offset)
78
+ end
79
+
80
+ sig { override.returns(Integer) }
81
+ def size
82
+ @buffer.size
83
+ end
84
+
85
+ sig { returns(Capnp::Reference) }
86
+ def to_reference
87
+ Capnp::Reference.new(self, 0)
88
+ end
89
+ end
@@ -0,0 +1,159 @@
1
+ # typed: strict
2
+
3
+ require "sorbet-runtime"
4
+
5
+ class Capnp::Struct
6
+ extend T::Sig
7
+ extend T::Helpers
8
+
9
+ abstract!
10
+
11
+ sig { params(data: Capnp::Reference, data_size: Integer, pointers: Capnp::Reference, pointers_size: Integer).void }
12
+ def initialize(data, data_size, pointers, pointers_size)
13
+ @data = data
14
+ @data_size = data_size
15
+ @pointers = pointers
16
+ @pointers_size = pointers_size
17
+ end
18
+
19
+ sig do
20
+ params(pointer_ref: Capnp::Reference)
21
+ .returns([Integer, Integer, Integer])
22
+ end
23
+ def self.decode_pointer(pointer_ref)
24
+ # Fetch pointer data from buffer
25
+ data = pointer_ref.read_bytes(0, Capnp::WORD_SIZE)
26
+ parts = T.cast(data.unpack("l<S<S<"), [Integer, Integer, Integer])
27
+
28
+ # Check the type of the pointer
29
+ pointer_type = parts[0] & 0b11
30
+ raise Capnp::Error.new("Pointer has type #{pointer_type}") unless pointer_type == 0
31
+
32
+ # Shift offset to remove type bits
33
+ parts[0] >>= 2
34
+
35
+ parts
36
+ end
37
+
38
+ sig { params(pointer_ref: Capnp::Reference).returns(T.nilable(T.attached_class)) }
39
+ def self.from_pointer(pointer_ref)
40
+ # Process far pointers
41
+ pointer_ref, content_ref = pointer_ref.segment.message.dereference_pointer(pointer_ref)
42
+
43
+ # Decode the pointer
44
+ offset_words, data_words, pointers_words = decode_pointer(pointer_ref)
45
+
46
+ # Check for empty struct
47
+ return new(Capnp::Reference::EMPTY, 0, Capnp::Reference::EMPTY, 0) if offset_words == -1
48
+
49
+ # Check for NULL pointer
50
+ return nil if offset_words.zero? && data_words.zero? && pointers_words.zero?
51
+
52
+ # Extract data section
53
+ data_size = data_words * Capnp::WORD_SIZE
54
+ if content_ref.nil?
55
+ data_offset = (offset_words + 1) * Capnp::WORD_SIZE
56
+ data_ref = pointer_ref.offset_position(data_offset)
57
+ else
58
+ data_ref = content_ref
59
+ end
60
+
61
+ # Extract pointers section
62
+ pointers_size = pointers_words * Capnp::WORD_SIZE
63
+ pointers_ref = data_ref.offset_position(data_size)
64
+
65
+ new(data_ref, data_size, pointers_ref, pointers_size)
66
+ end
67
+
68
+ sig { abstract.returns(Object) }
69
+ def to_obj
70
+ end
71
+
72
+ private
73
+
74
+ sig { params(offset: Integer, default: Integer).returns(Integer) }
75
+ def read_u8(offset, default)
76
+ (offset >= @data_size) ? default : (@data.read_u8(offset) ^ default)
77
+ end
78
+
79
+ sig { params(offset: Integer, default: Integer).returns(Integer) }
80
+ def read_u16(offset, default)
81
+ (offset >= @data_size) ? default : (@data.read_u16(offset) ^ default)
82
+ end
83
+
84
+ sig { params(offset: Integer, default: Integer).returns(Integer) }
85
+ def read_u32(offset, default)
86
+ (offset >= @data_size) ? default : (@data.read_u32(offset) ^ default)
87
+ end
88
+
89
+ sig { params(offset: Integer, default: Integer).returns(Integer) }
90
+ def read_u64(offset, default)
91
+ (offset >= @data_size) ? default : (@data.read_u64(offset) ^ default)
92
+ end
93
+
94
+ sig { params(offset: Integer, default: Integer).returns(Integer) }
95
+ def read_s8(offset, default)
96
+ (offset >= @data_size) ? default : (@data.read_s8(offset) ^ default)
97
+ end
98
+
99
+ sig { params(offset: Integer, default: Integer).returns(Integer) }
100
+ def read_s16(offset, default)
101
+ (offset >= @data_size) ? default : (@data.read_s16(offset) ^ default)
102
+ end
103
+
104
+ sig { params(offset: Integer, default: Integer).returns(Integer) }
105
+ def read_s32(offset, default)
106
+ (offset >= @data_size) ? default : (@data.read_s32(offset) ^ default)
107
+ end
108
+
109
+ sig { params(offset: Integer, default: Integer).returns(Integer) }
110
+ def read_s64(offset, default)
111
+ (offset >= @data_size) ? default : (@data.read_s64(offset) ^ default)
112
+ end
113
+
114
+ sig { params(offset: Integer, default: Float).returns(Float) }
115
+ def read_f32(offset, default)
116
+ if offset >= @data_size
117
+ # The float is not in the data buffer
118
+ default
119
+
120
+ elsif default.zero?
121
+ # The float is in the data buffer and there is no default value
122
+ @data.read_f32(offset)
123
+
124
+ else
125
+ # The float is in the data buffer and there is a default value
126
+ default_int = [default].pack("e").unpack1("L<")
127
+ value = @data.read_u32(offset)
128
+ [value ^ default_int].pack("L<").unpack1("e")
129
+ end
130
+ end
131
+
132
+ sig { params(offset: Integer, default: Float).returns(Float) }
133
+ def read_f64(offset, default)
134
+ if offset >= @data_size
135
+ # The float is not in the data buffer
136
+ default
137
+
138
+ elsif default.zero?
139
+ # The float is in the data buffer and there is no default value
140
+ @data.read_f64(offset)
141
+
142
+ else
143
+ # The float is in the data buffer and there is a default value
144
+ default_int = [default].pack("E").unpack1("Q<")
145
+ value = @data.read_u64(offset)
146
+ [value ^ default_int].pack("Q<").unpack1("E")
147
+ end
148
+ end
149
+
150
+ sig { params(ix: Integer).returns(Capnp::Reference) }
151
+ def read_pointer(ix)
152
+ offset = ix * Capnp::WORD_SIZE
153
+
154
+ # The pointer is not in the pointer buffer
155
+ return Capnp::Reference::NULL_POINTER if offset >= @pointers_size
156
+
157
+ @pointers.offset_position(offset)
158
+ end
159
+ end
@@ -0,0 +1,3 @@
1
+ # typed: strict
2
+
3
+ Dir.glob(File.join(__dir__, "runtime", "**", "*.rb")) { |file| require file }
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capnp
4
+ VERSION = "0.0.1"
5
+ end
data/lib/capnp.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ require "sorbet-runtime"
5
+ require_relative "capnp/version"
6
+ require_relative "capnp/runtime"
7
+
8
+ module Capnp
9
+ extend T::Sig
10
+
11
+ WORD_SIZE = 8
12
+
13
+ class Error < StandardError; end
14
+ end
metadata ADDED
@@ -0,0 +1,200 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capnp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jack Moran
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 1980-01-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sorbet-runtime
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sorbet
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: tapioca
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ruby-lsp
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '5.22'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.22'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '13.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '13.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: standard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.3'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.3'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov-lcov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.8.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.8.0
139
+ description:
140
+ email:
141
+ - jack@earth.co.nz
142
+ executables:
143
+ - capnpc-ruby
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - bin/capnpc-ruby
148
+ - lib/capnp.rb
149
+ - lib/capnp/generator.rb
150
+ - lib/capnp/generator/generator.rb
151
+ - lib/capnp/generator/schema.capnp.rb
152
+ - lib/capnp/runtime.rb
153
+ - lib/capnp/runtime/buffer/buffer.rb
154
+ - lib/capnp/runtime/buffer/io_buffer.rb
155
+ - lib/capnp/runtime/buffer/sliceable_buffer.rb
156
+ - lib/capnp/runtime/buffer/string_buffer.rb
157
+ - lib/capnp/runtime/list/buffer/data.rb
158
+ - lib/capnp/runtime/list/buffer/list.rb
159
+ - lib/capnp/runtime/list/buffer/numeric.rb
160
+ - lib/capnp/runtime/list/buffer/string.rb
161
+ - lib/capnp/runtime/list/buffer/struct.rb
162
+ - lib/capnp/runtime/list/list.rb
163
+ - lib/capnp/runtime/list/object/list.rb
164
+ - lib/capnp/runtime/list/object/string.rb
165
+ - lib/capnp/runtime/list/string.rb
166
+ - lib/capnp/runtime/message/flat_message.rb
167
+ - lib/capnp/runtime/message/message.rb
168
+ - lib/capnp/runtime/message/stream_message.rb
169
+ - lib/capnp/runtime/reference.rb
170
+ - lib/capnp/runtime/segment.rb
171
+ - lib/capnp/runtime/struct.rb
172
+ - lib/capnp/version.rb
173
+ homepage: https://github.com/jasmoran/capnproto-ruby
174
+ licenses:
175
+ - MIT
176
+ metadata:
177
+ allowed_push_host: https://rubygems.org
178
+ homepage_uri: https://github.com/jasmoran/capnproto-ruby
179
+ source_code_uri: https://github.com/jasmoran/capnproto-ruby
180
+ changelog_uri: https://github.com/jasmoran/capnproto-ruby/blob/main/CHANGELOG.md
181
+ post_install_message:
182
+ rdoc_options: []
183
+ require_paths:
184
+ - lib
185
+ required_ruby_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: 3.0.0
190
+ required_rubygems_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ requirements: []
196
+ rubygems_version: 3.4.22
197
+ signing_key:
198
+ specification_version: 4
199
+ summary: Ruby support for the Cap'n Proto data interchange format
200
+ test_files: []