io-stream 0.7.0 → 0.8.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c48d464c539d56862e04437f88dee2997e4393951efca83cf622a23bac9e4b75
4
- data.tar.gz: 610277102a9233e5d470daabd4f12917d429dc6a141cf52897ff95af3a06de95
3
+ metadata.gz: 5f73e60fdaf4001c88fcfaa4ccb29bfc8ee90d2fc3ffc81408c8673b414038ae
4
+ data.tar.gz: 933183cda89e7d555239ba15a752dadccc938628d6197675b3bedb8cfeb60f43
5
5
  SHA512:
6
- metadata.gz: 5761c359f16364169757dca90c4f41bfb87269ab3219b6a565b0081aafb3146f2ff6b11e77a95bebd478b31cbc702752e486c484666536f286e4ccdb4a2c6520
7
- data.tar.gz: 6e44c1ce99d3741c6c9e8f65976f5664d287586e5a704749466a70992dcfcf5bac55ab84e1429cc5a22417af889ee7938af55ec63081309b3522629a9e05721b
6
+ metadata.gz: 732318c46b27af3ecabb0c99361b60de5ae3c2733013261ae3089fbaa0f4f2f542e70ee10c410227262a8d137a59d5f1e36ba9419307e801fefd0cfebb412ce5
7
+ data.tar.gz: 5ae80afa0d558011183648ce9d34c02dc52e2b8f0cf24bde53a319d1cba3dd188fa8705a477baa8c7fcd5afeb6ee487087e72c1a75d39c80566ea9c378d4e7b1
checksums.yaml.gz.sig CHANGED
Binary file
@@ -106,23 +106,26 @@ module IO::Stream
106
106
  end
107
107
  end
108
108
 
109
- def syswrite(buffer)
110
- # This fails due to re-entrancy issues with a concurrent call to `sysclose`.
111
- # return @io.write(buffer)
112
-
113
- while true
114
- result = @io.write_nonblock(buffer, exception: false)
115
-
116
- case result
117
- when :wait_readable
118
- @io.wait_readable(@io.timeout) or raise ::IO::TimeoutError, "read timeout"
119
- when :wait_writable
120
- @io.wait_writable(@io.timeout) or raise ::IO::TimeoutError, "write timeout"
121
- else
122
- if result == buffer.bytesize
123
- return
109
+ if RUBY_VERSION >= "3.3"
110
+ def syswrite(buffer)
111
+ return @io.write(buffer)
112
+ end
113
+ else
114
+ def syswrite(buffer)
115
+ while true
116
+ result = @io.write_nonblock(buffer, exception: false)
117
+
118
+ case result
119
+ when :wait_readable
120
+ @io.wait_readable(@io.timeout) or raise ::IO::TimeoutError, "read timeout"
121
+ when :wait_writable
122
+ @io.wait_writable(@io.timeout) or raise ::IO::TimeoutError, "write timeout"
124
123
  else
125
- buffer = buffer.byteslice(result, buffer.bytesize)
124
+ if result == buffer.bytesize
125
+ return
126
+ else
127
+ buffer = buffer.byteslice(result, buffer.bytesize)
128
+ end
126
129
  end
127
130
  end
128
131
  end
@@ -35,7 +35,7 @@ module IO::Stream
35
35
  return if closed?
36
36
 
37
37
  begin
38
- flush
38
+ self.flush
39
39
  rescue
40
40
  # We really can't do anything here unless we want #close to raise exceptions.
41
41
  ensure
@@ -116,17 +116,28 @@ module IO::Stream
116
116
  # @parameter offset [Integer] The offset to start searching from.
117
117
  # @parameter limit [Integer | Nil] The maximum number of bytes to read while searching.
118
118
  # @returns [Integer | Nil] The index of the pattern, or nil if not found.
119
- private def index_of(pattern, offset, limit)
119
+ private def index_of(pattern, offset, limit, discard = false)
120
120
  # We don't want to split on the pattern, so we subtract the size of the pattern.
121
121
  split_offset = pattern.bytesize - 1
122
-
122
+
123
123
  until index = @read_buffer.index(pattern, offset)
124
124
  offset = @read_buffer.bytesize - split_offset
125
125
 
126
126
  offset = 0 if offset < 0
127
127
 
