fiber_stream 0.1.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.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +25 -0
  3. data/LICENSE +19 -0
  4. data/README.md +361 -0
  5. data/examples/README.md +51 -0
  6. data/examples/async_http_requests.rb +132 -0
  7. data/examples/background_execution.rb +31 -0
  8. data/examples/backpressure_buffer.rb +66 -0
  9. data/examples/basic_pipeline.rb +28 -0
  10. data/examples/composable_pipeline.rb +43 -0
  11. data/examples/file_copy.rb +33 -0
  12. data/examples/line_processing.rb +20 -0
  13. data/examples/ractor_map_hashing.rb +43 -0
  14. data/examples/ractor_port_source.rb +45 -0
  15. data/lib/fiber_stream/errors.rb +44 -0
  16. data/lib/fiber_stream/flow.rb +190 -0
  17. data/lib/fiber_stream/pipeline.rb +49 -0
  18. data/lib/fiber_stream/pull/async_boundary.rb +85 -0
  19. data/lib/fiber_stream/pull/buffer_boundary.rb +123 -0
  20. data/lib/fiber_stream/pull/each.rb +31 -0
  21. data/lib/fiber_stream/pull/io_source.rb +89 -0
  22. data/lib/fiber_stream/pull/lines.rb +121 -0
  23. data/lib/fiber_stream/pull/map.rb +37 -0
  24. data/lib/fiber_stream/pull/parallel_map_boundary.rb +299 -0
  25. data/lib/fiber_stream/pull/ractor_map_boundary.rb +500 -0
  26. data/lib/fiber_stream/pull/ractor_port_source.rb +242 -0
  27. data/lib/fiber_stream/pull/select.rb +40 -0
  28. data/lib/fiber_stream/pull/take.rb +47 -0
  29. data/lib/fiber_stream/pull.rb +85 -0
  30. data/lib/fiber_stream/ractor_port.rb +17 -0
  31. data/lib/fiber_stream/running_pipeline.rb +156 -0
  32. data/lib/fiber_stream/sink.rb +176 -0
  33. data/lib/fiber_stream/source.rb +184 -0
  34. data/lib/fiber_stream/version.rb +5 -0
  35. data/lib/fiber_stream.rb +15 -0
  36. data/sig/fiber_stream.rbs +97 -0
  37. metadata +154 -0
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FiberStream
4
+ class Sink
5
+ # Creates a sink that collects all stream elements into an Array.
6
+ #
7
+ # The sink consumes upstream until normal completion and returns the
8
+ # collected array as the stream materialized value.
9
+ def self.to_a
10
+ new do |stream|
11
+ values = []
12
+
13
+ loop do
14
+ value = stream.next
15
+ break if Pull.done?(value)
16
+
17
+ values << value
18
+ end
19
+
20
+ values
21
+ end
22
+ end
23
+
24
+ # Creates a sink that returns the first stream element.
25
+ #
26
+ # The sink pulls at most one element. It returns `nil` when upstream
27
+ # completes before producing a value.
28
+ def self.first
29
+ new do |stream|
30
+ value = stream.next
31
+ Pull.done?(value) ? nil : value
32
+ end
33
+ end
34
+
35
+ # Creates a sink that folds all stream elements into an accumulator.
36
+ #
37
+ # The sink consumes upstream until normal completion. It returns the final
38
+ # accumulator, or the initial accumulator when upstream is empty. Exceptions
39
+ # raised by the block fail the stream and are re-raised from
40
+ # `Source#run_with`. FiberStream assigns the initial accumulator directly;
41
+ # it does not duplicate or freeze that object.
42
+ def self.fold(initial, &block)
43
+ raise ArgumentError, "missing block" unless block
44
+
45
+ new do |stream|
46
+ accumulator = initial
47
+
48
+ loop do
49
+ value = stream.next
50
+ break if Pull.done?(value)
51
+
52
+ accumulator = block.call(accumulator, value)
53
+ end
54
+
55
+ accumulator
56
+ end
57
+ end
58
+
59
+ # Creates a sink that writes String chunks to an IO-like object.
60
+ #
61
+ # The sink consumes upstream until normal completion and returns the number
62
+ # of chunks successfully written. It requires a scheduler-backed
63
+ # non-blocking fiber before write, flush, or normal close operations. The IO
64
+ # object is closed only when `close: true` is passed, and flushed on normal
65
+ # completion only when `flush: true` is passed.
66
+ def self.io(io, close: false, flush: false)
67
+ raise TypeError, "io must respond to write" unless io.respond_to?(:write)
68
+ raise TypeError, "close must be true or false" unless [true, false].include?(close)
69
+ raise TypeError, "flush must be true or false" unless [true, false].include?(flush)
70
+ raise TypeError, "io must respond to close" if close && !io.respond_to?(:close)
71
+ raise TypeError, "io must respond to flush" if flush && !io.respond_to?(:flush)
72
+
73
+ new do |stream|
74
+ IOSink.new(io, close, flush).run(stream)
75
+ end
76
+ end
77
+
78
+ def initialize(&run)
79
+ @run = run
80
+ end
81
+
82
+ private_class_method :new
83
+
84
+ private
85
+
86
+ def run(stream)
87
+ @run.call(stream)
88
+ end
89
+
90
+ class IOSink
91
+ def initialize(io, close_io, flush_io)
92
+ @io = io
93
+ @close_io = close_io
94
+ @flush_io = flush_io
95
+ @chunks_written = 0
96
+ @io_closed = false
97
+ end
98
+
99
+ def run(stream)
100
+ loop do
101
+ value = stream.next
102
+ break if Pull.done?(value)
103
+
104
+ write(value)
105
+ end
106
+
107
+ finish
108
+ rescue StandardError
109
+ close_suppressing_error
110
+ raise
111
+ end
112
+
113
+ private
114
+
115
+ def write(value)
116
+ unless value.is_a?(String)
117
+ raise TypeError, "Sink.io elements must be String"
118
+ end
119
+
120
+ validate_scheduler!
121
+ @io.write(value)
122
+ @chunks_written += 1
123
+ end
124
+
125
+ def finish
126
+ flush
127
+ close_on_normal_completion
128
+ @chunks_written
129
+ end
130
+
131
+ def flush
132
+ return unless @flush_io
133
+
134
+ validate_scheduler!
135
+ @io.flush
136
+ end
137
+
138
+ def close_on_normal_completion
139
+ return unless @close_io
140
+
141
+ validate_scheduler!
142
+ close_error = close_io
143
+ raise close_error if close_error
144
+ end
145
+
146
+ def validate_scheduler!
147
+ return if Fiber.scheduler && !Fiber.current.blocking?
148
+
149
+ message =
150
+ if Fiber.scheduler
151
+ "Sink.io requires a non-blocking fiber"
152
+ else
153
+ "Sink.io requires Fiber.scheduler"
154
+ end
155
+ raise SchedulerRequiredError, message
156
+ end
157
+
158
+ def close_suppressing_error
159
+ close_io
160
+ end
161
+
162
+ def close_io
163
+ return nil unless @close_io
164
+ return nil if @io_closed
165
+
166
+ @io_closed = true
167
+ @io.close
168
+ nil
169
+ rescue StandardError => error
170
+ error
171
+ end
172
+ end
173
+
174
+ private_constant :IOSink
175
+ end
176
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FiberStream
4
+ class Source
5
+ # Creates a source definition from an Enumerable.
6
+ #
7
+ # The enumerable is not consumed until values are pulled by `run_with`. Each
8
+ # materialization creates an Enumerator with `enumerable.to_enum(:each)`;
9
+ # FiberStream does not snapshot values or guarantee replayability for
10
+ # one-shot enumerables.
11
+ def self.each(enumerable)
12
+ new(-> { Pull.each(enumerable) })
13
+ end
14
+
15
+ # Creates a source definition from an IO-like object.
16
+ #
17
+ # The IO object is not read until values are pulled by `run_with`. Each
18
+ # materialization reads from the same IO object's current position; this
19
+ # source does not snapshot, reopen, or guarantee replayability. The IO is
20
+ # closed only when `close: true` is passed.
21
+ def self.io(io, chunk_size: 16 * 1024, close: false)
22
+ raise TypeError, "io must respond to readpartial" unless io.respond_to?(:readpartial)
23
+ raise TypeError, "chunk_size must be an Integer" unless chunk_size.is_a?(Integer)
24
+ raise ArgumentError, "chunk_size must be positive" unless chunk_size.positive?
25
+ raise TypeError, "close must be true or false" unless [true, false].include?(close)
26
+ raise TypeError, "io must respond to close" if close && !io.respond_to?(:close)
27
+
28
+ new(-> { Pull.io(io, chunk_size, close) })
29
+ end
30
+
31
+ # Creates a backpressure-aware source definition from Ractor ports.
32
+ #
33
+ # `port` is the data/control port received by FiberStream. `ack_port` is a
34
+ # producer-owned port that receives `RactorPort::Ack` and
35
+ # `RactorPort::Cancel` control messages. The producer must wait for an ack
36
+ # before sending each `RactorPort::Element`, `RactorPort::Complete`, or
37
+ # `RactorPort::Failure` message.
38
+ def self.ractor_port(port, ack_port:, ack_transfer: :copy, cancel: true)
39
+ raise TypeError, "port must respond to receive" unless port.respond_to?(:receive)
40
+ unless ack_port.respond_to?(:send) && ack_port.method(:send).owner != Kernel
41
+ raise TypeError, "ack_port must provide Ractor-style send"
42
+ end
43
+
44
+ Flow.__send__(:validate_ractor_transfer_policy!, :ack_transfer, ack_transfer)
45
+ raise TypeError, "cancel must be true or false" unless [true, false].include?(cancel)
46
+
47
+ new(-> { Pull.ractor_port(port, ack_port, ack_transfer, cancel) })
48
+ end
49
+
50
+ def initialize(source_factory, flows = [])
51
+ @source_factory = source_factory
52
+ @flows = flows
53
+ end
54
+
55
+ # Returns a new source definition that passes this source through `flow`.
56
+ #
57
+ # This method is lazy. It does not run the source, enumerate values, or call
58
+ # flow blocks.
59
+ def via(flow)
60
+ raise TypeError, "expected FiberStream::Flow" unless flow.is_a?(Flow)
61
+
62
+ self.class.__send__(:new, @source_factory, @flows + [flow])
63
+ end
64
+
65
+ # Returns a new source definition that maps each element with `block`.
66
+ #
67
+ # This is a convenience wrapper around `via(FiberStream::Flow.map { ... })`
68
+ # and has the same lazy construction, error, and backpressure behavior as
69
+ # the underlying flow.
70
+ def map(&block)
71
+ via(Flow.map(&block))
72
+ end
73
+
74
+ # Returns a new source definition that maps elements concurrently.
75
+ #
76
+ # This is a convenience wrapper around
77
+ # `via(FiberStream::Flow.parallel_map(concurrency:) { ... })` and preserves
78
+ # the same ordered delivery, scheduler requirement, validation, bounded
79
+ # upstream run-ahead, and cancellation behavior.
80
+ def parallel_map(concurrency:, &block)
81
+ via(Flow.parallel_map(concurrency: concurrency, &block))
82
+ end
83
+
84
+ # Returns a new source definition that maps elements in Ractor workers.
85
+ #
86
+ # This is a convenience wrapper around
87
+ # `via(FiberStream::Flow.ractor_map(workers:) { ... })` and preserves the
88
+ # same shareable mapper requirement, ordered delivery, transfer policy,
89
+ # bounded upstream run-ahead, and cooperative worker shutdown behavior.
90
+ def ractor_map(workers:, input_transfer: :copy, output_transfer: :copy, &block)
91
+ via(
92
+ Flow.ractor_map(
93
+ workers: workers,
94
+ input_transfer: input_transfer,
95
+ output_transfer: output_transfer,
96
+ &block
97
+ )
98
+ )
99
+ end
100
+
101
+ # Returns a new source definition that keeps elements matching `block`.
102
+ #
103
+ # This is a convenience wrapper around
104
+ # `via(FiberStream::Flow.select { ... })` and has the same truthiness and
105
+ # lazy construction behavior as the underlying flow.
106
+ def select(&block)
107
+ via(Flow.select(&block))
108
+ end
109
+
110
+ # Returns a new source definition that emits at most `count` elements.
111
+ #
112
+ # This is a convenience wrapper around `via(FiberStream::Flow.take(count))`
113
+ # and preserves the same validation and upstream close behavior.
114
+ def take(count)
115
+ via(Flow.take(count))
116
+ end
117
+
118
+ # Returns a new source definition with an asynchronous boundary.
119
+ #
120
+ # This is a convenience wrapper around `via(FiberStream::Flow.async)` and
121
+ # preserves the same scheduler requirement and cancellation behavior.
122
+ def async
123
+ via(Flow.async)
124
+ end
125
+
126
+ # Returns a new source definition with a bounded asynchronous buffer.
127
+ #
128
+ # This is a convenience wrapper around
129
+ # `via(FiberStream::Flow.buffer(count))` and preserves the same validation,
130
+ # scheduler requirement, and cancellation behavior.
131
+ def buffer(count)
132
+ via(Flow.buffer(count))
133
+ end
134
+
135
+ # Returns a new source definition that splits String chunks into lines.
136
+ #
137
+ # This is a convenience wrapper around
138
+ # `via(FiberStream::Flow.lines(chomp:, max_length:))`.
139
+ def lines(chomp: true, max_length: nil)
140
+ via(Flow.lines(chomp: chomp, max_length: max_length))
141
+ end
142
+
143
+ # Returns a runnable pipeline from this source to `sink`.
144
+ #
145
+ # Construction is lazy. The source and sink are not materialized until
146
+ # `Pipeline#run` is called.
147
+ def to(sink)
148
+ raise TypeError, "expected FiberStream::Sink" unless sink.is_a?(Sink)
149
+
150
+ Pipeline.__send__(:new, self, sink)
151
+ end
152
+
153
+ # Materializes and runs this source with `sink`.
154
+ #
155
+ # The stream runs in the current fiber until completion or failure. The
156
+ # method returns the sink's materialized value and closes the materialized
157
+ # pull chain on success, failure, or early sink completion.
158
+ def run_with(sink)
159
+ raise TypeError, "expected FiberStream::Sink" unless sink.is_a?(Sink)
160
+
161
+ primary_error = nil
162
+
163
+ begin
164
+ stream = @source_factory.call
165
+ @flows.each do |flow|
166
+ stream = flow.__send__(:attach, stream)
167
+ end
168
+
169
+ sink.__send__(:run, stream)
170
+ rescue StandardError => error
171
+ primary_error = error
172
+ raise
173
+ ensure
174
+ begin
175
+ stream&.close
176
+ rescue StandardError => close_error
177
+ raise close_error unless primary_error
178
+ end
179
+ end
180
+ end
181
+
182
+ private_class_method :new
183
+ end
184
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FiberStream
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "fiber_stream/pull"
4
+ require_relative "fiber_stream/version"
5
+ require_relative "fiber_stream/errors"
6
+ require_relative "fiber_stream/ractor_port"
7
+ require_relative "fiber_stream/flow"
8
+ require_relative "fiber_stream/sink"
9
+ require_relative "fiber_stream/running_pipeline"
10
+ require_relative "fiber_stream/pipeline"
11
+ require_relative "fiber_stream/source"
12
+
13
+ module FiberStream
14
+ private_constant :Pull
15
+ end
@@ -0,0 +1,97 @@
1
+ module FiberStream
2
+ type ractor_transfer_policy = :copy | :move
3
+ type ractor_map_error_kind = :input_transfer | :output_transfer | :worker | :worker_termination | :isolation
4
+ type ractor_port_source_error_kind = :invalid_message | :producer_failure | :receive | :ack_transfer | :cancel_transfer
5
+
6
+ class SchedulerRequiredError < RuntimeError
7
+ end
8
+
9
+ class FrameTooLongError < RuntimeError
10
+ end
11
+
12
+ class PipelineCancelledError < RuntimeError
13
+ end
14
+
15
+ class RactorPortSourceError < RuntimeError
16
+ attr_reader kind: ractor_port_source_error_kind
17
+ attr_reader cause_class_name: String
18
+ attr_reader cause_message: String
19
+ end
20
+
21
+ class RactorMapError < RuntimeError
22
+ attr_reader sequence: Integer
23
+ attr_reader kind: ractor_map_error_kind
24
+ attr_reader cause_class_name: String
25
+ attr_reader cause_message: String
26
+ end
27
+
28
+ module RactorPort
29
+ class Element[Elem] < Data
30
+ attr_reader value: Elem
31
+ end
32
+
33
+ class Complete < Data
34
+ end
35
+
36
+ class Failure < Data
37
+ attr_reader cause_class_name: String
38
+ attr_reader cause_message: String
39
+ end
40
+
41
+ class Ack < Data
42
+ end
43
+
44
+ class Cancel < Data
45
+ attr_reader reason: Symbol
46
+ end
47
+ end
48
+
49
+ class Source[Elem]
50
+ def self.each: [Elem] (Enumerable[Elem] enumerable) -> Source[Elem]
51
+ def self.io: (untyped io, ?chunk_size: Integer, ?close: bool) -> Source[String]
52
+ def self.ractor_port: [Elem] (untyped port, ack_port: untyped, ?ack_transfer: ractor_transfer_policy, ?cancel: bool) -> Source[Elem]
53
+ def via: [Out] (Flow[Elem, Out] flow) -> Source[Out]
54
+ def map: [Out] () { (Elem) -> Out } -> Source[Out]
55
+ def parallel_map: [Out] (concurrency: Integer) { (Elem) -> Out } -> Source[Out]
56
+ def ractor_map: [Out] (workers: Integer, ?input_transfer: ractor_transfer_policy, ?output_transfer: ractor_transfer_policy) { (Elem) -> Out } -> Source[Out]
57
+ def select: () { (Elem) -> boolish } -> Source[Elem]
58
+ def take: (Integer count) -> Source[Elem]
59
+ def async: () -> Source[Elem]
60
+ def buffer: (Integer count) -> Source[Elem]
61
+ def lines: (?chomp: bool, ?max_length: Integer?) -> Source[String]
62
+ def to: [Mat] (Sink[Elem, Mat] sink) -> Pipeline[Mat]
63
+ def run_with: [Mat] (Sink[Elem, Mat] sink) -> Mat
64
+ end
65
+
66
+ class Flow[In, Out]
67
+ def self.map: [In, Out] () { (In) -> Out } -> Flow[In, Out]
68
+ def self.parallel_map: [In, Out] (concurrency: Integer) { (In) -> Out } -> Flow[In, Out]
69
+ def self.ractor_map: [In, Out] (workers: Integer, ?input_transfer: ractor_transfer_policy, ?output_transfer: ractor_transfer_policy) { (In) -> Out } -> Flow[In, Out]
70
+ def self.select: [Elem] () { (Elem) -> boolish } -> Flow[Elem, Elem]
71
+ def self.take: [Elem] (Integer count) -> Flow[Elem, Elem]
72
+ def self.async: [Elem] () -> Flow[Elem, Elem]
73
+ def self.buffer: [Elem] (Integer count) -> Flow[Elem, Elem]
74
+ def self.lines: (?chomp: bool, ?max_length: Integer?) -> Flow[String, String]
75
+ def via: [Next] (Flow[Out, Next] flow) -> Flow[In, Next]
76
+ def to: [Mat] (Sink[Out, Mat] sink) -> Sink[In, Mat]
77
+ end
78
+
79
+ class Sink[In, Mat]
80
+ def self.to_a: [Elem] () -> Sink[Elem, Array[Elem]]
81
+ def self.first: [Elem] () -> Sink[Elem, Elem?]
82
+ def self.fold: [Elem, Acc] (Acc initial) { (Acc, Elem) -> Acc } -> Sink[Elem, Acc]
83
+ def self.io: (untyped io, ?close: bool, ?flush: bool) -> Sink[String, Integer]
84
+ end
85
+
86
+ class Pipeline[Mat]
87
+ def run: () -> Mat
88
+ def run_async: () -> RunningPipeline[Mat]
89
+ end
90
+
91
+ class RunningPipeline[Mat]
92
+ def wait: () -> Mat
93
+ def cancel: () -> self
94
+ def done?: () -> bool
95
+ def cancel_requested?: () -> bool
96
+ end
97
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fiber_stream
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dai Akatsuka
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: async
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: minitest
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '5.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rake
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '13.0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '13.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rbs
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '3.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rubocop
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '1.0'
75
+ - - "<"
76
+ - !ruby/object:Gem::Version
77
+ version: '2.0'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '1.0'
85
+ - - "<"
86
+ - !ruby/object:Gem::Version
87
+ version: '2.0'
88
+ description: A Ruby stream processing library built around Fiber and Fiber.scheduler.
89
+ executables: []
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - CHANGELOG.md
94
+ - LICENSE
95
+ - README.md
96
+ - examples/README.md
97
+ - examples/async_http_requests.rb
98
+ - examples/background_execution.rb
99
+ - examples/backpressure_buffer.rb
100
+ - examples/basic_pipeline.rb
101
+ - examples/composable_pipeline.rb
102
+ - examples/file_copy.rb
103
+ - examples/line_processing.rb
104
+ - examples/ractor_map_hashing.rb
105
+ - examples/ractor_port_source.rb
106
+ - lib/fiber_stream.rb
107
+ - lib/fiber_stream/errors.rb
108
+ - lib/fiber_stream/flow.rb
109
+ - lib/fiber_stream/pipeline.rb
110
+ - lib/fiber_stream/pull.rb
111
+ - lib/fiber_stream/pull/async_boundary.rb
112
+ - lib/fiber_stream/pull/buffer_boundary.rb
113
+ - lib/fiber_stream/pull/each.rb
114
+ - lib/fiber_stream/pull/io_source.rb
115
+ - lib/fiber_stream/pull/lines.rb
116
+ - lib/fiber_stream/pull/map.rb
117
+ - lib/fiber_stream/pull/parallel_map_boundary.rb
118
+ - lib/fiber_stream/pull/ractor_map_boundary.rb
119
+ - lib/fiber_stream/pull/ractor_port_source.rb
120
+ - lib/fiber_stream/pull/select.rb
121
+ - lib/fiber_stream/pull/take.rb
122
+ - lib/fiber_stream/ractor_port.rb
123
+ - lib/fiber_stream/running_pipeline.rb
124
+ - lib/fiber_stream/sink.rb
125
+ - lib/fiber_stream/source.rb
126
+ - lib/fiber_stream/version.rb
127
+ - sig/fiber_stream.rbs
128
+ homepage: https://github.com/dakatsuka/fiber_stream
129
+ licenses:
130
+ - MIT
131
+ metadata:
132
+ allowed_push_host: https://rubygems.org
133
+ homepage_uri: https://github.com/dakatsuka/fiber_stream
134
+ source_code_uri: https://github.com/dakatsuka/fiber_stream/tree/v0.1.0
135
+ changelog_uri: https://github.com/dakatsuka/fiber_stream/blob/main/CHANGELOG.md
136
+ rubygems_mfa_required: 'true'
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '4.0'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubygems_version: 4.0.6
152
+ specification_version: 4
153
+ summary: Asynchronous, non-blocking stream processing with backpressure.
154
+ test_files: []