diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e6f033..68e4020 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,9 +48,22 @@ jobs: - name: Run tests run: sbt ++${{ matrix.scala }}! test + website: + runs-on: ubuntu-20.04 + timeout-minutes: 60 + steps: + - name: Checkout current branch + uses: actions/checkout@v3.1.0 + - name: Setup Scala and Java + uses: olafurpg/setup-scala@v13 + - name: Cache scala dependencies + uses: coursier/cache-action@v6 + - name: Check Document Generation + run: sbt docs/compileDocs + publish: runs-on: ubuntu-20.04 - needs: [lint, test] + needs: [lint, test, website] if: github.event_name != 'pull_request' steps: - name: Checkout current branch diff --git a/.github/workflows/site.yml b/.github/workflows/site.yml new file mode 100644 index 0000000..ccd31cf --- /dev/null +++ b/.github/workflows/site.yml @@ -0,0 +1,28 @@ +# This file was autogenerated using `zio-sbt` via `sbt generateGithubWorkflow` +# task and should be included in the git repository. Please do not edit +# it manually. + +name: website + +on: + release: + types: [ published ] + +jobs: + publish-docs: + runs-on: ubuntu-20.04 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3.1.0 + with: + fetch-depth: 0 + - name: Setup Scala and Java + uses: olafurpg/setup-scala@v13 + - uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - name: Publishing Docs to NPM Registry + run: sbt sbt/publishToNpm + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index c7738ce..8fab3c2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .sbtopts .vscode .lh +.idea metals.sbt project/.sbt project/metals.sbt diff --git a/README.md b/README.md index 3a68db6..24c9c7c 100644 --- a/README.md +++ b/README.md @@ -7,84 +7,9 @@ This library provides an interoperability layer between ZIO and reactive streams. -## Reactive Streams `Producer` and `Subscriber` +## Documentation -**ZIO** integrates with [Reactive Streams](http://reactive-streams.org) by providing conversions from `zio.stream.Stream` to `org.reactivestreams.Publisher` -and from `zio.stream.Sink` to `org.reactivestreams.Subscriber` and vice versa. Simply import `import zio.interop.reactivestreams._` to make the -conversions available. - -## Examples - -First, let's get a few imports out of the way. - -```scala mdoc:silent -import org.reactivestreams.example.unicast._ -import zio._ -import zio.interop.reactivestreams._ -import zio.stream._ -``` - -We use the following `Publisher` and `Subscriber` for the examples: - -```scala mdoc -val publisher = new RangePublisher(3, 10) -val subscriber = new SyncSubscriber[Int] { - override protected def whenNext(v: Int): Boolean = { - print(s"$v, ") - true - } -} -``` - -### Publisher to Stream - -A `Publisher` used as a `Stream` buffers up to `qSize` elements. If possible, `qSize` should be -a power of two for best performance. The default is 16. - -```scala mdoc -val streamFromPublisher = publisher.toZIOStream(qSize = 16) -streamFromPublisher.run(Sink.collectAll[Integer]) -``` - -### Subscriber to Sink - -When running a `Stream` to a `Subscriber`, a side channel is needed for signalling failures. -For this reason `toZIOSink` returns a tuple of a callback and a `Sink`. The callback must be used to signal `Stream` failure. The type parameter on `toZIOSink` is the error type of *the Stream*. - -```scala mdoc -val asSink = subscriber.toZIOSink[Throwable] -val failingStream = ZStream.range(3, 13) ++ ZStream.fail(new RuntimeException("boom!")) -ZIO.scoped { - asSink.flatMap { case (signalError, sink) => // FIXME - failingStream.run(sink).catchAll(signalError) - } -} -``` - -### Stream to Publisher - -```scala mdoc -val stream = Stream.range(3, 13) -stream.toPublisher.flatMap { publisher => - UIO(publisher.subscribe(subscriber)) -} -``` - -### Sink to Subscriber - -`toSubscriber` returns a `Subscriber` and an `IO` which completes with the result of running the -`Sink` or the error if the `Publisher` fails. -A `Sink` used as a `Subscriber` buffers up to `qSize` elements. If possible, `qSize` should be -a power of two for best performance. The default is 16. - -```scala mdoc -val sink = Sink.collectAll[Integer] -ZIO.scoped { - sink.toSubscriber(qSize = 16).flatMap { case (subscriber, result) => - UIO(publisher.subscribe(subscriber)) *> result - } -} -``` +[Homepage](https://zio.dev/zio-interop-reactivestreams) [Badge-CI]: https://github.com/zio/interop-reactive-streams/workflows/CI/badge.svg [Badge-SonatypeReleases]: https://img.shields.io/nexus/r/https/oss.sonatype.org/dev.zio/zio-interop-reactivestreams_2.12.svg "Sonatype Releases" diff --git a/build.sbt b/build.sbt index 98a8080..7c1b7d7 100644 --- a/build.sbt +++ b/build.sbt @@ -3,7 +3,7 @@ import BuildHelper._ inThisBuild( List( organization := "dev.zio", - homepage := Some(url("https://zio.dev")), + homepage := Some(url("https://zio.dev/zio-interop-reactivestreams")), licenses := List("Apache-2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0")), developers := List( Developer( @@ -65,3 +65,17 @@ lazy val interopReactiveStreams = project ) // .settings(Test / javaOptions += "-XX:ActiveProcessorCount=1") // uncomment to test for deadlocks .settings(Test / fork := true) + +lazy val docs = project + .in(file("zio-interop-reactivestreams-docs")) + .settings( + publish / skip := true, + moduleName := "zio-interop-reactivestreams-docs", + scalacOptions -= "-Yno-imports", + scalacOptions -= "-Xfatal-warnings", + libraryDependencies ++= Seq( + "dev.zio" %% "zio" % zioVersion + ) + ) + .dependsOn(interopReactiveStreams) + .enablePlugins(WebsitePlugin) diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..c71ee47 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,84 @@ +--- +id: index +title: "Introduction to ZIO Interop Reactive Streams" +sidebar_label: "ZIO Interop Reactive Streams" +--- + +This library provides an interoperability layer between ZIO and reactive streams. + +## Reactive Streams `Producer` and `Subscriber` + +**ZIO** integrates with [Reactive Streams](http://reactive-streams.org) by providing conversions from `zio.stream.Stream` to `org.reactivestreams.Publisher` +and from `zio.stream.Sink` to `org.reactivestreams.Subscriber` and vice versa. Simply import `import zio.interop.reactivestreams._` to make the +conversions available. + +## Examples + +First, let's get a few imports out of the way. + +```scala +import org.reactivestreams.example.unicast._ +import zio._ +import zio.interop.reactivestreams._ +import zio.stream._ +``` + +We use the following `Publisher` and `Subscriber` for the examples: + +```scala +val publisher = new RangePublisher(3, 10) +val subscriber = new SyncSubscriber[Int] { + override protected def whenNext(v: Int): Boolean = { + print(s"$v, ") + true + } +} +``` + +### Publisher to Stream + +A `Publisher` used as a `Stream` buffers up to `qSize` elements. If possible, `qSize` should be +a power of two for best performance. The default is 16. + +```scala +val streamFromPublisher = publisher.toZIOStream(qSize = 16) +streamFromPublisher.run(Sink.collectAll[Integer]) +``` + +### Subscriber to Sink + +When running a `Stream` to a `Subscriber`, a side channel is needed for signalling failures. +For this reason `toZIOSink` returns a tuple of a callback and a `Sink`. The callback must be used to signal `Stream` failure. The type parameter on `toZIOSink` is the error type of *the Stream*. + +```scala +val asSink = subscriber.toZIOSink[Throwable] +val failingStream = ZStream.range(3, 13) ++ ZStream.fail(new RuntimeException("boom!")) +ZIO.scoped { + asSink.flatMap { case (signalError, sink) => // FIXME + failingStream.run(sink).catchAll(signalError) + } +} +``` + +### Stream to Publisher + +```scala +val stream = Stream.range(3, 13) +stream.toPublisher.flatMap { publisher => + UIO(publisher.subscribe(subscriber)) +} +``` + +### Sink to Subscriber + +`toSubscriber` returns a `Subscriber` and an `IO` which completes with the result of running the `Sink` or the error if the `Publisher` fails. +A `Sink` used as a `Subscriber` buffers up to `qSize` elements. If possible, `qSize` should be a power of two for best performance. The default is 16. + +```scala +val sink = Sink.collectAll[Integer] +ZIO.scoped { + sink.toSubscriber(qSize = 16).flatMap { case (subscriber, result) => + UIO(publisher.subscribe(subscriber)) *> result + } +} +``` diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..d4d7a01 --- /dev/null +++ b/docs/package.json @@ -0,0 +1,5 @@ +{ + "name": "@zio.dev/zio-interop-reactivestreams", + "description": "ZIO Interop Reactive Streams Documentation", + "license": "Apache-2.0" +} diff --git a/docs/sidebars.js b/docs/sidebars.js new file mode 100644 index 0000000..b485cd2 --- /dev/null +++ b/docs/sidebars.js @@ -0,0 +1,7 @@ +const sidebars = { + sidebar: [ + "index" + ] +}; + +module.exports = sidebars; diff --git a/project/plugins.sbt b/project/plugins.sbt index c215ae9..ddf0a6d 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -6,3 +6,6 @@ addSbtPlugin("com.github.cb372" % "sbt-explicit-dependencies" % "0.2.16") addSbtPlugin("org.portable-scala" % "sbt-crossproject" % "1.2.0") addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.7.0") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6") +addSbtPlugin("dev.zio" % "zio-sbt-website" % "0.0.0+84-6fd7d64e-SNAPSHOT") + +resolvers += Resolver.sonatypeRepo("public")