nl 0.2.4 → 0.4.1

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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/Rakefile +7 -0
  4. data/lib/nl/async/dispatcher.rb +199 -0
  5. data/lib/nl/async/driver.rb +37 -0
  6. data/lib/nl/async/mailbox.rb +81 -0
  7. data/lib/nl/async/operation.rb +277 -0
  8. data/lib/nl/async.rb +13 -0
  9. data/lib/nl/attribute_set.rb +173 -0
  10. data/lib/nl/bitfield32.rb +86 -0
  11. data/lib/nl/blocking_transport.rb +131 -0
  12. data/lib/nl/connection.rb +61 -0
  13. data/lib/nl/datagram.rb +22 -0
  14. data/lib/nl/datatypes.rb +454 -0
  15. data/lib/nl/decoder.rb +13 -1
  16. data/lib/nl/endian.rb +10 -0
  17. data/lib/nl/error.rb +10 -0
  18. data/lib/nl/exchange.rb +124 -0
  19. data/lib/nl/family.rb +117 -23
  20. data/lib/nl/genl/client.rb +104 -0
  21. data/lib/nl/genl/protocol.rb +59 -0
  22. data/lib/nl/genl/wire.rb +94 -0
  23. data/lib/nl/genl.rb +60 -73
  24. data/lib/nl/notification.rb +112 -0
  25. data/lib/nl/notification_router.rb +92 -0
  26. data/lib/nl/raw/client.rb +83 -0
  27. data/lib/nl/raw/protocol.rb +112 -0
  28. data/lib/nl/raw/wire.rb +146 -0
  29. data/lib/nl/raw.rb +104 -0
  30. data/lib/nl/sequence_allocator.rb +34 -0
  31. data/lib/nl/socket.rb +15 -12
  32. data/lib/nl/structured_payload.rb +61 -0
  33. data/lib/nl/sub_message.rb +94 -0
  34. data/lib/nl/version.rb +1 -1
  35. data/lib/nl.rb +10 -12
  36. data/sig/generated/nl/async/dispatcher.rbs +53 -0
  37. data/sig/generated/nl/async/driver.rbs +21 -0
  38. data/sig/generated/nl/async/mailbox.rbs +32 -0
  39. data/sig/generated/nl/async/operation.rbs +123 -0
  40. data/sig/generated/nl/async.rbs +9 -0
  41. data/sig/generated/nl/attribute_set.rbs +50 -0
  42. data/sig/generated/nl/bitfield32.rbs +41 -0
  43. data/sig/generated/nl/blocking_transport.rbs +33 -0
  44. data/sig/generated/nl/connection.rbs +26 -0
  45. data/sig/generated/nl/datagram.rbs +11 -0
  46. data/sig/generated/nl/datatypes.rbs +181 -0
  47. data/sig/generated/nl/decoder.rbs +38 -0
  48. data/sig/generated/nl/encoder.rbs +29 -0
  49. data/sig/generated/nl/endian.rbs +28 -0
  50. data/sig/generated/nl/error.rbs +27 -0
  51. data/sig/generated/nl/exchange.rbs +75 -0
  52. data/sig/generated/nl/family.rbs +71 -0
  53. data/sig/generated/nl/genl/client.rbs +74 -0
  54. data/sig/generated/nl/genl/protocol.rbs +37 -0
  55. data/sig/generated/nl/genl/wire.rbs +113 -0
  56. data/sig/generated/nl/genl.rbs +50 -0
  57. data/sig/generated/nl/notification.rbs +53 -0
  58. data/sig/generated/nl/notification_router.rbs +30 -0
  59. data/sig/generated/nl/raw/client.rbs +50 -0
  60. data/sig/generated/nl/raw/protocol.rbs +122 -0
  61. data/sig/generated/nl/raw/wire.rbs +151 -0
  62. data/sig/generated/nl/raw.rbs +70 -0
  63. data/sig/generated/nl/sequence_allocator.rbs +15 -0
  64. data/sig/generated/nl/socket.rbs +40 -0
  65. data/sig/generated/nl/structured_payload.rbs +25 -0
  66. data/sig/generated/nl/sub_message.rbs +74 -0
  67. data/sig/generated/nl/version.rbs +5 -0
  68. data/sig/generated/nl.rbs +2 -0
  69. metadata +65 -9
  70. data/lib/nl/core.rb +0 -94
  71. data/lib/nl/protocols/genl.rb +0 -55
  72. data/lib/nl/protocols/raw.rb +0 -395
