cztop 1.0.0 → 1.1.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/coverage.yml +20 -0
- data/.github/workflows/draft_api.yml +27 -0
- data/.github/workflows/{main.yml → stable_api.yml} +6 -6
- data/.rubocop.yml +175 -0
- data/CHANGES.md +8 -1
- data/Gemfile +5 -0
- data/README.md +3 -1
- data/ci/install-libczmq +22 -0
- data/ci/install-libzmq +22 -0
- data/cztop.gemspec +3 -2
- data/lib/cztop/actor.rb +55 -26
- data/lib/cztop/authenticator.rb +18 -9
- data/lib/cztop/beacon.rb +22 -10
- data/lib/cztop/cert_store.rb +8 -2
- data/lib/cztop/certificate.rb +47 -18
- data/lib/cztop/config/comments.rb +14 -3
- data/lib/cztop/config/serialization.rb +25 -5
- data/lib/cztop/config/traversing.rb +44 -13
- data/lib/cztop/config.rb +23 -9
- data/lib/cztop/frame.rb +23 -10
- data/lib/cztop/has_ffi_delegate.rb +11 -1
- data/lib/cztop/message/frames.rb +16 -2
- data/lib/cztop/message.rb +36 -22
- data/lib/cztop/metadata.rb +35 -24
- data/lib/cztop/monitor.rb +14 -5
- data/lib/cztop/poller/aggregated.rb +31 -15
- data/lib/cztop/poller/zmq.rb +25 -22
- data/lib/cztop/poller/zpoller.rb +18 -6
- data/lib/cztop/poller.rb +43 -18
- data/lib/cztop/polymorphic_zsock_methods.rb +6 -1
- data/lib/cztop/proxy.rb +34 -19
- data/lib/cztop/send_receive_methods.rb +5 -1
- data/lib/cztop/socket/types.rb +128 -22
- data/lib/cztop/socket.rb +23 -18
- data/lib/cztop/version.rb +5 -1
- data/lib/cztop/z85/padded.rb +12 -3
- data/lib/cztop/z85/pipe.rb +40 -17
- data/lib/cztop/z85.rb +17 -6
- data/lib/cztop/zap.rb +57 -32
- data/lib/cztop/zsock_options.rb +155 -122
- data/lib/cztop.rb +2 -1
- metadata +28 -10
- data/.ruby-version +0 -1
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Methods used to traverse a {CZTop::Config} tree.
|
2
4
|
module CZTop::Config::Traversing
|
3
5
|
|
@@ -12,24 +14,25 @@ module CZTop::Config::Traversing
|
|
12
14
|
# @raise [Exception] the block's exception, in case it raises (it won't
|
13
15
|
# call the block any more after that)
|
14
16
|
def execute
|
15
|
-
raise ArgumentError,
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
raise ArgumentError, 'no block given' unless block_given?
|
18
|
+
|
19
|
+
exception = nil
|
20
|
+
block_value = nil
|
21
|
+
ret = nil
|
22
|
+
callback = CZMQ::FFI::Zconfig.fct do |zconfig, _arg, level|
|
20
23
|
begin
|
21
24
|
# NOTE: work around JRuby and Rubinius bug, where it'd keep calling
|
22
25
|
# this FFI::Function, even when the block `break`ed
|
23
26
|
if ret != -1
|
24
|
-
config
|
27
|
+
config = from_ffi_delegate(zconfig)
|
25
28
|
block_value = yield config, level
|
26
|
-
ret
|
29
|
+
ret = 0 # report success to keep zconfig_execute() going
|
27
30
|
end
|
28
|
-
rescue
|
31
|
+
rescue StandardError
|
29
32
|
# remember exception, so we can raise it later to the ruby code
|
30
33
|
# (it can't be raised now, as we have to report failure to
|
31
34
|
# zconfig_execute())
|
32
|
-
exception =
|
35
|
+
exception = $ERROR_INFO
|
33
36
|
|
34
37
|
ret = -1 # report failure to stop zconfig_execute() immediately
|
35
38
|
ensure
|
@@ -39,15 +42,18 @@ module CZTop::Config::Traversing
|
|
39
42
|
end
|
40
43
|
ffi_delegate.execute(callback, _arg = nil)
|
41
44
|
raise exception if exception
|
42
|
-
|
45
|
+
|
46
|
+
block_value
|
43
47
|
end
|
44
48
|
|
49
|
+
|
45
50
|
# Access to this config item's direct children.
|
46
51
|
# @return [ChildrenAccessor]
|
47
52
|
def children
|
48
53
|
ChildrenAccessor.new(self)
|
49
54
|
end
|
50
55
|
|
56
|
+
|
51
57
|
# Access to this config item's siblings.
|
52
58
|
# @note Only the "younger" (later in the ZPL file) config items are
|
53
59
|
# considered.
|
@@ -56,9 +62,11 @@ module CZTop::Config::Traversing
|
|
56
62
|
SiblingsAccessor.new(self)
|
57
63
|
end
|
58
64
|
|
65
|
+
|
59
66
|
# Used to give access to a {Config} item's children or siblings.
|
60
67
|
# @abstract
|
61
68
|
class FamilyAccessor
|
69
|
+
|
62
70
|
include Enumerable
|
63
71
|
|
64
72
|
# @param config [Config] the relative starting point (either parent or
|
@@ -67,25 +75,30 @@ module CZTop::Config::Traversing
|
|
67
75
|
@config = config
|
68
76
|
end
|
69
77
|
|
78
|
+
|
70
79
|
# This is supposed to return the first relevant config item.
|
71
80
|
# @abstract
|
72
81
|
# @return [Config, nil]
|
73
82
|
def first; end
|
74
83
|
|
84
|
+
|
75
85
|
# Yields all direct children/younger siblings. Starts with {#first}, if
|
76
86
|
# set.
|
77
87
|
# @yieldparam config [Config]
|
78
88
|
def each
|
79
|
-
current = first
|
89
|
+
current = first
|
80
90
|
return if current.nil?
|
91
|
+
|
81
92
|
yield current
|
82
|
-
current_delegate
|
93
|
+
current_delegate = current.ffi_delegate
|
83
94
|
while current_delegate = current_delegate.next
|
84
95
|
break if current_delegate.null?
|
96
|
+
|
85
97
|
yield CZTop::Config.from_ffi_delegate(current_delegate)
|
86
98
|
end
|
87
99
|
end
|
88
100
|
|
101
|
+
|
89
102
|
# Recursively compares these config items with the ones of the other.
|
90
103
|
# @param other [FamilyAccessor]
|
91
104
|
def ==(other)
|
@@ -94,30 +107,39 @@ module CZTop::Config::Traversing
|
|
94
107
|
these.size == those.size && these.zip(those) do |this, that|
|
95
108
|
this.tree_equal?(that) or return false
|
96
109
|
end
|
97
|
-
|
110
|
+
true
|
98
111
|
end
|
112
|
+
|
99
113
|
end
|
100
114
|
|
115
|
+
|
101
116
|
# Accesses the younger siblings of a given {Config} item.
|
102
117
|
class SiblingsAccessor < FamilyAccessor
|
118
|
+
|
103
119
|
# Returns the first sibling.
|
104
120
|
# @return [Config]
|
105
121
|
# @return [nil] if no younger siblings
|
106
122
|
def first
|
107
123
|
ptr = @config.ffi_delegate.next
|
108
124
|
return nil if ptr.null?
|
125
|
+
|
109
126
|
CZTop::Config.from_ffi_delegate(ptr)
|
110
127
|
end
|
128
|
+
|
111
129
|
end
|
112
130
|
|
131
|
+
|
113
132
|
# Accesses the direct children of a given {Config} item.
|
114
133
|
class ChildrenAccessor < FamilyAccessor
|
134
|
+
|
115
135
|
def first
|
116
136
|
ptr = @config.ffi_delegate.child
|
117
137
|
return nil if ptr.null?
|
138
|
+
|
118
139
|
CZTop::Config.from_ffi_delegate(ptr)
|
119
140
|
end
|
120
141
|
|
142
|
+
|
121
143
|
# Adds a new Config item and yields it, so it can be configured in
|
122
144
|
# a block.
|
123
145
|
# @param name [String] name for new config item
|
@@ -129,8 +151,10 @@ module CZTop::Config::Traversing
|
|
129
151
|
yield config if block_given?
|
130
152
|
config
|
131
153
|
end
|
154
|
+
|
132
155
|
end
|
133
156
|
|
157
|
+
|
134
158
|
# Finds a config item along a path, relative to the current item.
|
135
159
|
# @param path [String] path (leading slash is optional and will be
|
136
160
|
# ignored)
|
@@ -139,19 +163,26 @@ module CZTop::Config::Traversing
|
|
139
163
|
def locate(path)
|
140
164
|
ptr = ffi_delegate.locate(path)
|
141
165
|
return nil if ptr.null?
|
166
|
+
|
142
167
|
from_ffi_delegate(ptr)
|
143
168
|
end
|
144
169
|
|
170
|
+
|
145
171
|
# Finds last item at given level (0 = root).
|
146
172
|
# @return [Config] the last config item at given level
|
147
173
|
# @return [nil] if there's no config item at given level
|
148
174
|
def last_at_depth(level)
|
149
175
|
ptr = ffi_delegate.at_depth(level)
|
150
176
|
return nil if ptr.null?
|
177
|
+
|
151
178
|
from_ffi_delegate(ptr)
|
152
179
|
end
|
180
|
+
|
153
181
|
end
|
154
182
|
|
183
|
+
|
155
184
|
class CZTop::Config
|
185
|
+
|
156
186
|
include Traversing
|
187
|
+
|
157
188
|
end
|
data/lib/cztop/config.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module CZTop
|
3
4
|
# Represents a CZMQ::FFI::Zconfig item.
|
4
5
|
# @see http://rfc.zeromq.org/spec:4/ZPL
|
5
6
|
class Config
|
7
|
+
|
6
8
|
include HasFFIDelegate
|
7
9
|
extend CZTop::HasFFIDelegate::ClassMethods
|
8
10
|
|
11
|
+
|
9
12
|
# Initializes a new {Config} item. Takes an optional block to initialize
|
10
13
|
# the item further.
|
11
14
|
# @param name [String] config item name
|
@@ -17,7 +20,7 @@ module CZTop
|
|
17
20
|
# {Config} object is garbage collected).
|
18
21
|
def initialize(name = nil, value = nil, parent: nil)
|
19
22
|
if parent
|
20
|
-
parent
|
23
|
+
parent = parent.ffi_delegate if parent.is_a?(Config)
|
21
24
|
delegate = ::CZMQ::FFI::Zconfig.new(name, parent)
|
22
25
|
attach_ffi_delegate(delegate)
|
23
26
|
|
@@ -42,9 +45,11 @@ module CZTop
|
|
42
45
|
def name
|
43
46
|
ptr = ffi_delegate.name
|
44
47
|
return nil if ptr.null? # NOTE: for unnamed elements
|
48
|
+
|
45
49
|
ptr.read_string
|
46
50
|
end
|
47
51
|
|
52
|
+
|
48
53
|
# Sets a new name.
|
49
54
|
# @param new_name [String, #to_s]
|
50
55
|
# @return [new_name]
|
@@ -52,28 +57,33 @@ module CZTop
|
|
52
57
|
ffi_delegate.set_name(new_name.to_s)
|
53
58
|
end
|
54
59
|
|
60
|
+
|
55
61
|
# Get the value of the config item.
|
56
62
|
# @return [String]
|
57
63
|
# @note This returns an empty string if the value is unset.
|
58
64
|
def value
|
59
65
|
ptr = ffi_delegate.value
|
60
|
-
return
|
66
|
+
return '' if ptr.null? # NOTE: for root elements
|
67
|
+
|
61
68
|
ptr.read_string
|
62
69
|
end
|
63
70
|
|
71
|
+
|
64
72
|
# Set or update the value of the config item.
|
65
73
|
# @param new_value [String, #to_s]
|
66
74
|
# @return [new_value]
|
67
75
|
def value=(new_value)
|
68
|
-
ffi_delegate.set_value(
|
76
|
+
ffi_delegate.set_value('%s', :string, new_value.to_s)
|
69
77
|
end
|
70
78
|
|
79
|
+
|
71
80
|
# Inspects this {Config} item.
|
72
81
|
# @return [String] shows class, name, and value
|
73
82
|
def inspect
|
74
83
|
"#<#{self.class.name}: name=#{name.inspect} value=#{value.inspect}>"
|
75
84
|
end
|
76
85
|
|
86
|
+
|
77
87
|
# Update the value of a config item by path.
|
78
88
|
# @param path [String, #to_s] path to config item
|
79
89
|
# @param value [String, #to_s] path to config item
|
@@ -81,7 +91,7 @@ module CZTop
|
|
81
91
|
def []=(path, value)
|
82
92
|
ffi_delegate.put(path.to_s, value.to_s)
|
83
93
|
end
|
84
|
-
|
94
|
+
alias put []=
|
85
95
|
|
86
96
|
# Get the value of the current config item.
|
87
97
|
# @param path [String, #to_s] path to config item
|
@@ -92,30 +102,34 @@ module CZTop
|
|
92
102
|
# @note The default value is not returned when the config item exists but
|
93
103
|
# just doesn't have a value. In that case, it'll return the empty
|
94
104
|
# string.
|
95
|
-
def [](path, default =
|
105
|
+
def [](path, default = '')
|
96
106
|
ptr = ffi_delegate.get(path, default)
|
97
107
|
return nil if ptr.null?
|
108
|
+
|
98
109
|
ptr.read_string
|
99
110
|
end
|
100
|
-
|
111
|
+
alias get []
|
101
112
|
|
102
113
|
# @!endgroup
|
103
114
|
|
115
|
+
|
104
116
|
# Compares this config item to another. Only the name and value are
|
105
117
|
# considered. If you need to compare a config tree, use {#tree_equal?}.
|
106
118
|
# @param other [Config] the other config item
|
107
119
|
# @return [Boolean] whether they're equal
|
108
120
|
def ==(other)
|
109
121
|
name == other.name &&
|
110
|
-
|
122
|
+
value == other.value
|
111
123
|
end
|
112
124
|
|
125
|
+
|
113
126
|
# Compares this config tree to another tree or subtree. Names, values, and
|
114
127
|
# children are considered.
|
115
128
|
# @param other [Config] the other config tree
|
116
129
|
# @return [Boolean] whether they're equal
|
117
130
|
def tree_equal?(other)
|
118
|
-
self == other &&
|
131
|
+
self == other && children == other.children
|
119
132
|
end
|
133
|
+
|
120
134
|
end
|
121
135
|
end
|
data/lib/cztop/frame.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CZTop
|
2
4
|
# Represents a CZMQ::FFI::Zframe, a part of a message.
|
3
5
|
#
|
@@ -8,6 +10,7 @@ module CZTop
|
|
8
10
|
#
|
9
11
|
# @see http://api.zeromq.org/czmq3-0:zframe
|
10
12
|
class Frame
|
13
|
+
|
11
14
|
include HasFFIDelegate
|
12
15
|
extend CZTop::HasFFIDelegate::ClassMethods
|
13
16
|
|
@@ -18,8 +21,8 @@ module CZTop
|
|
18
21
|
self.content = content if content
|
19
22
|
end
|
20
23
|
|
21
|
-
FLAG_MORE
|
22
|
-
FLAG_REUSE
|
24
|
+
FLAG_MORE = 1
|
25
|
+
FLAG_REUSE = 2
|
23
26
|
FLAG_DONTWAIT = 4
|
24
27
|
|
25
28
|
# Send {Message} to a {Socket}/{Actor}.
|
@@ -39,14 +42,14 @@ module CZTop
|
|
39
42
|
# @raise [SystemCallError] if there was some error. In that case, the
|
40
43
|
# native counterpart still exists and this {Frame} can be reused.
|
41
44
|
def send_to(destination, more: false, reuse: false, dontwait: false)
|
42
|
-
flags
|
45
|
+
flags = 0
|
43
46
|
flags |= FLAG_MORE if more
|
44
47
|
flags |= FLAG_REUSE if reuse
|
45
48
|
flags |= FLAG_DONTWAIT if dontwait
|
46
49
|
|
47
50
|
# remember pointer, in case the zframe_t won't be destroyed
|
48
51
|
zframe_ptr = ffi_delegate.to_ptr
|
49
|
-
ret
|
52
|
+
ret = CZMQ::FFI::Zframe.send(ffi_delegate, destination, flags)
|
50
53
|
|
51
54
|
if reuse || ret == -1
|
52
55
|
# zframe_t hasn't been destroyed yet: avoid memory leak.
|
@@ -55,14 +58,13 @@ module CZTop
|
|
55
58
|
end
|
56
59
|
|
57
60
|
if ret == -1
|
58
|
-
if dontwait && FFI.errno == Errno::EAGAIN::Errno
|
59
|
-
raise IO::EAGAINWaitWritable
|
60
|
-
end
|
61
|
+
raise IO::EAGAINWaitWritable if dontwait && FFI.errno == Errno::EAGAIN::Errno
|
61
62
|
|
62
63
|
raise_zmq_err
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
67
|
+
|
66
68
|
# Receive {Frame} from a {Socket}/{Actor}.
|
67
69
|
# @note This is low-level. Consider just receiving a {Message}.
|
68
70
|
# @return [Frame]
|
@@ -70,18 +72,20 @@ module CZTop
|
|
70
72
|
from_ffi_delegate(CZMQ::FFI::Zframe.recv(source))
|
71
73
|
end
|
72
74
|
|
75
|
+
|
73
76
|
# @note This string is always binary. Use String#force_encoding if needed.
|
74
77
|
# @return [String] content as string (encoding = Encoding::BINARY)
|
75
78
|
def content
|
76
79
|
ffi_delegate.data.read_string(size)
|
77
80
|
end
|
78
|
-
|
81
|
+
alias to_s content
|
79
82
|
|
80
83
|
# @return [Boolean] if this {Frame} has zero-sized content
|
81
84
|
def empty?
|
82
85
|
size.zero?
|
83
86
|
end
|
84
87
|
|
88
|
+
|
85
89
|
# Sets new content of this {Frame}.
|
86
90
|
# @param new_content [String]
|
87
91
|
# @return [new_content]
|
@@ -92,12 +96,14 @@ module CZTop
|
|
92
96
|
# NOTE: FFI::MemoryPointer will autorelease
|
93
97
|
end
|
94
98
|
|
99
|
+
|
95
100
|
# Duplicates a frame.
|
96
101
|
# @return [Frame] new frame with same content
|
97
102
|
def dup
|
98
103
|
from_ffi_delegate(ffi_delegate.dup)
|
99
104
|
end
|
100
105
|
|
106
|
+
|
101
107
|
# @return [Boolean] if the MORE indicator is set
|
102
108
|
# @note This happens when reading a frame from a {Socket} or using
|
103
109
|
# {#more=}.
|
@@ -105,6 +111,7 @@ module CZTop
|
|
105
111
|
ffi_delegate.more == 1
|
106
112
|
end
|
107
113
|
|
114
|
+
|
108
115
|
# Sets the MORE indicator.
|
109
116
|
# @param indicator [Boolean]
|
110
117
|
# @note This is NOT used when sending frame to socket.
|
@@ -114,6 +121,7 @@ module CZTop
|
|
114
121
|
ffi_delegate.set_more(indicator ? 1 : 0)
|
115
122
|
end
|
116
123
|
|
124
|
+
|
117
125
|
# Compare to another frame.
|
118
126
|
# @param other [Frame]
|
119
127
|
# @return [Boolean] if this and the other frame have identical size and
|
@@ -151,10 +159,12 @@ module CZTop
|
|
151
159
|
def routing_id=(new_routing_id)
|
152
160
|
# need to raise manually, as FFI lacks this feature.
|
153
161
|
# @see https://github.com/ffi/ffi/issues/473
|
154
|
-
raise RangeError if new_routing_id
|
162
|
+
raise RangeError if new_routing_id.negative?
|
163
|
+
|
155
164
|
ffi_delegate.set_routing_id(new_routing_id)
|
156
165
|
end
|
157
166
|
|
167
|
+
|
158
168
|
# Gets the group (radio/dish pattern).
|
159
169
|
# @note This is only set when the frame has been read from
|
160
170
|
# a {CZTop::Socket::DISH} socket.
|
@@ -163,9 +173,11 @@ module CZTop
|
|
163
173
|
def group
|
164
174
|
group = ffi_delegate.group
|
165
175
|
return nil if group.nil? || group.empty?
|
176
|
+
|
166
177
|
group
|
167
178
|
end
|
168
179
|
|
180
|
+
|
169
181
|
# Sets a new group (radio/dish pattern).
|
170
182
|
# @note This is used when the frame is sent via a {CZTop::Socket::RADIO}
|
171
183
|
# socket.
|
@@ -174,7 +186,8 @@ module CZTop
|
|
174
186
|
# @return [new_group]
|
175
187
|
def group=(new_group)
|
176
188
|
rc = ffi_delegate.set_group(new_group)
|
177
|
-
raise_zmq_err(
|
189
|
+
raise_zmq_err(format('unable to set group to %p', new_group)) if rc == -1
|
178
190
|
end
|
191
|
+
|
179
192
|
end
|
180
193
|
end
|
@@ -1,9 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'forwardable'
|
2
4
|
require 'socket' # for SocketError
|
3
5
|
|
4
6
|
# This module is used to attach the low-level objects of classes within the
|
5
7
|
# CZMQ::FFI namespace (coming from the _czmq-ffi-gen_ gem) as delegates.
|
6
8
|
module CZTop::HasFFIDelegate
|
9
|
+
|
7
10
|
# @return [CZMQ::FFI::*] the attached delegate
|
8
11
|
attr_reader :ffi_delegate
|
9
12
|
|
@@ -12,6 +15,7 @@ module CZTop::HasFFIDelegate
|
|
12
15
|
@ffi_delegate.to_ptr
|
13
16
|
end
|
14
17
|
|
18
|
+
|
15
19
|
# Attaches an FFI delegate to the current (probably new) {CZTop} object.
|
16
20
|
# @param ffi_delegate an instance of the corresponding class in the
|
17
21
|
# CZMQ::FFI namespace
|
@@ -27,6 +31,7 @@ module CZTop::HasFFIDelegate
|
|
27
31
|
@ffi_delegate = ffi_delegate
|
28
32
|
end
|
29
33
|
|
34
|
+
|
30
35
|
# Same as the counterpart in {ClassMethods}, but usable from within an
|
31
36
|
# instance.
|
32
37
|
# @see CZTop::FFIDelegate::ClassMethods#from_ffi_delegate
|
@@ -60,8 +65,10 @@ module CZTop::HasFFIDelegate
|
|
60
65
|
end
|
61
66
|
end
|
62
67
|
|
68
|
+
|
63
69
|
# Some class methods related to FFI delegates.
|
64
70
|
module ClassMethods
|
71
|
+
|
65
72
|
include Forwardable
|
66
73
|
|
67
74
|
# Delegate specified instance method to the registered FFI delegate.
|
@@ -73,6 +80,7 @@ module CZTop::HasFFIDelegate
|
|
73
80
|
def_delegator(:@ffi_delegate, method)
|
74
81
|
end
|
75
82
|
|
83
|
+
|
76
84
|
# Allocates a new instance and attaches the FFI delegate to it. This is
|
77
85
|
# useful if you already have an FFI delegate and need to attach it to a
|
78
86
|
# fresh high-level object.
|
@@ -84,7 +92,9 @@ module CZTop::HasFFIDelegate
|
|
84
92
|
def from_ffi_delegate(ffi_delegate)
|
85
93
|
obj = allocate
|
86
94
|
obj.attach_ffi_delegate(ffi_delegate)
|
87
|
-
|
95
|
+
obj
|
88
96
|
end
|
97
|
+
|
89
98
|
end
|
99
|
+
|
90
100
|
end
|
data/lib/cztop/message/frames.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CZTop
|
2
4
|
class Message
|
3
5
|
|
@@ -7,14 +9,17 @@ module CZTop
|
|
7
9
|
frames.count
|
8
10
|
end
|
9
11
|
|
12
|
+
|
10
13
|
# Access to this {Message}'s {Frame}s.
|
11
14
|
# @return [FramesAccessor]
|
12
15
|
def frames
|
13
16
|
FramesAccessor.new(self)
|
14
17
|
end
|
15
18
|
|
19
|
+
|
16
20
|
# Used to access a {Message}'s {Frame}s.
|
17
21
|
class FramesAccessor
|
22
|
+
|
18
23
|
include Enumerable
|
19
24
|
|
20
25
|
# @param message [Message]
|
@@ -22,24 +27,29 @@ module CZTop
|
|
22
27
|
@message = message
|
23
28
|
end
|
24
29
|
|
30
|
+
|
25
31
|
# Returns the last frame of this message.
|
26
32
|
# @return [Frame] first frame of Message
|
27
33
|
# @return [nil] if there are no frames
|
28
34
|
def first
|
29
35
|
first = @message.ffi_delegate.first
|
30
36
|
return nil if first.null?
|
37
|
+
|
31
38
|
Frame.from_ffi_delegate(first)
|
32
39
|
end
|
33
40
|
|
41
|
+
|
34
42
|
# Returns the last frame of this message.
|
35
43
|
# @return [Frame] last {Frame} of {Message}
|
36
44
|
# @return [nil] if there are no frames
|
37
45
|
def last
|
38
46
|
last = @message.ffi_delegate.last
|
39
47
|
return nil if last.null?
|
48
|
+
|
40
49
|
Frame.from_ffi_delegate(last)
|
41
50
|
end
|
42
51
|
|
52
|
+
|
43
53
|
# Index access to a frame/frames of this message, just like with an
|
44
54
|
# array.
|
45
55
|
# @overload [](index)
|
@@ -56,6 +66,7 @@ module CZTop
|
|
56
66
|
end
|
57
67
|
end
|
58
68
|
|
69
|
+
|
59
70
|
# Yields all frames for this message to the given block.
|
60
71
|
# @note Not thread safe.
|
61
72
|
# @yieldparam frame [Frame]
|
@@ -63,12 +74,15 @@ module CZTop
|
|
63
74
|
def each
|
64
75
|
first = first()
|
65
76
|
return unless first
|
77
|
+
|
66
78
|
yield first
|
67
|
-
while frame = @message.ffi_delegate.next
|
79
|
+
while (frame = @message.ffi_delegate.next) && !frame.null?
|
68
80
|
yield Frame.from_ffi_delegate(frame)
|
69
81
|
end
|
70
|
-
|
82
|
+
self
|
71
83
|
end
|
84
|
+
|
72
85
|
end
|
86
|
+
|
73
87
|
end
|
74
88
|
end
|