128
- return nil if limit and offset >= limit
129
- return nil unless fill_read_buffer
128
+ if limit and offset >= limit
129
+ return nil
130
+ end
131
+
132
+ unless fill_read_buffer
133
+ return nil
134
+ end
135
+
136
+ if discard
137
+ # If we are discarding, we should consume the read buffer up to the offset:
138
+ consume_read_buffer(offset)
139
+ offset = 0
140
+ end
130
141
  end
131
142
 
132
143
  return index
@@ -136,7 +147,8 @@ module IO::Stream
136
147
  # @parameter pattern [String] The pattern to match.
137
148
  # @parameter offset [Integer] The offset to start searching from.
138
149
  # @parameter limit [Integer] The maximum number of bytes to read, including the pattern (even if chomped).
139
- # @returns [String | Nil] The contents of the stream up until the pattern, which is consumed but not returned.
150
+ # @parameter chomp [Boolean] Whether to remove the pattern from the returned data.
151
+ # @returns [String | Nil] The contents of the stream up until the pattern, or nil if the pattern was not found.
140
152
  def read_until(pattern, offset = 0, limit: nil, chomp: true)
141
153
  if index = index_of(pattern, offset, limit)
142
154
  return nil if limit and index >= limit
@@ -149,6 +161,28 @@ module IO::Stream
149
161
  end
150
162
  end
151
163
 
164
+ # Efficiently discard data from the stream until encountering pattern.
165
+ # @parameter pattern [String] The pattern to match.
166
+ # @parameter offset [Integer] The offset to start searching from.
167
+ # @parameter limit [Integer] The maximum number of bytes to read, including the pattern.
168
+ # @returns [String | Nil] The contents of the stream up until the pattern, or nil if the pattern was not found.
169
+ def discard_until(pattern, offset = 0, limit: nil)
170
+ if index = index_of(pattern, offset, limit, true)
171
+ @read_buffer.freeze
172
+
173
+ if limit and index >= limit
174
+ @read_buffer = @read_buffer.byteslice(limit, @read_buffer.bytesize)
175
+
176
+ return nil
177
+ end
178
+
179
+ matched = @read_buffer.byteslice(0, index+pattern.bytesize)
180
+ @read_buffer = @read_buffer.byteslice(index+pattern.bytesize, @read_buffer.bytesize)
181
+
182
+ return matched
183
+ end
184
+ end
185
+
152
186
  # Peek at data in the buffer without consuming it.
153
187
  # @parameter size [Integer | Nil] The number of bytes to peek at. If nil, peek at all available data.
154
188
  # @returns [String] The data in the buffer without consuming it.
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2023-2024, by Samuel Williams.
5
5
 
6
6
  module IO::Stream
7
- VERSION = "0.7.0"
7
+ VERSION = "0.8.0"
8
8
  end
data/readme.md CHANGED
@@ -12,6 +12,11 @@ Please see the [project documentation](https://socketry.github.io/io-stream) for
12
12
 
13
13
  Please see the [project releases](https://socketry.github.io/io-streamreleases/index) for all releases.
14
14
 
15
+ ### v0.8.0
16
+
17
+ - On Ruby v3.3+, use `IO#write` directly instead of `IO#write_nonblock`, for better performance.
18
+ - Introduce support for `Readable#discard_until` method to discard data until a specific pattern is found.
19
+
15
20
  ### v0.7.0
16
21
 
17
22
  - Split stream functionality into separate `Readable` and `Writable` modules for better modularity and composition.
@@ -57,11 +62,6 @@ Please see the [project releases](https://socketry.github.io/io-streamreleases/i
57
62
 
58
63
  - Add support for timeouts with compatibility shims for various IO types.
59
64
 
60
- ### v0.2.0
61
-
62
- - Prefer `write_nonblock` in `syswrite` implementation for better non-blocking behavior.
63
- - Add test cases for crash scenarios.
64
-
65
65
  ## See Also
66
66
 
67
67
  - [async-io](https://github.com/socketry/async-io) — Where this implementation originally came from.
data/releases.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Releases
2
2
 
3
+ ## v0.8.0
4
+
5
+ - On Ruby v3.3+, use `IO#write` directly instead of `IO#write_nonblock`, for better performance.
6
+ - Introduce support for `Readable#discard_until` method to discard data until a specific pattern is found.
7
+
3
8
  ## v0.7.0
4
9
 
5
10
  - Split stream functionality into separate `Readable` and `Writable` modules for better modularity and composition.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: io-stream
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
metadata.gz.sig CHANGED
Binary file