@@ -0,0 +1,5 @@
1
+ # Generated from lib/nl/version.rb with RBS::Inline
2
+
3
+ module Nl
4
+ VERSION: ::String
5
+ end
@@ -0,0 +1,2 @@
1
+ # Generated from lib/nl.rb with RBS::Inline
2
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kasumi Hanazuki
@@ -9,7 +9,8 @@ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
- description: Linux Netlink client
12
+ description: nl is a general-purpose Netlink implementation for building Ruby applications
13
+ that communicate with Linux kernel APIs or other userspace processes.
13
14
  email:
14
15
  - kasumi@rollingapple.net
15
16
  executables: []
@@ -22,22 +23,77 @@ files:
22
23
  - README.md
23
24
  - Rakefile
24
25
  - lib/nl.rb
25
- - lib/nl/core.rb
26
+ - lib/nl/async.rb
27
+ - lib/nl/async/dispatcher.rb
28
+ - lib/nl/async/driver.rb
29
+ - lib/nl/async/mailbox.rb
30
+ - lib/nl/async/operation.rb
31
+ - lib/nl/attribute_set.rb
32
+ - lib/nl/bitfield32.rb
33
+ - lib/nl/blocking_transport.rb
34
+ - lib/nl/connection.rb
35
+ - lib/nl/datagram.rb
36
+ - lib/nl/datatypes.rb
26
37
  - lib/nl/decoder.rb
27
38
  - lib/nl/encoder.rb
28
39
  - lib/nl/endian.rb
40
+ - lib/nl/error.rb
41
+ - lib/nl/exchange.rb
29
42
  - lib/nl/family.rb
30
43
  - lib/nl/genl.rb
31
- - lib/nl/protocols/genl.rb
32
- - lib/nl/protocols/raw.rb
44
+ - lib/nl/genl/client.rb
45
+ - lib/nl/genl/protocol.rb
46
+ - lib/nl/genl/wire.rb
47
+ - lib/nl/notification.rb
48
+ - lib/nl/notification_router.rb
49
+ - lib/nl/raw.rb
50
+ - lib/nl/raw/client.rb
51
+ - lib/nl/raw/protocol.rb
52
+ - lib/nl/raw/wire.rb
53
+ - lib/nl/sequence_allocator.rb
33
54
  - lib/nl/socket.rb
55
+ - lib/nl/structured_payload.rb
56
+ - lib/nl/sub_message.rb
34
57
  - lib/nl/version.rb
