Skip to content

Commit 5369f24

Browse files
author
José Valim
committed
Ensure Stream.resource/3 is zippable
1 parent a7dae16 commit 5369f24

File tree

2 files changed

+27
-6
lines changed

2 files changed

+27
-6
lines changed

lib/elixir/lib/stream.ex

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -822,13 +822,27 @@ defmodule Stream do
822822
"""
823823
@spec resource((() -> acc), (acc -> { element, acc } | nil), (acc -> term)) :: Enumerable.t
824824
def resource(start_fun, next_fun, after_fun) do
825-
fn acc, fun ->
826-
next_acc = start_fun.()
827-
try do
828-
do_unfold(next_acc, next_fun, acc, fun)
829-
after
825+
&do_resource(start_fun.(), next_fun, &1, &2, after_fun)
826+
end
827+
828+
defp do_resource(next_acc, next_fun, { :suspend, acc }, fun, after_fun) do
829+
{ :suspended, acc, &do_resource(next_acc, next_fun, &1, fun, after_fun) }
830+
end
831+
832+
defp do_resource(_next_acc, _next_fun, { :halt, acc }, _fun, _after_fun) do
833+
{ :halted, acc }
834+
end
835+
836+
defp do_resource(next_acc, next_fun, { :cont, acc }, fun, after_fun) do
837+
try do
838+
next_fun.(next_acc)
839+
catch
840+
kind, reason ->
830841
after_fun.(next_acc)
831-
end
842+
:erlang.raise(kind, reason, :erlang.get_stacktrace)
843+
else
844+
nil -> { :done, acc }
845+
{ v, next_acc } -> do_resource(next_acc, next_fun, fun.(v, acc), fun, after_fun)
832846
end
833847
end
834848

lib/elixir/test/elixir/stream_test.exs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,13 @@ defmodule StreamTest do
366366
assert Enum.to_list(stream) == [5, 4, 3, 2, 1]
367367
end
368368

369+
test "resource is zippable" do
370+
# File.stream! uses Stream.resource underneath
371+
stream = File.stream!(__FILE__)
372+
list = Enum.to_list(stream)
373+
assert Enum.zip(list, list) == Enum.zip(stream, stream)
374+
end
375+
369376
test "unfold only calculate values if needed" do
370377
stream = Stream.unfold(1, fn x -> if x > 0, do: {x, x-1}, else: throw(:boom) end)
371378
assert Enum.take(stream, 1) == [1]

0 commit comments

Comments
 (0)