|
1 | 1 | package asyncstreams |
2 | 2 |
|
| 3 | +import scala.annotation.unchecked.{uncheckedVariance => uV} |
3 | 4 | import scala.collection.generic.CanBuildFrom |
4 | | -import scala.annotation.unchecked.{ uncheckedVariance => uV } |
5 | 5 | import scala.concurrent.{ExecutionContext, Future} |
6 | 6 | import scala.language.higherKinds |
7 | 7 | import scalaz.std.scalaFuture._ |
8 | | -import scalaz.syntax.std.option._ |
9 | 8 | import scalaz.syntax.monad._ |
10 | | -import scalaz.OptionT.{optionT => opT} |
11 | 9 |
|
12 | | -case class AsyncStream[A](data: Future[Chunk[A, AsyncStream[A]]]) { |
| 10 | +case class AsyncStream[A](data: Future[Pair[A, AsyncStream[A]]]) { |
13 | 11 | import AsyncStream._ |
14 | 12 |
|
15 | 13 | def foldLeft[B](start: B)(f: (B, A) => B)(implicit executor: ExecutionContext): Future[B] = { |
16 | | - def impl(d: Future[Chunk[A, AsyncStream[A]]], acc: Future[B]): Future[B] = |
17 | | - d.flatMap(chunk => chunk.map(p => impl(p.second.data, acc map (b => f(b, p.first)))).getOrElse(acc)) |
| 14 | + def impl(d: Future[Pair[A, AsyncStream[A]]], acc: Future[B]): Future[B] = |
| 15 | + d.flatMap { |
| 16 | + case null => acc |
| 17 | + case pair => impl(pair.second.data, acc map (b => f(b, pair.first))) |
| 18 | + } |
18 | 19 |
|
19 | 20 | impl(data, Future(start)) |
20 | 21 | } |
21 | 22 |
|
22 | 23 | def to[Col[_]](implicit executor: ExecutionContext, cbf: CanBuildFrom[Nothing, A, Col[A @uV]]): Future[Col[A]] = |
23 | 24 | foldLeft(cbf())((col, el) => col += el).map(_.result()) |
24 | 25 |
|
| 26 | + |
25 | 27 | def takeWhile(p: A => Boolean)(implicit executor: ExecutionContext): AsyncStream[A] = |
26 | 28 | new AsyncStream[A](data map { |
27 | | - case None => None |
28 | | - case Some(pair) if !p(pair.first) => None |
29 | | - case Some(pair) => Some(Pair(pair.first, pair.second.takeWhile(p))) |
| 29 | + case null => END |
| 30 | + case pair if !p(pair.first) => END |
| 31 | + case pair => Pair(pair.first, pair.second.takeWhile(p)) |
30 | 32 | }) |
31 | 33 |
|
| 34 | + |
32 | 35 | def take(n: Int)(implicit executor: ExecutionContext): AsyncStream[A] = |
33 | 36 | if (n <= 0) nil |
34 | | - else AsyncStream(opT(data).map(p => Pair(p.first, p.second.take(n - 1))).run) |
| 37 | + else AsyncStream(data.map { |
| 38 | + case null => END |
| 39 | + case p => Pair(p.first, p.second.take(n - 1)) |
| 40 | + }) |
35 | 41 | } |
36 | 42 |
|
| 43 | + |
37 | 44 | object AsyncStream { |
38 | | - def nil[A](implicit executor: ExecutionContext): AsyncStream[A] = AsyncStream(None.point[Future]) |
| 45 | + def nil[A](implicit executor: ExecutionContext): AsyncStream[A] = AsyncStream(ENDF) |
39 | 46 | def single[A](item: A)(implicit executor: ExecutionContext): AsyncStream[A] = |
40 | | - AsyncStream(Pair(item, nil[A]).some.point[Future]) |
| 47 | + AsyncStream(Pair(item, nil[A]).point[Future]) |
41 | 48 |
|
42 | | - def generate[S, A](start: S)(gen: S => Future[Option[(S, A)]])(implicit executor: ExecutionContext): AsyncStream[A] = |
43 | | - AsyncStream(opT(gen(start)).map(p => Pair(p._2, generate(p._1)(gen))).run) |
| 49 | + def generate[S, A](start: S)(gen: S => Future[(A, S)])(implicit executor: ExecutionContext): AsyncStream[A] = |
| 50 | + AsyncStream(gen(start).map { |
| 51 | + case null => END |
| 52 | + case (el, rest) => Pair(el, generate(rest)(gen)) |
| 53 | + }) |
44 | 54 |
|
45 | 55 | def concat[A](s1: AsyncStream[A], s2: AsyncStream[A])(implicit executor: ExecutionContext): AsyncStream[A] = |
46 | 56 | new AsyncStream[A](s1.data.flatMap { |
47 | | - case None => s2.data |
48 | | - case Some(p) => Pair(p.first, concat(p.second, s2)).some.point[Future] |
| 57 | + case null => s2.data |
| 58 | + case p => Pair(p.first, concat(p.second, s2)).point[Future] |
49 | 59 | }) |
50 | 60 | } |
| 61 | + |
0 commit comments