58
+ - sig/generated/nl.rbs
59
+ - sig/generated/nl/async.rbs
60
+ - sig/generated/nl/async/dispatcher.rbs
61
+ - sig/generated/nl/async/driver.rbs
62
+ - sig/generated/nl/async/mailbox.rbs
63
+ - sig/generated/nl/async/operation.rbs
64
+ - sig/generated/nl/attribute_set.rbs
65
+ - sig/generated/nl/bitfield32.rbs
66
+ - sig/generated/nl/blocking_transport.rbs
67
+ - sig/generated/nl/connection.rbs
68
+ - sig/generated/nl/datagram.rbs
69
+ - sig/generated/nl/datatypes.rbs
70
+ - sig/generated/nl/decoder.rbs
71
+ - sig/generated/nl/encoder.rbs
72
+ - sig/generated/nl/endian.rbs
73
+ - sig/generated/nl/error.rbs
74
+ - sig/generated/nl/exchange.rbs
75
+ - sig/generated/nl/family.rbs
76
+ - sig/generated/nl/genl.rbs
77
+ - sig/generated/nl/genl/client.rbs
78
+ - sig/generated/nl/genl/protocol.rbs
79
+ - sig/generated/nl/genl/wire.rbs
80
+ - sig/generated/nl/notification.rbs
81
+ - sig/generated/nl/notification_router.rbs
82
+ - sig/generated/nl/raw.rbs
83
+ - sig/generated/nl/raw/client.rbs
84
+ - sig/generated/nl/raw/protocol.rbs
85
+ - sig/generated/nl/raw/wire.rbs
86
+ - sig/generated/nl/sequence_allocator.rbs
87
+ - sig/generated/nl/socket.rbs
88
+ - sig/generated/nl/structured_payload.rbs
89
+ - sig/generated/nl/sub_message.rbs
90
+ - sig/generated/nl/version.rbs
35
91
  homepage: https://github.com/hanazuki/nl
36
92
  licenses:
37
93
  - MIT
38
94
  metadata:
39
95
  homepage_uri: https://github.com/hanazuki/nl
40
- source_code_uri: https://github.com/hanazuki/nl/tree/v0.2.4
96
+ source_code_uri: https://github.com/hanazuki/nl/tree/v0.4.1
41
97
  changelog_uri: https://github.com/hanazuki/nl/blob/master/CHANGELOG.md
42
98
  rdoc_options: []
43
99
  require_paths:
@@ -46,14 +102,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
46
102
  requirements:
47
103
  - - ">="
48
104
  - !ruby/object:Gem::Version
49
- version: '3.1'
105
+ version: '3.4'
50
106
  required_rubygems_version: !ruby/object:Gem::Requirement
51
107
  requirements:
52
108
  - - ">="
53
109
  - !ruby/object:Gem::Version
54
110
  version: '0'
55
111
  requirements: []
56
- rubygems_version: 4.0.6
112
+ rubygems_version: 4.0.16
57
113
  specification_version: 4
58
- summary: Linux Netlink client
114
+ summary: Netlink protocol support for Ruby
59
115
  test_files: []
data/lib/nl/core.rb DELETED
@@ -1,94 +0,0 @@
1
- # Data types and message handling
2
-
3
- require_relative 'endian'
4
-
5
- module Nl
6
- module Core
7
- module Constants
8
- # From include/uapi/linux/netlink.h
9
- NETLINK_ROUTE = 0
10
- NETLINK_NETFILTER = 12
11
- NETLINK_GENERIC = 16
12
-
13
- NLM_F_REQUEST = 1
14
- NLM_F_MULTI = 2
15
- NLM_F_ACK = 4
16
- NLM_F_ECHO = 8
17
- NLM_F_DUMP_INTR = 16
18
- NLM_F_DUMP_FILTERED = 32
19
- NLM_F_ROOT = 0x100
20
- NLM_F_MATCH = 0x200
21
- NLM_F_ATOMIC = 0x400
22
- NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH
23
- NLM_F_REPLACE = 0x100
24
- NLM_F_EXCL = 0x200
25
- NLM_F_CREATE = 0x400
26
- NLM_F_APPEND = 0x800
27
-
28
- NLMSG_ALIGNTO = 4
29
- NLMSG_HDRLEN = 16
30
-
31
- NLMSG_NOOP = 0x1
32
- NLMSG_ERROR = 0x2
33
- NLMSG_DONE = 0x3
34
- NLMSG_OVERRUN = 0x4
35
-
36
- NLMSG_MIN_TYPE = 0x10
37
-
38
- NLA_F_NESTED = 1 << 15
39
- NLA_F_NET_BYTEORDER = 1 << 14
40
- NLA_TYPE_MASK = ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
41
-
42
- NLA_ALIGNTO = 4
43
- NLA_HDRLEN = 4
44
- end
45
- include Constants
46
-
47
- NlMsgHdr = Struct.new(:len, :type, :flags, :seq, :pid)
48
- # Message header
49
- class NlMsgHdr
50
- FORMAT = Ractor.make_shareable([
51
- Endian::Host::U32,
52
- Endian::Host::U16,
53
- Endian::Host::U16,
54
- Endian::Host::U32,
55
- Endian::Host::U32,
56
- ])
57
- private_constant :FORMAT
58
-
59
- def self.decode(decoder)
60
- obj = new(*decoder.get_values(FORMAT))
61
- decoder.align_to(Constants::NLMSG_ALIGNTO)
62
- obj
63
- end
64
-
65
- def encode(encoder)
66
- encoder.reserve(Constants::NLMSG_HDRLEN)
67
- encoder.put_values(FORMAT, to_a)
68
- encoder.align_to(Constants::NLMSG_ALIGNTO)
69
- end
70
- end
71
-
72
- NlAttr = Struct.new(:len, :type)
73
- # Attribute header
74
- class NlAttr
75
- FORMAT = Ractor.make_shareable([
76
- Endian::Host::U16,
77
- Endian::Host::U16,
78
- ])
79
- private_constant :FORMAT
80
-
81
- def self.decode(decoder)
82
- obj = new(*decoder.get_values(FORMAT))
83
- decoder.align_to(Constants::NLA_ALIGNTO)
84
- obj
85
- end
86
-
87
- def encode(encoder)
88
- encoder.reserve(Constants::NLA_HDRLEN)
89
- encoder.put_values(FORMAT, to_a)
90
- encoder.align_to(Constants::NLA_ALIGNTO)
91
- end
92
- end
93
- end
94
- end
@@ -1,55 +0,0 @@
1
- module Nl
2
- module Protocols
3
- # The Generic Netlink protocol
4
- class Genl < Raw
5
- GenlMsgHdr = ::Struct.new(:cmd, :version, :reserved)
6
- class GenlMsgHdr
7
- FORMAT = Ractor.make_shareable([
8
- Endian::Host::U8,
9
- Endian::Host::U8,
10
- Endian::Host::U16,
11
- ])
12
-
13
- def self.decode(decoder)
14
- new(*decoder.get_values(FORMAT))
15
- end
16
-
17
- def encode(encoder)
18
- encoder.put_values(FORMAT, to_a)
19
- end
20
- end
21
-
22
- def initialize(name, family_id: nil)
23
- super(name, Core::NETLINK_GENERIC)
24
- @family_id = family_id || default_family_id(name)
25
- end
26
-
27
- def family_id
28
- @family_id or raise NotImplementedError, "Genetlink family ID for '#{name}' must be resolved via nlctrl"
29
- end
30
-
31
- def encode_message(encoder, message)
32
- cmd = message.nlmsg_header.type
33
- encoder.measure(Endian::Host::U16) do
34
- message.nlmsg_header.type = family_id
35
- message.nlmsg_header.encode(encoder)
36
- message.nlmsg_header.type = cmd
37
- GenlMsgHdr.new(cmd, 1, 0).encode(encoder)
38
- message.fixed_header&.encode(encoder)
39
- message.attributes.encode(encoder)
40
- end
41
- end
42
-
43
- class Message < Raw::Message
44
- def self.decode(decoder, header)
45
- genlhdr = GenlMsgHdr.decode(decoder)
46
- super(decoder, header, type: genlhdr.cmd)
47
- end
48
- end
49
-
50
- private def default_family_id(name)
51
- Nl::Genl::GENL_ID_CTRL if name == 'nlctrl'
52
- end
53
- end
54
- end
55
- end
@@ -1,395 +0,0 @@
1
- require_relative '../encoder'
2
- require_relative '../decoder'
3
-
4
- module Nl
5
- module Protocols
6
- # The raw Netlink protocol
7
- class Raw
8
- class Done
9
- end
10
- class Ack
11
- end
12
-
13
- attr_reader :name, :protonum
14
-
15
- def initialize(name, protonum)
16
- @name = name
17
- @protonum = protonum
18
- end
19
-
20
- def encode_message(encoder, message)
21
- message.encode(encoder)
22
- end
23
-
24
- def decode_message(decoder, message_class)
25
- header = NlMsgHdr.decode(decoder)
26
- decoder.limit(header.len - Core::NLMSG_HDRLEN) do
27
- message_class.decode(decoder, header)
28
- end
29
- end
30
-
31
- def send_message(socket, message)
32
- seq_pid = socket.complete(message.nlmsg_header)
33
- encoder = Encoder.new
34
- encode_message(encoder, message)
35
- socket.sendmsg(encoder.buffer.get_string, 0, Socket.sockaddr_nl(0, 0))
36
- seq_pid
37
- end
38
-
39
- def recv_message(socket, seq_pid, message_class)
40
- data, = socket.recvmsg
41
-
42
- decoder = Decoder.new(IO::Buffer.for(data))
43
- while decoder.available?(Core::NLMSG_HDRLEN)
44
- header = Core::NlMsgHdr.decode(decoder)
45
- decoder.align_to(Core::NLMSG_ALIGNTO)
46
- raise binding.irb unless [header.seq, header.pid] == seq_pid
47
- if header.type < Core::NLMSG_MIN_TYPE
48
- # Control messages
49
- case header.type
50
- when Core::NLMSG_ERROR
51
- errno = decoder.get_value(Endian::Host::SINT)
52
- if errno == 0
53
- yield Ack.new
54
- else
55
- yield SystemCallError.new(-errno)
56
- end
57
- decoder.skip(header.len - Core::NLMSG_HDRLEN - 4)
58
- when Core::NLMSG_DONE
59
- yield Done.new
60
- decoder.skip(header.len - Core::NLMSG_HDRLEN)
61
- else
62
- # just ignore NLMSG_NOOP and other unknown control messages
63
- decoder.skip(header.len - Core::NLMSG_HDRLEN)
64
- end
65
- else
66
- # Subsystem-specific messages
67
- decoder.limit(header.len - Core::NLMSG_HDRLEN) do
68
- decoder.align_to(Core::NLMSG_ALIGNTO)
69
- yield message_class.decode(decoder, header)
70
- end
71
- end
72
- end
73
- end
74
-
75
- # @param socket [Socket] Netlink socket
76
- # @param type [:do, :dump] Request type
77
- # @param request_class [Class] Request message class
78
- # @param reply_class [Class] Reply message class
79
- # @param args [Hash] Request arguments
80
- def exchange_message(socket, type, request_class, reply_class, args)
81
- flags = Core::NLM_F_REQUEST
82
- flags |= type == :dump ? Core::NLM_F_DUMP : Core::NLM_F_ACK
83
-
84
- request = request_class.from_params(args)
85
- request.nlmsg_header.flags = flags
86
- seq_pid = send_message(socket, request)
87
-
88
- result = [] unless block_given?
89
-
90
- done = false
91
- begin
92
- recv_message(socket, seq_pid, reply_class) do |message|
93
- case message
94
- when Done, Ack
95
- done = true
96
- when Exception
97
- raise message
98
- else
99
- if block_given?
100
- yield message
101
- else
102
- result << message
103
- end
104
- end
105
- end
106
- end until done
107
-
108
- unless block_given?
109
- type == :dump ? result : result.first
110
- end
111
- end
112
-
113
- class AttributeSet
114
- Attribute = Struct.new(:value)
115
- class Attribute
116
- def self.decode(decoder)
117
- value = self::DATATYPE.decode(decoder)
118
- new(value)
119
- end
120
-
121
- def encode(encoder)
122
- self.class::DATATYPE.encode(encoder, self.value)
123
- end
124
- end
125
-
126
- def initialize(attributes)
127
- attr_class = self.class::Attribute
128
-
129
- attributes.each do |attr|
130
- unless attr.kind_of?(attr_class)
131
- raise TypeError, "attribute must be an instance of #{attr_class}"
132
- end
133
- end
134
-
135
- @attributes = Array(attributes)
136
- end
137
-
138
- def [](type)
139
- case type
140
- when Symbol
141
- attr_class = self.class.by_name(type)
142
- when Integer
143
- attr_class = self.class.by_type(type)
144
- else
145
- raise TypeError, "attribute type must be a Symbol or an Integer"
146
- end
147
-
148
- # TODO: multi-attr
149
- @attributes.find { it.kind_of?(attr_class) } rescue binding.irb
150
- end
151
-
152
- def <<(attr)
153
- attr_class = self.class::Attribute
154
- unless attr.kind_of?(attr_class)
155
- raise TypeError, "attribute must be an instance of #{attr_class}"
156
- end
157
-
158
- @attributes << attr
159
- end
160
-
161
- private def encode1(encoder, attr)
162
- nlattr = Core::NlAttr.new(0, attr.class::TYPE)
163
- encoder.measure(Endian::Host::U16) do
164
- nlattr.encode(encoder)
165
- attr.encode(encoder)
166
- end
167
- encoder.align_to(Core::NLA_ALIGNTO)
168
- end
169
-
170
- def encode(encoder)
171
- @attributes.each do |attr|
172
- encode1(encoder, attr)
173
- end
174
- end
175
-
176
- class << self
177
- private def decode1(decoder)
178
- nlattr = Core::NlAttr.decode(decoder)
179
- attr = decoder.limit(nlattr.len - Core::NLA_HDRLEN) do
180
- if attr_class = self::BY_TYPE[nlattr.type & Core::NLA_TYPE_MASK]
181
- attr_class.decode(decoder)
182
- else
183
- decoder.skip
184
- nil
185
- end
186
- end
187
- decoder.align_to(Core::NLA_ALIGNTO)
188
- attr
189
- end
190
-
191
- def decode(decoder)
192
- attrs = []
193
- while decoder.available?
194
- attr = decode1(decoder)
195
- attrs << attr
196
- end
197
- new(attrs.compact)
198
- end
199
-
200
- def build_attributes(**params)
201
- attrs = params.map do |name, value|
202
- attr_class = self::BY_NAME[name] or raise "Unknown attribute #{name}"
203
- attr_class.new(value)
204
- end
205
- new(attrs)
206
- end
207
- end
208
- end
209
-
210
- class Message
211
- attr_accessor :nlmsg_header, :fixed_header, :attributes
212
-
213
- def initialize(header, fixed_header = nil, attributes = self.class::ATTRIBUTE_SET.new)
214
- @nlmsg_header = header
215
- @fixed_header = fixed_header
216
- @attributes = attributes
217
- end
218
-
219
- def self.from_params(params)
220
- if self::FIXED_HEADER
221
- header_params = params.slice(*self::FIXED_HEADER.members)
222
- fixed_header = self::FIXED_HEADER.new(**header_params)
223
- end
224
- attribute_params = params.slice(*self::ATTRIBUTES)
225
- attributes = self::ATTRIBUTE_SET.build_attributes(**attribute_params)
226
-
227
- unknown = params.keys - attribute_params.keys
228
- unknown -= header_params.keys if header_params
229
- unless unknown.empty?
230
- raise ArgumentError, "unknown parameters: #{unknown.join(', ')}"
231
- end
232
-
233
- header = Core::NlMsgHdr.new(0, self::TYPE, nil, nil, nil)
234
- new(header, fixed_header, attributes)
235
- end
236
-
237
- def append_attribute(attribute)
238
- @attributes << attribute
239
- end
240
-
241
- def encode(encoder)
242
- encoder.measure(Endian::Host::U16) do
243
- @nlmsg_header.encode(encoder)
244
- @fixed_header&.encode(encoder)
245
- @attributes.encode(encoder)
246
- end
247
- end
248
-
249
- def self.decode(decoder, header, type: header.type)
250
- unless self::TYPE == type
251
- raise "Expected message type #{self::TYPE}, got #{type}"
252
- end
253
-
254
- if fixed_header_class = self::FIXED_HEADER
255
- fixed_header = fixed_header_class.decode(decoder)
256
- end
257
-
258
- attributes = self::ATTRIBUTE_SET.decode(decoder)
259
-
260
- new(header, fixed_header, attributes)
261
- end
262
- end
263
-
264
- module DataTypes
265
- class Scalar
266
- def initialize(type, check)
267
- @type = type
268
- @check = check
269
- end
270
-
271
- def encode(encoder, value)
272
- value ||= 0
273
- encoder.put_value(@type, value.tap(&@check))
274
- end
275
-
276
- def decode(decoder)
277
- value = decoder.get_value(@type).tap(&@check)
278
- end
279
- end
280
-
281
- class String
282
- def initialize(check)
283
- @check = check
284
- end
285
-
286
- def encode(encoder, value)
287
- encoder.put_zstring(value)
288
- end
289
-
290
- def decode(decoder)
291
- decoder.get_zstring
292
- end
293
- end
294
-
295
- class Binary
296
- def initialize(check)
297
- @check = check
298
- end
299
-
300
- def encode(encoder, value)
301
- encoder.put_string(value)
302
- end
303
-
304
- def decode(decoder)
305
- decoder.get_string
306
- end
307
- end
308
-
309
- class Flag
310
- def encode(encoder, value)
311
- # flag attribute has no payload; presence encodes true
312
- end
313
-
314
- def decode(decoder)
315
- true
316
- end
317
- end
318
-
319
- # A 32-bit value paired with a selector mask (8 bytes total: value u32 + selector u32)
320
- class Bitfield32
321
- def encode(encoder, value)
322
- v, selector = value.is_a?(Array) ? value : [value, 0xFFFFFFFF]
323
- encoder.put_value(Endian::Host::U32, v)
324
- encoder.put_value(Endian::Host::U32, selector)
325
- end
326
-
327
- def decode(decoder)
328
- value = decoder.get_value(Endian::Host::U32)
329
- selector = decoder.get_value(Endian::Host::U32)
330
- [value, selector]
331
- end
332
- end
333
-
334
- class Pad
335
- def initialize(length = nil)
336
- @length = length
337
- end
338
-
339
- def encode(encoder, _value)
340
- encoder.put_string(?\0.b * @length) if @length
341
- end
342
-
343
- def decode(decoder)
344
- @length ? decoder.skip(@length) : decoder.skip
345
- nil
346
- end
347
- end
348
-
349
- class NestedAttributes
350
- def initialize(attribute_set)
351
- @attribute_set = attribute_set
352
- end
353
-
354
- def encode(encoder, value)
355
- @attribute_set.encode(encoder, value)
356
- end
357
-
358
- def decode(decoder)
359
- @attribute_set.decode(decoder)
360
- end
361
- end
362
-
363
- class IndexedArray
364
- def initialize(sub_type)
365
- @sub_type = sub_type
366
- end
367
-
368
- def encode(encoder, values)
369
- values.each_with_index do |value, i|
370
- nlattr = Core::NlAttr.new(0, i + 1)
371
- encoder.measure(Endian::Host::U16) do
372
- nlattr.encode(encoder)
373
- @sub_type.encode(encoder, value)
374
- end
375
- encoder.align_to(Core::NLA_ALIGNTO)
376
- end
377
- end
378
-
379
- def decode(decoder)
380
- result = []
381
- while decoder.available?
382
- nlattr = Core::NlAttr.decode(decoder)
383
- element = decoder.limit(nlattr.len - Core::NLA_HDRLEN) do
384
- @sub_type.decode(decoder)
385
- end
386
- decoder.align_to(Core::NLA_ALIGNTO)
387
- result << element
388
- end
389
- result
390
- end
391
- end
392
- end
393
- end
394
- end
395
- end