├── docs
└── src
│ ├── paradox
│ ├── CNAME
│ ├── usage
│ │ ├── further
│ │ │ ├── modules.md
│ │ │ ├── rendering.md
│ │ │ ├── index.md
│ │ │ ├── configuration.md
│ │ │ └── best-practices.md
│ │ ├── transformations
│ │ │ ├── reference
│ │ │ │ ├── map.md
│ │ │ │ ├── nop.md
│ │ │ │ ├── tee.md
│ │ │ │ ├── zip.md
│ │ │ │ ├── drop.md
│ │ │ │ ├── fold.md
│ │ │ │ ├── last.md
│ │ │ │ ├── scan.md
│ │ │ │ ├── take.md
│ │ │ │ ├── async.md
│ │ │ │ ├── buffer.md
│ │ │ │ ├── concat.md
│ │ │ │ ├── delay.md
│ │ │ │ ├── expand.md
│ │ │ │ ├── filter.md
│ │ │ │ ├── first.md
│ │ │ │ ├── merge.md
│ │ │ │ ├── orElse.md
│ │ │ │ ├── reduce.md
│ │ │ │ ├── sample.md
│ │ │ │ ├── slice.md
│ │ │ │ ├── split.md
│ │ │ │ ├── withLimit.md
│ │ │ │ ├── collect.md
│ │ │ │ ├── conflate.md
│ │ │ │ ├── dropAll.md
│ │ │ │ ├── dropLast.md
│ │ │ │ ├── flatMap.md
│ │ │ │ ├── groupBy.md
│ │ │ │ ├── grouped.md
│ │ │ │ ├── mapAsync.md
│ │ │ │ ├── multiply.md
│ │ │ │ ├── onCancel.md
│ │ │ │ ├── onError.md
│ │ │ │ ├── onSignal.md
│ │ │ │ ├── onStart.md
│ │ │ │ ├── protect.md
│ │ │ │ ├── recover.md
│ │ │ │ ├── sliding.md
│ │ │ │ ├── takeLast.md
│ │ │ │ ├── throttle.md
│ │ │ │ ├── dropWhile.md
│ │ │ │ ├── duplicate.md
│ │ │ │ ├── elementAt.md
│ │ │ │ ├── filterNot.md
│ │ │ │ ├── foldAsync.md
│ │ │ │ ├── groupedTo.md
│ │ │ │ ├── logSignal.md
│ │ │ │ ├── onElement.md
│ │ │ │ ├── onRequest.md
│ │ │ │ ├── scanAsync.md
│ │ │ │ ├── slidingTo.md
│ │ │ │ ├── splitWhen.md
│ │ │ │ ├── takeWhile.md
│ │ │ │ ├── deduplicate.md
│ │ │ │ ├── dropWithin.md
│ │ │ │ ├── fanInConcat.md
│ │ │ │ ├── fanInMerge.md
│ │ │ │ ├── fanInToSum.md
│ │ │ │ ├── fanOutToAny.md
│ │ │ │ ├── fanOutUnZip.md
│ │ │ │ ├── headAndTail.md
│ │ │ │ ├── injectToAny.md
│ │ │ │ ├── interleave.md
│ │ │ │ ├── intersperse.md
│ │ │ │ ├── mergeSorted.md
│ │ │ │ ├── onComplete.md
│ │ │ │ ├── onSignalPF.md
│ │ │ │ ├── onTerminate.md
│ │ │ │ ├── recoverWith.md
│ │ │ │ ├── sliceEvery.md
│ │ │ │ ├── splitAfter.md
│ │ │ │ ├── takeWithin.md
│ │ │ │ ├── asyncBoundary.md
│ │ │ │ ├── fanInSorted.md
│ │ │ │ ├── fanInToHList.md
│ │ │ │ ├── fanInToTuple.md
│ │ │ │ ├── fanOutSwitch.md
│ │ │ │ ├── flattenConcat.md
│ │ │ │ ├── flattenMerge.md
│ │ │ │ ├── flattenSorted.md
│ │ │ │ ├── flattenToSeq.md
│ │ │ │ ├── groupedWithin.md
│ │ │ │ ├── mergeToEither.md
│ │ │ │ ├── prefixAndTail.md
│ │ │ │ ├── recoverToTry.md
│ │ │ │ ├── takeEveryNth.md
│ │ │ │ ├── bufferDropping.md
│ │ │ │ ├── conflateToLast.md
│ │ │ │ ├── fanInToProduct.md
│ │ │ │ ├── withLimitWeighted.md
│ │ │ │ ├── conflateWithSeed.md
│ │ │ │ ├── fanInRoundRobin.md
│ │ │ │ ├── fanInToCoproduct.md
│ │ │ │ ├── fanOutBroadcast.md
│ │ │ │ ├── fanOutRoundRobin.md
│ │ │ │ ├── fanOutSequential.md
│ │ │ │ ├── injectBroadcast.md
│ │ │ │ ├── injectRoundRobin.md
│ │ │ │ ├── injectSequential.md
│ │ │ │ ├── prefixAndTailTo.md
│ │ │ │ ├── withIdleTimeout.md
│ │ │ │ ├── flattenRoundRobin.md
│ │ │ │ ├── mapAsyncUnordered.md
│ │ │ │ ├── withInitialTimeout.md
│ │ │ │ └── withCompletionTimeout.md
│ │ │ ├── index.md
│ │ │ └── couplings.md
│ │ ├── domain
│ │ │ ├── tcp.md
│ │ │ └── index.md
│ │ ├── swave-core-api.md
│ │ ├── show-off
│ │ │ ├── index.md
│ │ │ └── overview.md
│ │ ├── swave-testkit
│ │ │ └── index.md
│ │ ├── index.md
│ │ ├── swave-scodec-compat
│ │ │ └── index.md
│ │ └── swave-akka-compat
│ │ │ └── index.md
│ ├── _template
│ │ ├── favicon.ico
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── mstile-150x150.png
│ │ ├── apple-touch-icon.png
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── browserconfig.xml
│ │ ├── manifest.json
│ │ ├── assets
│ │ │ ├── js
│ │ │ │ └── theme.init.js
│ │ │ └── vendor
│ │ │ │ ├── nanoscroller
│ │ │ │ └── nanoscroller.css
│ │ │ │ └── highlight
│ │ │ │ └── github.css
│ │ └── safari-pinned-tab.svg
│ ├── talks
│ │ └── 2016
│ │ │ ├── scalar
│ │ │ ├── lib
│ │ │ │ ├── font
│ │ │ │ │ ├── RobotoSlab-Light.ttf
│ │ │ │ │ ├── RobotoSlab-Regular.ttf
│ │ │ │ │ └── YanoneKaffeesatz-Bold.ttf
│ │ │ │ ├── font-awesome
│ │ │ │ │ └── fonts
│ │ │ │ │ │ ├── FontAwesome.otf
│ │ │ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ │ │ └── fontawesome-webfont.woff
│ │ │ │ ├── js
│ │ │ │ │ ├── html5shiv.js
│ │ │ │ │ └── classList.js
│ │ │ │ └── css
│ │ │ │ │ └── zenburn.css
│ │ │ ├── plugin
│ │ │ │ └── print-pdf
│ │ │ │ │ └── print-pdf.js
│ │ │ └── img
│ │ │ │ └── not-the-other-way-around.svg
│ │ │ ├── scala.io
│ │ │ ├── lib
│ │ │ │ ├── font
│ │ │ │ │ ├── RobotoSlab-Light.ttf
│ │ │ │ │ ├── RobotoSlab-Regular.ttf
│ │ │ │ │ └── YanoneKaffeesatz-Bold.ttf
│ │ │ │ ├── font-awesome
│ │ │ │ │ └── fonts
│ │ │ │ │ │ ├── FontAwesome.otf
│ │ │ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ │ │ └── fontawesome-webfont.woff
│ │ │ │ ├── js
│ │ │ │ │ ├── html5shiv.js
│ │ │ │ │ └── classList.js
│ │ │ │ └── css
│ │ │ │ │ └── zenburn.css
│ │ │ ├── plugin
│ │ │ │ └── print-pdf
│ │ │ │ │ └── print-pdf.js
│ │ │ └── img
│ │ │ │ ├── small-inout.svg
│ │ │ │ ├── small-inject.svg
│ │ │ │ ├── small-flatten.svg
│ │ │ │ ├── line-fanin3.svg
│ │ │ │ └── not-the-other-way-around.svg
│ │ │ └── scaladays
│ │ │ ├── lib
│ │ │ ├── font
│ │ │ │ ├── RobotoSlab-Light.ttf
│ │ │ │ ├── RobotoSlab-Regular.ttf
│ │ │ │ └── YanoneKaffeesatz-Bold.ttf
│ │ │ ├── font-awesome
│ │ │ │ └── fonts
│ │ │ │ │ ├── FontAwesome.otf
│ │ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ │ └── fontawesome-webfont.woff
│ │ │ ├── js
│ │ │ │ ├── html5shiv.js
│ │ │ │ └── classList.js
│ │ │ └── css
│ │ │ │ └── zenburn.css
│ │ │ ├── plugin
│ │ │ └── print-pdf
│ │ │ │ └── print-pdf.js
│ │ │ └── img
│ │ │ ├── small-inout.svg
│ │ │ ├── small-inject.svg
│ │ │ ├── small-flatten.svg
│ │ │ └── line-fanin3.svg
│ ├── project
│ │ ├── changelog.md
│ │ ├── index.md
│ │ ├── sponsors.md
│ │ ├── references.md
│ │ └── license.md
│ ├── introduction
│ │ ├── index.md
│ │ └── talks-on-swave.md
│ ├── dev
│ │ └── index.md
│ └── index.md
│ └── test
│ └── scala
│ └── swave
│ └── docs
│ ├── Debugging.scala
│ ├── SimpleTransformSpec.scala
│ ├── CouplingSpec.scala
│ ├── DrainSpec.scala
│ ├── StreamOfStreamsSpec.scala
│ └── BasicSpec.scala
├── project
├── build.properties
└── plugins.sbt
├── version.sbt
├── core-tests
└── src
│ └── test
│ ├── scala
│ └── swave
│ │ └── core
│ │ ├── tags.scala
│ │ ├── tck
│ │ ├── Timeouts.scala
│ │ ├── ToPublisherDrainSpec.scala
│ │ ├── IdentityProcessorSpec.scala
│ │ └── SwavePublisherVerification.scala
│ │ ├── impl
│ │ └── stages
│ │ │ ├── SyncPipeSpec.scala
│ │ │ └── LazyStartSpoutSpec.scala
│ │ ├── hash
│ │ └── HashTransformationSpec.scala
│ │ └── DisconnectedGraphSpec.scala
│ └── resources
│ └── RegionSpec.examples.txt
├── core
└── src
│ ├── main
│ ├── scala
│ │ └── swave
│ │ │ └── core
│ │ │ ├── graph
│ │ │ ├── package.scala
│ │ │ └── impl
│ │ │ │ └── LineRendering.scala
│ │ │ ├── io
│ │ │ ├── package.scala
│ │ │ └── files
│ │ │ │ └── package.scala
│ │ │ ├── util
│ │ │ ├── RichTraversable.scala
│ │ │ ├── RichDuration.scala
│ │ │ ├── RichFiniteDuration.scala
│ │ │ ├── IntInt.scala
│ │ │ ├── RichHList.scala
│ │ │ ├── RichInt.scala
│ │ │ ├── BreakOutTo.scala
│ │ │ ├── RichFuture.scala
│ │ │ ├── RichArrayBuffer.scala
│ │ │ ├── RichByteArray.scala
│ │ │ ├── RichLong.scala
│ │ │ ├── RichList.scala
│ │ │ ├── AnyRefExtractor.scala
│ │ │ └── RichSeq.scala
│ │ │ ├── impl
│ │ │ ├── stages
│ │ │ │ ├── StreamTermination.scala
│ │ │ │ ├── DrainStage.scala
│ │ │ │ ├── SpoutStage.scala
│ │ │ │ ├── drain
│ │ │ │ │ ├── CancellingDrainStage.scala
│ │ │ │ │ ├── IgnoreDrainStage.scala
│ │ │ │ │ ├── HeadDrainStage.scala
│ │ │ │ │ ├── ForeachDrainStage.scala
│ │ │ │ │ └── SubscriberDrainStage.scala
│ │ │ │ ├── FanInStage.scala
│ │ │ │ ├── InOutStage.scala
│ │ │ │ ├── inout
│ │ │ │ │ ├── NopStage.scala
│ │ │ │ │ ├── CouplingStage.scala
│ │ │ │ │ ├── AsyncDispatcherStage.scala
│ │ │ │ │ ├── DeduplicateStage.scala
│ │ │ │ │ ├── MapStage.scala
│ │ │ │ │ ├── OnStartStage.scala
│ │ │ │ │ ├── FilterStage.scala
│ │ │ │ │ ├── DropLastStage.scala
│ │ │ │ │ ├── TakeWhileStage.scala
│ │ │ │ │ ├── CollectStage.scala
│ │ │ │ │ ├── TakeWithinStage.scala
│ │ │ │ │ ├── WithLimitStage.scala
│ │ │ │ │ └── DropStage.scala
│ │ │ │ ├── fanout
│ │ │ │ │ ├── FanOutAnyStage.scala
│ │ │ │ │ ├── FanOutRoundRobinStage.scala
│ │ │ │ │ └── FanOutSwitchStage.scala
│ │ │ │ ├── spout
│ │ │ │ │ ├── RepeatSpoutStage.scala
│ │ │ │ │ ├── FailingSpoutStage.scala
│ │ │ │ │ ├── RingBufferSpoutStage.scala
│ │ │ │ │ ├── IteratorSpoutStage.scala
│ │ │ │ │ └── UnfoldSpoutStage.scala
│ │ │ │ ├── FanOutStage.scala
│ │ │ │ └── fanin
│ │ │ │ │ └── ConcatStage.scala
│ │ │ ├── CallingThreadExecutionContext.scala
│ │ │ ├── util
│ │ │ │ └── SettingsCompanion.scala
│ │ │ ├── Port.scala
│ │ │ ├── DispatchersImpl.scala
│ │ │ └── rs
│ │ │ │ └── helpers.scala
│ │ │ ├── Cancellable.scala
│ │ │ ├── StreamEvent.scala
│ │ │ ├── Coupling.scala
│ │ │ ├── hash
│ │ │ └── package.scala
│ │ │ ├── Dispatchers.scala
│ │ │ ├── text
│ │ │ └── package.scala
│ │ │ ├── Split.scala
│ │ │ └── Extension.scala
│ └── java
│ │ └── swave
│ │ └── core
│ │ └── impl
│ │ ├── util
│ │ └── UnsafeArrayAccess.java
│ │ └── Statics.java
│ └── test
│ └── scala
│ └── swave
│ └── core
│ └── util
│ ├── RichListSpec.scala
│ ├── RichLongSpec.scala
│ ├── RichRefArraySpec.scala
│ └── XorShiftRandomSpec.scala
├── .gitignore
├── compat-scodec
└── src
│ ├── main
│ └── scala
│ │ └── swave
│ │ └── compat
│ │ └── scodec
│ │ └── package.scala
│ └── test
│ └── resources
│ └── logback.xml
├── testkit
└── src
│ └── main
│ ├── scala
│ └── swave
│ │ └── testkit
│ │ ├── TestkitExtension.scala
│ │ ├── package.scala
│ │ ├── ExpectationFailedException.scala
│ │ ├── Testkit.scala
│ │ └── Timing.scala
│ └── resources
│ └── reference.conf
├── .scalafmt.conf
├── .travis.yml
├── README.rst
└── core-macros
└── src
└── main
└── scala
└── swave
└── core
└── macros
├── ConnectInAndSealWith.scala
├── ConnectOutAndSealWith.scala
├── ConnectFanInAndSealWith.scala
└── Macros.scala
/docs/src/paradox/CNAME:
--------------------------------------------------------------------------------
1 | swave.cc
--------------------------------------------------------------------------------
/project/build.properties:
--------------------------------------------------------------------------------
1 | sbt.version=0.13.13
2 |
--------------------------------------------------------------------------------
/version.sbt:
--------------------------------------------------------------------------------
1 | version in ThisBuild := "0.7.2-SNAPSHOT"
2 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/further/modules.md:
--------------------------------------------------------------------------------
1 | Modules
2 | =======
3 |
4 | ... TODO ...
--------------------------------------------------------------------------------
/docs/src/paradox/usage/further/rendering.md:
--------------------------------------------------------------------------------
1 | Rendering
2 | =========
3 |
4 | ... TODO ...
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/map.md:
--------------------------------------------------------------------------------
1 | map
2 | ===
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/nop.md:
--------------------------------------------------------------------------------
1 | nop
2 | ===
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/tee.md:
--------------------------------------------------------------------------------
1 | tee
2 | ===
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/zip.md:
--------------------------------------------------------------------------------
1 | zip
2 | ===
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/domain/tcp.md:
--------------------------------------------------------------------------------
1 | Network IO (TCP)
2 | ================
3 |
4 | ... TODO ...
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/drop.md:
--------------------------------------------------------------------------------
1 | drop
2 | ====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fold.md:
--------------------------------------------------------------------------------
1 | fold
2 | ====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/last.md:
--------------------------------------------------------------------------------
1 | last
2 | ====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/scan.md:
--------------------------------------------------------------------------------
1 | scan
2 | ====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/take.md:
--------------------------------------------------------------------------------
1 | take
2 | ====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/async.md:
--------------------------------------------------------------------------------
1 | async
2 | =====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/buffer.md:
--------------------------------------------------------------------------------
1 | buffer
2 | ======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/concat.md:
--------------------------------------------------------------------------------
1 | concat
2 | ======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/delay.md:
--------------------------------------------------------------------------------
1 | delay
2 | =====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/expand.md:
--------------------------------------------------------------------------------
1 | expand
2 | ======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/filter.md:
--------------------------------------------------------------------------------
1 | filter
2 | ======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/first.md:
--------------------------------------------------------------------------------
1 | first
2 | =====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/merge.md:
--------------------------------------------------------------------------------
1 | merge
2 | =====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/orElse.md:
--------------------------------------------------------------------------------
1 | orElse
2 | ======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/reduce.md:
--------------------------------------------------------------------------------
1 | reduce
2 | ======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/sample.md:
--------------------------------------------------------------------------------
1 | sample
2 | ======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/slice.md:
--------------------------------------------------------------------------------
1 | slice
2 | =====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/split.md:
--------------------------------------------------------------------------------
1 | split
2 | =====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/withLimit.md:
--------------------------------------------------------------------------------
1 | limit
2 | =====
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/collect.md:
--------------------------------------------------------------------------------
1 | collect
2 | =======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/conflate.md:
--------------------------------------------------------------------------------
1 | conflate
2 | ========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/dropAll.md:
--------------------------------------------------------------------------------
1 | dropAll
2 | =======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/dropLast.md:
--------------------------------------------------------------------------------
1 | dropLast
2 | ========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/flatMap.md:
--------------------------------------------------------------------------------
1 | flatMap
2 | =======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/groupBy.md:
--------------------------------------------------------------------------------
1 | groupBy
2 | =======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/grouped.md:
--------------------------------------------------------------------------------
1 | grouped
2 | =======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/mapAsync.md:
--------------------------------------------------------------------------------
1 | mapAsync
2 | ========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/multiply.md:
--------------------------------------------------------------------------------
1 | multiply
2 | ========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/onCancel.md:
--------------------------------------------------------------------------------
1 | onCancel
2 | ========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/onError.md:
--------------------------------------------------------------------------------
1 | onError
2 | =======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/onSignal.md:
--------------------------------------------------------------------------------
1 | onSignal
2 | ========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/onStart.md:
--------------------------------------------------------------------------------
1 | onStart
2 | =======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/protect.md:
--------------------------------------------------------------------------------
1 | protect
2 | =======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/recover.md:
--------------------------------------------------------------------------------
1 | recover
2 | =======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/sliding.md:
--------------------------------------------------------------------------------
1 | sliding
2 | =======
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/takeLast.md:
--------------------------------------------------------------------------------
1 | takeLast
2 | ========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/throttle.md:
--------------------------------------------------------------------------------
1 | throttle
2 | ========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/dropWhile.md:
--------------------------------------------------------------------------------
1 | dropWhile
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/duplicate.md:
--------------------------------------------------------------------------------
1 | duplicate
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/elementAt.md:
--------------------------------------------------------------------------------
1 | elementAt
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/filterNot.md:
--------------------------------------------------------------------------------
1 | filterNot
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/foldAsync.md:
--------------------------------------------------------------------------------
1 | foldAsync
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/groupedTo.md:
--------------------------------------------------------------------------------
1 | groupedTo
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/logSignal.md:
--------------------------------------------------------------------------------
1 | logSignal
2 | ========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/onElement.md:
--------------------------------------------------------------------------------
1 | onElement
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/onRequest.md:
--------------------------------------------------------------------------------
1 | onRequest
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/scanAsync.md:
--------------------------------------------------------------------------------
1 | scanAsync
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/slidingTo.md:
--------------------------------------------------------------------------------
1 | slidingTo
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/splitWhen.md:
--------------------------------------------------------------------------------
1 | splitWhen
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/takeWhile.md:
--------------------------------------------------------------------------------
1 | takeWhile
2 | =========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/deduplicate.md:
--------------------------------------------------------------------------------
1 | deduplicate
2 | ===========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/dropWithin.md:
--------------------------------------------------------------------------------
1 | dropWithin
2 | ==========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanInConcat.md:
--------------------------------------------------------------------------------
1 | fanInConcat
2 | ===========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanInMerge.md:
--------------------------------------------------------------------------------
1 | fanInMerge
2 | ==========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanInToSum.md:
--------------------------------------------------------------------------------
1 | fanInToSum
2 | ==========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanOutToAny.md:
--------------------------------------------------------------------------------
1 | fanOutToAny
2 | ===========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanOutUnZip.md:
--------------------------------------------------------------------------------
1 | fanOutUnZip
2 | ===========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/headAndTail.md:
--------------------------------------------------------------------------------
1 | headAndTail
2 | ===========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/injectToAny.md:
--------------------------------------------------------------------------------
1 | injectToAny
2 | ===========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/interleave.md:
--------------------------------------------------------------------------------
1 | interleave
2 | ==========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/intersperse.md:
--------------------------------------------------------------------------------
1 | intersperse
2 | ===========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/mergeSorted.md:
--------------------------------------------------------------------------------
1 | mergeSorted
2 | ===========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/onComplete.md:
--------------------------------------------------------------------------------
1 | onComplete
2 | ==========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/onSignalPF.md:
--------------------------------------------------------------------------------
1 | onSignalPF
2 | ==========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/onTerminate.md:
--------------------------------------------------------------------------------
1 | onTerminate
2 | ===========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/recoverWith.md:
--------------------------------------------------------------------------------
1 | recoverWith
2 | ===========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/sliceEvery.md:
--------------------------------------------------------------------------------
1 | sliceEvery
2 | ==========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/splitAfter.md:
--------------------------------------------------------------------------------
1 | splitAfter
2 | ==========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/takeWithin.md:
--------------------------------------------------------------------------------
1 | takeWithin
2 | ==========
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/asyncBoundary.md:
--------------------------------------------------------------------------------
1 | asyncBoundary
2 | =============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanInSorted.md:
--------------------------------------------------------------------------------
1 | fanInSorted
2 | ================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanInToHList.md:
--------------------------------------------------------------------------------
1 | fanInToHList
2 | ============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanInToTuple.md:
--------------------------------------------------------------------------------
1 | fanInToTuple
2 | ============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanOutSwitch.md:
--------------------------------------------------------------------------------
1 | fanOutSwitch
2 | ============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/flattenConcat.md:
--------------------------------------------------------------------------------
1 | flattenConcat
2 | =============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/flattenMerge.md:
--------------------------------------------------------------------------------
1 | flattenMerge
2 | ============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/flattenSorted.md:
--------------------------------------------------------------------------------
1 | flattenSorted
2 | =============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/flattenToSeq.md:
--------------------------------------------------------------------------------
1 | flattenToSeq
2 | ============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/groupedWithin.md:
--------------------------------------------------------------------------------
1 | groupedWithin
2 | =============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/mergeToEither.md:
--------------------------------------------------------------------------------
1 | mergeToEither
2 | =============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/prefixAndTail.md:
--------------------------------------------------------------------------------
1 | prefixAndTail
2 | =============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/recoverToTry.md:
--------------------------------------------------------------------------------
1 | recoverToTry
2 | ============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/takeEveryNth.md:
--------------------------------------------------------------------------------
1 | takeEveryNth
2 | ============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/_template/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/_template/favicon.ico
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/bufferDropping.md:
--------------------------------------------------------------------------------
1 | bufferDropping
2 | ==============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/conflateToLast.md:
--------------------------------------------------------------------------------
1 | conflateToLast
2 | ==============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanInToProduct.md:
--------------------------------------------------------------------------------
1 | fanInToProduct
2 | ==============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/withLimitWeighted.md:
--------------------------------------------------------------------------------
1 | limitWeighted
2 | =============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/conflateWithSeed.md:
--------------------------------------------------------------------------------
1 | conflateWithSeed
2 | ================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanInRoundRobin.md:
--------------------------------------------------------------------------------
1 | fanInRoundRobin
2 | ===============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanInToCoproduct.md:
--------------------------------------------------------------------------------
1 | fanInToCoproduct
2 | ================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanOutBroadcast.md:
--------------------------------------------------------------------------------
1 | fanOutBroadcast
2 | ===============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanOutRoundRobin.md:
--------------------------------------------------------------------------------
1 | fanOutRoundRobin
2 | ================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/fanOutSequential.md:
--------------------------------------------------------------------------------
1 | fanOutSequential
2 | ================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/injectBroadcast.md:
--------------------------------------------------------------------------------
1 | injectBroadcast
2 | ===============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/injectRoundRobin.md:
--------------------------------------------------------------------------------
1 | injectRoundRobin
2 | ================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/injectSequential.md:
--------------------------------------------------------------------------------
1 | injectSequential
2 | ================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/prefixAndTailTo.md:
--------------------------------------------------------------------------------
1 | prefixAndTailTo
2 | ===============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/withIdleTimeout.md:
--------------------------------------------------------------------------------
1 | withIdleTimeout
2 | ===============
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/_template/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/_template/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/src/paradox/_template/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/_template/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/flattenRoundRobin.md:
--------------------------------------------------------------------------------
1 | flattenRoundRobin
2 | =================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/mapAsyncUnordered.md:
--------------------------------------------------------------------------------
1 | mapAsyncUnordered
2 | =================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/withInitialTimeout.md:
--------------------------------------------------------------------------------
1 | withInitialTimeout
2 | ==================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/_template/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/_template/mstile-150x150.png
--------------------------------------------------------------------------------
/docs/src/paradox/_template/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/_template/apple-touch-icon.png
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/reference/withCompletionTimeout.md:
--------------------------------------------------------------------------------
1 | withCompletionTimeout
2 | =====================
3 |
4 | ... TODO ...
5 |
--------------------------------------------------------------------------------
/docs/src/paradox/_template/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/_template/android-chrome-192x192.png
--------------------------------------------------------------------------------
/docs/src/paradox/_template/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/_template/android-chrome-512x512.png
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/lib/font/RobotoSlab-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scalar/lib/font/RobotoSlab-Light.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/lib/font/RobotoSlab-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scala.io/lib/font/RobotoSlab-Light.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/lib/font/RobotoSlab-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scalar/lib/font/RobotoSlab-Regular.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/project/changelog.md:
--------------------------------------------------------------------------------
1 | Changelog
2 | =========
3 |
4 | This is the current *swave* @github[CHANGELOG](/CHANGELOG):
5 |
6 |
7 |
8 | @@snip [-](../../../../CHANGELOG)
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/lib/font/RobotoSlab-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scala.io/lib/font/RobotoSlab-Regular.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/lib/font/RobotoSlab-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scaladays/lib/font/RobotoSlab-Light.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/lib/font/RobotoSlab-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scaladays/lib/font/RobotoSlab-Regular.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/lib/font/YanoneKaffeesatz-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scalar/lib/font/YanoneKaffeesatz-Bold.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/lib/font/YanoneKaffeesatz-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scala.io/lib/font/YanoneKaffeesatz-Bold.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/lib/font/YanoneKaffeesatz-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scaladays/lib/font/YanoneKaffeesatz-Bold.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/lib/font-awesome/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scalar/lib/font-awesome/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/lib/font-awesome/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scala.io/lib/font-awesome/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/lib/font-awesome/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scaladays/lib/font-awesome/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/lib/font-awesome/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scalar/lib/font-awesome/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/lib/font-awesome/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scalar/lib/font-awesome/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/lib/font-awesome/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scala.io/lib/font-awesome/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/lib/font-awesome/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scala.io/lib/font-awesome/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/lib/font-awesome/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scala.io/lib/font-awesome/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/lib/font-awesome/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scaladays/lib/font-awesome/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/lib/font-awesome/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scaladays/lib/font-awesome/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/lib/font-awesome/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scalar/lib/font-awesome/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/lib/font-awesome/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sirthias/swave/HEAD/docs/src/paradox/talks/2016/scaladays/lib/font-awesome/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/docs/src/paradox/usage/domain/index.md:
--------------------------------------------------------------------------------
1 | Domain Adapters
2 | ===============
3 |
4 | @@@index
5 |
6 | * [-](file-io.md)
7 | * [-](tcp.md)
8 | * [-](text.md)
9 | * [-](hash.md)
10 |
11 | @@@
12 |
13 | @@toc { depth=2 }
--------------------------------------------------------------------------------
/docs/src/paradox/usage/swave-core-api.md:
--------------------------------------------------------------------------------
1 | API Docs (ScalaDoc)
2 | ===================
3 |
4 | The complete API documentation, i.e. the ScalaDocs, for *swave-core* can
5 | be found @scaladoc[>>> HERE <<<](swave.core.index).
6 |
7 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/show-off/index.md:
--------------------------------------------------------------------------------
1 | Show-Off
2 | ========
3 |
4 | @@@index
5 |
6 | * [-](overview.md)
7 | * [-](md5.md)
8 | * [-](fahrenheit.md)
9 | * [-](monte-carlo-pi.md)
10 | * [-](fibonacci.md)
11 |
12 | @@@
13 |
14 | @@toc { depth=1 }
--------------------------------------------------------------------------------
/docs/src/paradox/project/index.md:
--------------------------------------------------------------------------------
1 | Project Info
2 | ============
3 |
4 | @@@index
5 |
6 | * [-](license.md)
7 | * [-](contributing.md)
8 | * [-](changelog.md)
9 | * [-](sponsors.md)
10 | * [-](references.md)
11 |
12 | @@@
13 |
14 | @@toc { depth=2 }
15 |
--------------------------------------------------------------------------------
/docs/src/paradox/introduction/index.md:
--------------------------------------------------------------------------------
1 | Introduction
2 | ============
3 |
4 | @@@index
5 |
6 | * [-](overview.md)
7 | * [-](reactive-streams.md)
8 | * [-](swave-vs-akka-stream.md)
9 | * [-](talks-on-swave.md)
10 |
11 | @@@
12 |
13 | @@toc { depth=3 }
14 |
15 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/swave-testkit/index.md:
--------------------------------------------------------------------------------
1 | swave-testkit
2 | =============
3 |
4 | ... TODO ...
5 |
6 |
7 | API Docs (ScalaDoc)
8 | -------------------
9 |
10 | The ScalaDoc for *swave-testkit* can be found @scaladoc[>>> HERE <<<](swave.testkit.package).
11 |
--------------------------------------------------------------------------------
/docs/src/paradox/_template/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #2b5797
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/lib/js/html5shiv.js:
--------------------------------------------------------------------------------
1 | document.createElement('header');
2 | document.createElement('nav');
3 | document.createElement('section');
4 | document.createElement('article');
5 | document.createElement('aside');
6 | document.createElement('footer');
7 | document.createElement('hgroup');
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/lib/js/html5shiv.js:
--------------------------------------------------------------------------------
1 | document.createElement('header');
2 | document.createElement('nav');
3 | document.createElement('section');
4 | document.createElement('article');
5 | document.createElement('aside');
6 | document.createElement('footer');
7 | document.createElement('hgroup');
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/lib/js/html5shiv.js:
--------------------------------------------------------------------------------
1 | document.createElement('header');
2 | document.createElement('nav');
3 | document.createElement('section');
4 | document.createElement('article');
5 | document.createElement('aside');
6 | document.createElement('footer');
7 | document.createElement('hgroup');
--------------------------------------------------------------------------------
/docs/src/paradox/usage/further/index.md:
--------------------------------------------------------------------------------
1 | Further Topics
2 | ==============
3 |
4 | @@@index
5 |
6 | * [-](sync-vs-async.md)
7 | * [-](pipes.md)
8 | * [-](modules.md)
9 | * [-](debugging.md)
10 | * [-](rendering.md)
11 | * [-](configuration.md)
12 | * [-](best-practices.md)
13 |
14 | @@@
15 |
16 | @@toc { depth=2 }
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/index.md:
--------------------------------------------------------------------------------
1 | Transformations
2 | ===============
3 |
4 | @@@index
5 |
6 | * [-](overview.md)
7 | * [-](simple.md)
8 | * [-](fan-ins.md)
9 | * [-](fan-outs.md)
10 | * [-](streams-of-streams.md)
11 | * [-](relationships.md)
12 | * [-](couplings.md)
13 | * [-](reference/index.md)
14 |
15 | @@@
16 |
17 | @@toc { depth=3 }
--------------------------------------------------------------------------------
/docs/src/paradox/project/sponsors.md:
--------------------------------------------------------------------------------
1 | Sponsors
2 | ========
3 |
4 | The following companies and organisations have kindly agreed to supply the *swave* development team with
5 | free open-source licenses of their excellent development tools:
6 |
7 | [Jetbrains](http://www.jetbrains.com/)
8 | : [We use IntelliJ IDEA Ultimate as the Scala IDE of our choice.](http://www.jetbrains.com/idea/)
--------------------------------------------------------------------------------
/core-tests/src/test/scala/swave/core/tags.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | import org.scalatest.Tag
10 |
11 | object NotOnTravis extends Tag("NotOnTravis")
12 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/graph/package.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | package object graph {
10 |
11 | type Glyph = Int with GlyphMarker
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/docs/src/paradox/_template/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "swave.cc",
3 | "icons": [
4 | {
5 | "src": "\/android-chrome-192x192.png",
6 | "sizes": "192x192",
7 | "type": "image\/png"
8 | },
9 | {
10 | "src": "\/android-chrome-512x512.png",
11 | "sizes": "512x512",
12 | "type": "image\/png"
13 | }
14 | ],
15 | "theme_color": "#ffffff",
16 | "display": "standalone"
17 | }
18 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/io/package.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | package object io {
10 |
11 | implicit val byteArrayBytes: Bytes[Array[Byte]] = new ByteArrayBytes
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/core-tests/src/test/scala/swave/core/tck/Timeouts.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.tck
8 |
9 | import scala.concurrent.duration._
10 |
11 | object Timeouts {
12 | def publisherShutdownTimeout = 3000.millis
13 |
14 | def defaultTimeout = 800.millis
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Only put project-/build-tool-specific things here!
2 | # Everything specific to your particular dev machine
3 | # (like OS- or IDE-related artifacts) should go into
4 | # a personal, global .gitignore file!
5 | # (See https://help.github.com/articles/ignoring-files/ for details)
6 |
7 | lib_managed
8 | target
9 | project/boot
10 | project/build/target
11 | project/plugins/lib_managed
12 | project/plugins/src_managed
13 | project/plugins/target
14 | project/plugins/project/build.properties
--------------------------------------------------------------------------------
/compat-scodec/src/main/scala/swave/compat/scodec/package.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.compat
8 |
9 | import swave.compat.scodec.impl.ByteVectorBytes
10 |
11 | package object scodec {
12 |
13 | implicit val byteVectorBytes: ByteVectorBytes = new ByteVectorBytes
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/compat-scodec/src/test/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | System.out
6 |
7 | %date{MM/dd HH:mm:ss.SSS} %-5level[%.15thread] %logger{1} - %msg%n
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/index.md:
--------------------------------------------------------------------------------
1 | User Documentation
2 | ==================
3 |
4 | @@@index
5 |
6 | * [-](show-off/index.md)
7 | * [-](setup.md)
8 | * [-](quick-start.md)
9 | * [-](basics.md)
10 | * [-](spouts.md)
11 | * [-](drains.md)
12 | * [-](transformations/index.md)
13 | * [-](further/index.md)
14 | * [-](domain/index.md)
15 | * [-](swave-core-api.md)
16 | * [-](swave-akka-compat/index.md)
17 | * [-](swave-scodec-compat/index.md)
18 | * [-](swave-testkit/index.md)
19 |
20 | @@@
21 |
22 | @@toc { depth=3 }
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichTraversable.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | final class RichTraversable[A](val underlying: Traversable[A]) extends AnyVal {
10 |
11 | def sumBy[N](f: A ⇒ N)(implicit num: Numeric[N]): N =
12 | underlying.foldLeft(num.zero)((sum, x) ⇒ num.plus(sum, f(x)))
13 | }
14 |
--------------------------------------------------------------------------------
/core-tests/src/test/scala/swave/core/impl/stages/SyncPipeSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages
8 |
9 | import org.scalatest.prop.Checkers
10 | import swave.core.SwaveSpec
11 | import swave.core.internal.testkit.TestGeneration
12 |
13 | abstract class SyncPipeSpec extends SwaveSpec with Checkers with TestGeneration
14 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/io/files/package.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.io
8 |
9 | import swave.core._
10 |
11 | package object files {
12 |
13 | implicit class RichSpout(val underlying: Spout.type) extends SpoutFromFiles
14 | implicit class RichDrain(val underlying: Drain.type) extends DrainToFiles
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichDuration.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import scala.concurrent.duration._
10 |
11 | final class RichDuration(val underlying: Duration) extends AnyVal {
12 |
13 | def orElse(that: Duration): Duration =
14 | if (underlying eq Duration.Undefined) that else underlying
15 | }
16 |
--------------------------------------------------------------------------------
/docs/src/paradox/project/references.md:
--------------------------------------------------------------------------------
1 | References
2 | ==========
3 |
4 | It's always hard for any open-source project to keep track of who is using the software around the world.
5 |
6 | For the individuals and organizations who'd like to make their using *swave* public we have created this page.
7 | If you'd like your organisation to be listed here (along with a backlink) please provide us with the following details:
8 |
9 | - Name of your organisation
10 | - Homepage URL
11 | - Short statement about how *swave* is used and/or your experiences (so far) with it.
12 | - Logo (optional)
13 |
14 | ---
--------------------------------------------------------------------------------
/docs/src/test/scala/swave/docs/Debugging.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.docs
8 |
9 | object Debugging extends App {
10 | //#example
11 | import swave.core._
12 |
13 | implicit val env = StreamEnv()
14 |
15 | Spout.ints(from = 0)
16 | .logSignal("A")
17 | .map(_ * 2)
18 | .take(5)
19 | .fold(0)(_ + _)
20 | .logSignal("B")
21 | .drainToBlackHole()
22 | //#example
23 | }
--------------------------------------------------------------------------------
/docs/src/paradox/dev/index.md:
--------------------------------------------------------------------------------
1 | Developer Documentation
2 | =======================
3 |
4 | ... TODO ...
5 |
6 | In this section we plan on providing concrete guidance for finding one's way around the *swave* internals,
7 | targeted at everyone who'd like to contribute actual code to the project for the first time.
8 | For example these things be discussed:
9 |
10 | - the introduction of the 7 types of "signals" that drive every processing stage in a stream setup
11 | - the internal DSL for defining stage state machines incl. the macro expansion step
12 | - more in-depth discussion of the stream execution model
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/testkit/src/main/scala/swave/testkit/TestkitExtension.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.testkit
8 |
9 | import swave.core.{Extension, ExtensionId, StreamEnv}
10 |
11 | object TestkitExtension extends ExtensionId[TestkitExtension] {
12 | def createExtension(env: StreamEnv) =
13 | new TestkitExtension(Testkit.Settings(env.config))
14 | }
15 |
16 | class TestkitExtension(val settings: Testkit.Settings) extends Extension
17 |
--------------------------------------------------------------------------------
/.scalafmt.conf:
--------------------------------------------------------------------------------
1 | style = defaultWithAlign
2 | maxColumn = 120
3 |
4 | assumeStandardLibraryStripMargin = true
5 | binPack.parentConstructors = true
6 | align.openParenCallSite = false
7 | runner.optimizer.forceConfigStyleOnOffset = -1
8 |
9 | rewrite.rules = [RedundantBraces, RedundantParens, SortImports, PreferCurlyFors]
10 | rewrite.redundantBraces.maxLines = 5
11 |
12 | project.git = true
13 | project.includeFilters = [
14 | "compat-akka/.*\\.scala"
15 | "compat-scodec/.*\\.scala"
16 | "core/.*\\.scala"
17 | "core-macros/.*\\.scala"
18 | "testkit/.*\\.scala"
19 | ]
20 | project.excludeFilters = [
21 | "core/src/test/scala/org/scalacheck/.*"
22 | ]
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # for SBT <-> Travis integration best practices see
2 | # http://www.scala-sbt.org/0.13/docs/Travis-CI-with-sbt.html
3 |
4 | language:
5 | - scala
6 |
7 | scala:
8 | - 2.11.8
9 |
10 | jdk:
11 | - oraclejdk8
12 |
13 | cache:
14 | directories:
15 | - $HOME/.ivy2/cache
16 | - $HOME/.sbt/boot/
17 |
18 | # avoid unnecessary cache updates
19 | before_cache:
20 | - find $HOME/.ivy2 -name "ivydata-*.properties" -delete
21 | - find $HOME/.sbt -name "*.lock" -delete
22 |
23 | script:
24 | - sbt clean coverage "test-only -- -l NotOnTravis" coverageReport -Dswave.test.timing.factor=1.05 &&
25 | sbt coverageAggregate
26 |
27 | after_success:
28 | - sbt coveralls
--------------------------------------------------------------------------------
/testkit/src/main/scala/swave/testkit/package.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave
8 |
9 | import scala.concurrent.duration._
10 | import swave.core.StreamEnv
11 | import swave.core.util._
12 |
13 | package object testkit {
14 |
15 | implicit class TestDuration(val duration: FiniteDuration) extends AnyVal {
16 | def dilated(implicit env: StreamEnv): FiniteDuration =
17 | duration timesFiniteFactor TestkitExtension(env).settings.timingDefaults.factor
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/further/configuration.md:
--------------------------------------------------------------------------------
1 | Configuration
2 | =============
3 |
4 | *swave* relies on [Typesafe Config] for configuration of all aspects of the streaming environment.
5 | When you create a @scaladoc[StreamEnv] instance for your application the configuration is loaded from the classpath
6 | (and/or other sources, like JVM system properties) and used for all stream runs under this `StreamEnv`.
7 |
8 | This is the content of *swave's* own `reference.conf` which contains the default values for all defined config settings:
9 |
10 | @@snip [-]($res$/reference.conf) { #source-quote type=bash }
11 |
12 | [Typesafe Config]: https://github.com/typesafehub/config
13 | [StreamEnv]: swave.core.StreamEnv
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichFiniteDuration.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import scala.concurrent.duration._
10 | import swave.core.macros._
11 |
12 | final class RichFiniteDuration(val underlying: FiniteDuration) extends AnyVal {
13 |
14 | def timesFiniteFactor(factor: Double): FiniteDuration = {
15 | requireArg(!factor.isInfinite && !factor.isNaN, "`factor` must not be infinite and not be NaN")
16 | Duration.fromNanos((underlying.toNanos * factor + 0.5).toLong)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/testkit/src/main/resources/reference.conf:
--------------------------------------------------------------------------------
1 | #######################################
2 | # swave Testkit Reference Config File #
3 | #######################################
4 |
5 | # This is the reference config file that contains all the default settings.
6 | # Make your edits/overrides in your application.conf.
7 |
8 | swave {
9 | test {
10 | timing {
11 | # factor by which to scale test timings
12 | factor = 1.0
13 |
14 | # factors to re-run an initially failing test with before declaring a test as truly failing
15 | scaling-chain = [1.1, 1.5, 2.0, 3.0, 4.0, 8.0]
16 |
17 | # default timeout for all `expectXXX` assertions outside of within() block
18 | single-expect-default = 1s
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/docs/src/paradox/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: main-index
3 | ---
4 |
5 | # swave
6 |
7 | 
8 |
9 | # Fast and Lightweight Streaming in [Scala][1]
10 |
11 |
12 |
13 | *swave* is an experimental open-source library for high-performance streaming in [Scala][1].
14 | Being lightweight, flexible and fully [Reactive-Streams][2]-compliant
15 | it's a great tool for implementing any type of stream-based logic in [Scala][1].
16 |
17 | [1]: http://www.scala-lang.org/
18 | [2]: http://www.reactive-streams.org/
19 |
20 |
21 |
22 | @@@index
23 |
24 | * [-](introduction/index.md)
25 | * [-](usage/index.md)
26 | * [-](dev/index.md)
27 | * [-](project/index.md)
28 | * [-](support.md)
29 |
30 | @@@
31 |
32 | @@toc { depth=3 }
--------------------------------------------------------------------------------
/core-tests/src/test/scala/swave/core/tck/ToPublisherDrainSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.tck
8 |
9 | import org.reactivestreams.Publisher
10 | import swave.core._
11 |
12 | // due to long runtime this test is disabled by default, remove parameter to enable the test
13 | class ToPublisherDrainSpec(dontRun: Any) extends SwavePublisherVerification[Int] {
14 |
15 | implicit val env = StreamEnv()
16 |
17 | def createPublisher(elements: Long): Publisher[Int] =
18 | Spout.ints(0).take(elements).drainTo(Drain.toPublisher()).get
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/IntInt.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | final class IntInt(val longValue: Long) extends AnyVal {
10 | def _1: Int = (longValue >>> 32).toInt
11 | def _2: Int = (longValue & 0xFFFFFFFF).toInt
12 |
13 | def toTuple: (Int, Int) = (_1, _2)
14 |
15 | // extraction support
16 | def isEmpty: Boolean = false
17 | def get: (Int, Int) = toTuple
18 | }
19 |
20 | object IntInt {
21 | def apply(i1: Int, i2: Int): IntInt = new IntInt(i1.toLong << 32 | i2.toLong)
22 |
23 | def unapply(ii: IntInt): IntInt = ii
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/StreamTermination.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages
8 |
9 | private[stages] abstract class StreamTermination {
10 | def transitionTo(to: StreamTermination): StreamTermination = this
11 | }
12 |
13 | private[stages] object StreamTermination {
14 | case object None extends StreamTermination {
15 | override def transitionTo(to: StreamTermination): StreamTermination = to
16 | }
17 | case object Completed extends StreamTermination
18 | final case class Error(e: Throwable) extends StreamTermination
19 | }
20 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/Cancellable.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | trait Cancellable {
10 |
11 | /**
12 | * Cancels this instance and returns true if that was successful,
13 | * i.e. if the instance was not already expired or cancelled.
14 | */
15 | def cancel(): Boolean
16 |
17 | /**
18 | * Returns false if this instance is not active (anymore).
19 | */
20 | def stillActive: Boolean
21 |
22 | }
23 |
24 | object Cancellable {
25 |
26 | val Inactive = new Cancellable {
27 | def cancel() = false
28 | def stillActive = false
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/project/plugins.sbt:
--------------------------------------------------------------------------------
1 | scalacOptions += "-deprecation"
2 |
3 | addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "0.6.6")
4 | addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.1")
5 | addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.6.1")
6 | addSbtPlugin("de.heikoseeberger" % "sbt-header" % "1.8.0")
7 | addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.4")
8 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.1")
9 | addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.0")
10 | addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.1.0")
11 | addSbtPlugin("com.lightbend.paradox" % "sbt-paradox" % "0.2.8")
12 | addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.2.0")
13 | addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.0")
--------------------------------------------------------------------------------
/docs/src/paradox/_template/assets/js/theme.init.js:
--------------------------------------------------------------------------------
1 | hljs.initHighlightingOnLoad();
2 |
3 | // Tooltip
4 | (function($) {
5 |
6 | 'use strict';
7 |
8 | if ( $.isFunction( $.fn['tooltip'] ) ) {
9 | $( '[data-toggle=tooltip],[rel=tooltip]' ).tooltip({ container: 'body' });
10 | }
11 |
12 | }).apply(this, [jQuery]);
13 |
14 | // Scrollable
15 | (function($) {
16 |
17 | 'use strict';
18 |
19 | if ( $.isFunction($.fn[ 'nanoScroller' ]) ) {
20 |
21 | $(function() {
22 | $('[data-plugin-scrollable]').each(function() {
23 | var $this = $( this ),
24 | opts = {};
25 |
26 | var pluginOptions = $this.data('plugin-options');
27 | if (pluginOptions) {
28 | opts = pluginOptions;
29 | }
30 |
31 | $this.themePluginScrollable(opts);
32 | });
33 | });
34 |
35 | }
36 |
37 | }).apply(this, [jQuery]);
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/CallingThreadExecutionContext.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl
8 |
9 | import scala.concurrent.ExecutionContext
10 |
11 | /**
12 | * [[ExecutionContext]] which runs everything on the calling thread.
13 | * Only use it for non-blocking and non-throwing tasks!
14 | */
15 | private[swave] object CallingThreadExecutionContext extends ExecutionContext {
16 |
17 | def execute(runnable: Runnable): Unit = runnable.run()
18 |
19 | override def reportFailure(t: Throwable): Unit =
20 | throw new IllegalStateException("Exception in CallingThreadExecutionContext", t)
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichHList.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import scala.annotation.tailrec
10 | import shapeless._
11 |
12 | import scala.collection.mutable.ListBuffer
13 |
14 | final class RichHList[L <: HList](val underlying: L) extends AnyVal {
15 |
16 | def toUntypedList: List[Any] = {
17 | val buf = new ListBuffer[Any]
18 | @tailrec def rec(remaining: HList): List[Any] =
19 | remaining match {
20 | case HNil ⇒ buf.toList
21 | case head :: tail ⇒
22 | buf += head
23 | rec(tail)
24 | }
25 | rec(underlying)
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/swave-scodec-compat/index.md:
--------------------------------------------------------------------------------
1 | swave-scodec-compat
2 | ===================
3 |
4 | The `swave-scodec-compat` modules provides for very easy interconnectivity between *swave* and [scodec].
5 |
6 | Currently all it contains is an implementation of the `Bytes[T]` type class for @scaladoc[scodec.bits.ByteVector].
7 | (See @ref[this section](../domain/file-io.md#the-bytes-t-type-class) for details.)
8 |
9 | You enable `Bytes` support for @scaladoc[scodec.bits.ByteVector] with this import
10 |
11 | ```scala
12 | import swave.compat.scodec.byteVectorBytes
13 | ```
14 |
15 |
16 | API Docs (ScalaDoc)
17 | -------------------
18 |
19 | The ScalaDoc for *swave-scodec-compat* can be found @scaladoc[>>> HERE <<<](swave.compat.scodec.index).
20 |
21 |
22 | [scodec]: http://scodec.org/
23 | [scodec.bits.ByteVector]: scodec.bits.ByteVector
--------------------------------------------------------------------------------
/core-tests/src/test/scala/swave/core/tck/IdentityProcessorSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.tck
8 |
9 | import org.reactivestreams.Processor
10 | import swave.core.{Pipe, StreamEnv}
11 |
12 | // due to long runtime this test is disabled by default, remove parameter to enable the test
13 | class IdentityProcessorSpec(dontRun: Any) extends SwaveIdentityProcessorVerification[Int] {
14 |
15 | implicit val env = StreamEnv()
16 |
17 | override def createIdentityProcessor(maxBufferSize: Int): Processor[Int, Int] =
18 | Pipe[Int].toProcessor.run().result.get
19 |
20 | override def createElement(element: Int): Int = element
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/StreamEvent.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | sealed abstract class StreamEvent[+T]
10 | object StreamEvent {
11 | sealed abstract class UpEvent extends StreamEvent[Nothing]
12 | sealed abstract class DownEvent[+T] extends StreamEvent[T]
13 |
14 | final case class Request(elements: Int) extends UpEvent
15 | case object Cancel extends UpEvent
16 |
17 | final case class OnNext[T](value: T) extends DownEvent[T]
18 | case object OnComplete extends DownEvent[Nothing]
19 | final case class OnError(cause: Throwable) extends DownEvent[Nothing]
20 | }
21 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichInt.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import scala.annotation.tailrec
10 | import swave.core.macros._
11 |
12 | private[swave] class RichInt(private val underlying: Int) extends AnyVal {
13 |
14 | /**
15 | * Allows for something like
16 | * {{{
17 | * 5.times(println("Hello"))
18 | * }}}
19 | */
20 | def times(block: ⇒ Unit): Unit = {
21 | requireArg(underlying >= 0, s"`$underlying.times(...)` is illegal")
22 | @tailrec def rec(i: Int): Unit =
23 | if (i > 0) {
24 | block
25 | rec(i - 1)
26 | }
27 | rec(underlying)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/DrainStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages
8 |
9 | import scala.annotation.compileTimeOnly
10 | import swave.core.Stage
11 | import swave.core.impl.Inport
12 |
13 | // format: OFF
14 | private[swave] abstract class DrainStage extends StageImpl {
15 |
16 | def kind: Stage.Kind.Drain
17 |
18 | protected var _inputStages: List[Stage] = Nil
19 |
20 | override def inputStages: List[Stage] = _inputStages
21 | final def outputStages: List[Stage] = Nil
22 |
23 | @compileTimeOnly("Unresolved `connectInAndSealWith` call")
24 | protected final def connectInAndSealWith(f: Inport ⇒ State): Unit = ()
25 | }
--------------------------------------------------------------------------------
/core-tests/src/test/scala/swave/core/hash/HashTransformationSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.hash
8 |
9 | import scodec.bits.ByteVector
10 | import swave.compat.scodec._
11 | import swave.core._
12 |
13 | class HashTransformationSpec extends SwaveSpec {
14 | import swave.core.text._
15 |
16 | implicit val env = StreamEnv()
17 |
18 | "HashTransformations" - {
19 |
20 | "md5" in {
21 | Spout
22 | .one("swave rocks!")
23 | .utf8Encode
24 | .md5
25 | .drainToHead()
26 | .value
27 | .get
28 | .get shouldEqual ByteVector.fromHex("e1b2b603f9cca4a909c07d42a5788fe3").get
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/further/best-practices.md:
--------------------------------------------------------------------------------
1 | Best Practices
2 | ==============
3 |
4 | In this chapter we collect general recommendations that have proven to be helpful when working with backpressured
5 | streams in general as well as *swave* in particular.
6 |
7 |
8 | Prefer `def` over `val`
9 | -----------------------
10 |
11 | One simple way to deal with the non-reusability of *swave's* stream components is to model them as a `def` rather than
12 | a `val` wherever reuse is desired, e.g. like this:
13 |
14 | @@snip [-]($test$/BasicSpec.scala) { #reuse }
15 |
16 | Apart from ensuring that you'll never see an @scaladoc[IllegalReuseException] it also has the benefit that
17 | parameterizing your higher-level stream constructs becomes trivial (as all that's required is giving the `def` a
18 | parameter list).
19 |
20 |
21 | [IllegalReuseException]: swave.core.IllegalReuseException
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/SpoutStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages
8 |
9 | import scala.annotation.compileTimeOnly
10 | import swave.core.Stage
11 | import swave.core.impl.Outport
12 |
13 | // format: OFF
14 | private[swave] abstract class SpoutStage extends StageImpl {
15 |
16 | def kind: Stage.Kind.Spout
17 |
18 | protected var _outputStages: List[Stage] = Nil
19 |
20 | final def inputStages: List[Stage] = Nil
21 | override def outputStages: List[Stage] = _outputStages
22 |
23 | @compileTimeOnly("Unresolved `connectOutAndSealWith` call")
24 | protected final def connectOutAndSealWith(f: Outport ⇒ State): Unit = ()
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/drain/CancellingDrainStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.drain
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.Inport
11 | import swave.core.impl.stages.DrainStage
12 | import swave.core.macros.StageImplementation
13 |
14 | // format: OFF
15 | @StageImplementation
16 | private[core] final class CancellingDrainStage extends DrainStage {
17 |
18 | def kind = Stage.Kind.Drain.Cancelling
19 |
20 | connectInAndSealWith { in ⇒
21 | region.impl.registerForXStart(this)
22 | awaitingXStart(in)
23 | }
24 |
25 | /**
26 | * @param in the active upstream
27 | */
28 | def awaitingXStart(in: Inport) =
29 | state(xStart = () => stopCancel(in))
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/BreakOutTo.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import scala.collection.generic.CanBuildFrom
10 |
11 | /**
12 | * Enables fluent (inline) type breakout in chains of collection transformations, e.g.
13 | * {{{
14 | * scala> Vector(1, 2, 3).map(_ + 10)(BreakOutTo[List].here).reverse
15 | * res0: List[Int] = List(13, 12, 11)
16 | * }}}
17 | */
18 | final class BreakOutTo[M[_]] private {
19 | def here[From, T](implicit b: CanBuildFrom[Nothing, T, M[T]]): CanBuildFrom[From, T, M[T]] = collection.breakOut
20 | }
21 |
22 | object BreakOutTo {
23 | private val instance = new BreakOutTo[shapeless.Id]
24 |
25 | def apply[M[_]]: BreakOutTo[M] = instance.asInstanceOf[BreakOutTo[M]]
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/test/scala/swave/core/util/RichListSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import org.scalacheck.Gen
10 | import org.scalatest.{FreeSpec, Matchers}
11 | import org.scalatest.prop.GeneratorDrivenPropertyChecks
12 |
13 | class RichListSpec extends FreeSpec with Matchers with GeneratorDrivenPropertyChecks {
14 |
15 | "RichList" - {
16 |
17 | "fastReverse" in {
18 | forAll { (list: List[Int]) ⇒
19 | list.fastReverse shouldEqual list.reverse
20 | }
21 | }
22 |
23 | "remove" in {
24 | forAll(Gen.choose(0, 5), Gen.choose(0, 4)) { (n: Int, x: Int) ⇒
25 | val list = List.tabulate(n)(identity)
26 | list.remove(x) shouldEqual list.filterNot(_ == x)
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/FanInStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages
8 |
9 | import scala.annotation.compileTimeOnly
10 | import swave.core.Stage
11 | import swave.core.impl.util.InportList
12 | import swave.core.impl.Outport
13 |
14 | // format: OFF
15 | private[core] abstract class FanInStage(subs: InportList) extends StageImpl {
16 |
17 | override def kind: Stage.Kind.FanIn
18 |
19 | protected final var _outputStages: List[Stage] = Nil
20 |
21 | final val inputStages: List[Stage] = subs.toStageList
22 | final def outputStages: List[Stage] = _outputStages
23 |
24 | @compileTimeOnly("Unresolved `connectFanInAndSealWith` call")
25 | protected final def connectFanInAndSealWith(f: Outport ⇒ State): Unit = ()
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/InOutStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages
8 |
9 | import scala.annotation.compileTimeOnly
10 | import swave.core.Stage
11 | import swave.core.impl.{Inport, Outport}
12 |
13 | // format: OFF
14 | private[core] abstract class InOutStage extends StageImpl {
15 |
16 | override def kind: Stage.Kind
17 |
18 | protected final var _inputStages: List[Stage] = Nil
19 | protected final var _outputStages: List[Stage] = Nil
20 |
21 | final def inputStages: List[Stage] = _inputStages
22 | final def outputStages: List[Stage] = _outputStages
23 |
24 | @compileTimeOnly("Unresolved `connectInOutAndSealWith` call")
25 | protected final def connectInOutAndSealWith(f: (Inport, Outport) ⇒ State): Unit = ()
26 | }
27 |
--------------------------------------------------------------------------------
/core-tests/src/test/scala/swave/core/DisconnectedGraphSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | import swave.testkit.Probes._
10 |
11 | class DisconnectedGraphSpec extends SwaveSpec {
12 |
13 | implicit val env = StreamEnv()
14 |
15 | "Disconnected graphs (forests) should" - {
16 |
17 | "work as expected" in {
18 | val drain = Drain.toPublisher[Int]()
19 | val spout = Spout.fromPublisher(drain.result)
20 |
21 | Spout(1, 2, 3)
22 | .map(_ * 2)
23 | .via(Pipe.fromDrainAndSpout(drain.dropResult, spout))
24 | .filter(_ < 10)
25 | .drainTo(DrainProbe[Int])
26 | .get
27 | .sendRequest(5)
28 | .expectNext(2, 4, 6)
29 | .expectComplete()
30 | .verifyCleanStop()
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/util/SettingsCompanion.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.util
8 |
9 | import com.typesafe.config.Config
10 | import swave.core.ConfigurationException
11 |
12 | private[swave] abstract class SettingsCompanion[T](prefix: String) {
13 | import com.typesafe.config.ConfigFactory._
14 |
15 | def apply(configOverrides: String, classLoader: ClassLoader = getClass.getClassLoader): T =
16 | apply(parseString(configOverrides).withFallback(defaultReference(classLoader)))
17 |
18 | def apply(config: Config): T =
19 | try fromSubConfig(config getConfig prefix)
20 | catch { case e: IllegalArgumentException ⇒ configError(e.getMessage) }
21 |
22 | def fromSubConfig(c: Config): T
23 |
24 | def configError(msg: String): Nothing = throw new ConfigurationException(msg)
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/NopStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.stages.InOutStage
11 | import swave.core.impl.{Inport, Outport}
12 | import swave.core.macros.StageImplementation
13 |
14 | // format: OFF
15 | @StageImplementation
16 | private[core] final class NopStage extends InOutStage {
17 |
18 | def kind = Stage.Kind.InOut.Nop
19 |
20 | connectInOutAndSealWith { (in, out) ⇒
21 | region.impl.requestBridging(in, this, out)
22 | running(in, out)
23 | }
24 |
25 | def running(in: Inport, out: Outport) = state(
26 | intercept = false,
27 |
28 | request = requestF(in),
29 | cancel = stopCancelF(in),
30 | onNext = onNextF(out),
31 | onComplete = stopCompleteF(out),
32 | onError = stopErrorF(out))
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/CouplingStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.stages.InOutStage
11 | import swave.core.impl.{Inport, Outport}
12 | import swave.core.macros.StageImplementation
13 |
14 | // format: OFF
15 | @StageImplementation
16 | private[core] final class CouplingStage extends InOutStage {
17 |
18 | def kind = Stage.Kind.InOut.Coupling
19 |
20 | connectInOutAndSealWith { (in, out) ⇒
21 | region.impl.requestBridging(in, this, out)
22 | running(in, out)
23 | }
24 |
25 | def running(in: Inport, out: Outport) = state(
26 | intercept = false,
27 |
28 | request = requestF(in),
29 | cancel = stopCancelF(in),
30 | onNext = onNextF(out),
31 | onComplete = stopCompleteF(out),
32 | onError = stopErrorF(out))
33 | }
34 |
--------------------------------------------------------------------------------
/testkit/src/main/scala/swave/testkit/ExpectationFailedException.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.testkit
8 |
9 | final class ExpectationFailedException(msg: String) extends RuntimeException(msg)
10 |
11 | object ExpectationFailedException {
12 | def apply(received: Option[Any], expected: Option[Any]): ExpectationFailedException = {
13 | val msg = (received, expected) match {
14 | case (Some(r), Some(e)) ⇒ s"Received `$r` but expected `$e`"
15 | case (None, Some(e)) ⇒ s"Received nothing but expected `$e`"
16 | case (Some(r), None) ⇒ s"Received `$r` when no signal was expected"
17 | case (None, None) ⇒ throw new IllegalStateException
18 | }
19 | new ExpectationFailedException("Test expectation failed: " + msg)
20 | }
21 |
22 | def apply(msg: String): ExpectationFailedException = new ExpectationFailedException(msg)
23 | }
24 |
--------------------------------------------------------------------------------
/docs/src/test/scala/swave/docs/SimpleTransformSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.docs
8 |
9 | import org.scalatest.{FreeSpec, Matchers}
10 |
11 | class SimpleTransformSpec extends FreeSpec with Matchers {
12 |
13 | "the examples in the `simple transformations` chapter should work as expected" - {
14 |
15 | "example" in {
16 | //#example
17 | import scala.concurrent.Future
18 | import swave.core._
19 |
20 | implicit val env = StreamEnv()
21 |
22 | val result: Future[String] =
23 | Spout(1, 2, 3, 4, 5) // Spout[Int]
24 | .map(_ * 2) // Spout[Int]
25 | .filter(_ > 5) // Spout[Int]
26 | .reduce(_ + _) // Spout[Int]
27 | .map(_.toString) // Spout[String]
28 | .drainToHead() // Future[String]
29 |
30 | result.value.get.get shouldEqual "24"
31 | //#example
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/core-tests/src/test/scala/swave/core/impl/stages/LazyStartSpoutSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages
8 |
9 | import org.scalacheck.Gen
10 | import org.scalatest.Inspectors
11 | import swave.core._
12 |
13 | final class LazyStartSpoutSpec extends SyncPipeSpec with Inspectors {
14 |
15 | implicit val env = StreamEnv()
16 | implicit val config = PropertyCheckConfiguration(minSuccessful = 100)
17 |
18 | implicit val integerInput = Gen.chooseNum(0, 999)
19 |
20 | "Spout.lazy" in check {
21 | testSetup
22 | .input[Int]
23 | .output[String]
24 | .prop
25 | .from { (in, out) ⇒
26 | Spout
27 | .lazyStart(() ⇒ in.spout)
28 | .map(_.toString)
29 | .drainTo(out.drain) shouldTerminate asScripted(in)
30 |
31 | out.received shouldEqual in.produced.take(out.scriptedSize).map(_.toString)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/fanout/FanOutAnyStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.fanout
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.{Inport, Outport}
11 | import swave.core.impl.stages.FanOutStage
12 |
13 | private[core] final class FanOutAnyStage(eagerCancel: Boolean) extends FanOutStage {
14 |
15 | def kind = Stage.Kind.FanOut.FirstAvailable(eagerCancel)
16 |
17 | type OutportCtx = FanOutStage.SimpleOutportContext
18 |
19 | protected def createOutportCtx(out: Outport, tail: OutportCtx): OutportCtx =
20 | new FanOutStage.SimpleOutportContext(out, tail)
21 |
22 | override def hasInport(in: Inport): Boolean = ???
23 | override def hasOutport(out: Outport): Boolean = ???
24 | override def rewireIn(from: Inport, to: Inport): Unit = ???
25 | override def rewireOut(from: Outport, to: Outport): Unit = ???
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/spout/RepeatSpoutStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.spout
8 |
9 | import scala.annotation.tailrec
10 | import swave.core.macros.StageImplementation
11 | import swave.core.Stage
12 | import swave.core.impl.Outport
13 | import swave.core.impl.stages.SpoutStage
14 |
15 | // format: OFF
16 | @StageImplementation(interceptAllRequests = true)
17 | private[core] final class RepeatSpoutStage(element: AnyRef) extends SpoutStage {
18 |
19 | def kind = Stage.Kind.Spout.Repeat(element)
20 |
21 | connectOutAndSealWith { out ⇒ running(out) }
22 |
23 | def running(out: Outport): State = state(
24 | request = (n, _) ⇒ {
25 | @tailrec def rec(n: Int): State =
26 | if (n > 0) {
27 | out.onNext(element)
28 | rec(n - 1)
29 | } else stay()
30 | rec(n)
31 | },
32 |
33 | cancel = stopF)
34 | }
35 |
--------------------------------------------------------------------------------
/core/src/test/scala/swave/core/util/RichLongSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import org.scalatest.prop.GeneratorDrivenPropertyChecks
10 | import org.scalatest.{FreeSpec, Matchers}
11 |
12 | class RichLongSpec extends FreeSpec with Matchers with GeneratorDrivenPropertyChecks {
13 |
14 | "RichLong" - {
15 | val longMin = BigDecimal(Long.MinValue)
16 | val longMax = BigDecimal(Long.MaxValue)
17 | def bounded(d: BigDecimal) =
18 | if (d < longMin) Long.MinValue
19 | else if (d > longMax) Long.MaxValue
20 | else d.longValue()
21 |
22 | "⊹" in {
23 | forAll { (x: Long, y: Long) ⇒
24 | x ⊹ y shouldEqual bounded(BigDecimal(x) + BigDecimal(y))
25 | }
26 | }
27 |
28 | "×" in {
29 | forAll { (x: Long, y: Long) ⇒
30 | (x × y) shouldEqual bounded(BigDecimal(x) * BigDecimal(y))
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/Coupling.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | import swave.core.impl.stages.inout.CouplingStage
10 | import swave.core.util.AnyRefExtractor.Extraction
11 |
12 | /**
13 | * A simple streaming component with one input, one output port and no internal transformation logic.
14 | *
15 | * It is typically used to manually connect two ports of a stream graph that cannot
16 | * be otherwise connected via the streaming DSL, e.g. for creating cycles.
17 | */
18 | final class Coupling[T] private {
19 | private[this] val stage = new CouplingStage
20 |
21 | val in: Drain[T, Unit] = Drain(stage)
22 | val out: Spout[T] = new Spout(stage)
23 | }
24 |
25 | object Coupling {
26 | def apply[T]: Coupling[T] = new Coupling[T]
27 |
28 | def unapply[T](value: Coupling[T]): Extraction[(Drain[T, Unit], Spout[T])] =
29 | new Extraction(value.in -> value.out)
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/fanout/FanOutRoundRobinStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.fanout
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.{Inport, Outport}
11 | import swave.core.impl.stages.FanOutStage
12 |
13 | private[core] final class FanOutRoundRobinStage(eagerCancel: Boolean) extends FanOutStage {
14 |
15 | def kind = Stage.Kind.FanOut.RoundRobin(eagerCancel)
16 |
17 | type OutportCtx = FanOutStage.SimpleOutportContext
18 |
19 | protected def createOutportCtx(out: Outport, tail: OutportCtx): OutportCtx =
20 | new FanOutStage.SimpleOutportContext(out, tail)
21 |
22 | override def hasInport(in: Inport): Boolean = ???
23 | override def hasOutport(out: Outport): Boolean = ???
24 | override def rewireIn(from: Inport, to: Inport): Unit = ???
25 | override def rewireOut(from: Outport, to: Outport): Unit = ???
26 | }
27 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/spout/FailingSpoutStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.spout
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.Outport
11 | import swave.core.impl.stages.SpoutStage
12 | import swave.core.macros.StageImplementation
13 |
14 | // format: OFF
15 | @StageImplementation
16 | private[core] final class FailingSpoutStage(error: Throwable, eager: Boolean) extends SpoutStage {
17 |
18 | def kind = Stage.Kind.Spout.Failing(error, eager)
19 |
20 | connectOutAndSealWith { out ⇒
21 | if (eager) {
22 | region.impl.registerForXStart(this)
23 | awaitingXStart(out)
24 | } else awaitingRequest(out)
25 | }
26 |
27 | def awaitingXStart(out: Outport) = state(
28 | xStart = () => stopError(error, out))
29 |
30 | def awaitingRequest(out: Outport) = state(
31 | request = (_, _) => stopError(error, out),
32 | cancel = _ => stop())
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/fanout/FanOutSwitchStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.fanout
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.{Inport, Outport}
11 | import swave.core.impl.stages.FanOutStage
12 |
13 | private[core] final class FanOutSwitchStage(branchCount: Int, f: AnyRef ⇒ Int, eagerCancel: Boolean)
14 | extends FanOutStage {
15 |
16 | def kind = Stage.Kind.FanOut.Switch(branchCount, f, eagerCancel)
17 |
18 | type OutportCtx = FanOutStage.SimpleOutportContext
19 |
20 | protected def createOutportCtx(out: Outport, tail: OutportCtx): OutportCtx =
21 | new FanOutStage.SimpleOutportContext(out, tail)
22 |
23 | override def hasInport(in: Inport): Boolean = ???
24 | override def hasOutport(out: Outport): Boolean = ???
25 | override def rewireIn(from: Inport, to: Inport): Unit = ???
26 | override def rewireOut(from: Outport, to: Outport): Unit = ???
27 | }
28 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | swave
2 | =====
3 |
4 | **swave** is an experimental open-source library for high-performance streaming in Scala.
5 |
6 | .. image:: https://travis-ci.org/sirthias/swave.svg?branch=master
7 | :target: https://travis-ci.org/sirthias/swave
8 | :alt: Current build status
9 |
10 | .. image:: https://coveralls.io/repos/github/sirthias/swave/badge.svg
11 | :target: https://coveralls.io/github/sirthias/swave
12 | :alt: Test coverage
13 |
14 | .. image:: https://img.shields.io/maven-central/v/io.swave/swave-core_2.11.svg
15 | :target: https://maven-badges.herokuapp.com/maven-central/io.swave/swave-core_2.11
16 | :alt: The latest swave artifacts on Maven Central
17 |
18 | .. image:: https://img.shields.io/badge/mailing%20list-active-brightgreen.svg
19 | :target: https://groups.google.com/forum/#!forum/swave-user
20 | :alt: Mailing list for swave users
21 |
22 | .. image:: https://img.shields.io/gitter/room/nwjs/nw.js.svg?maxAge=86400
23 | :target: https://gitter.im/sirthias/swave
24 | :alt: Gitter chat for swave
25 |
26 | .. image:: https://img.shields.io/badge/uses-badges-ff69b4.svg
27 | :target: http://shields.io/
28 | :alt: uses badges
29 |
--------------------------------------------------------------------------------
/testkit/src/main/scala/swave/testkit/Testkit.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.testkit
8 |
9 | import com.typesafe.config.Config
10 | import swave.core.impl.util.SettingsCompanion
11 | import swave.core.macros._
12 |
13 | object Testkit {
14 |
15 | final case class Settings(timingDefaults: Timing.Settings)
16 |
17 | object Settings extends SettingsCompanion[Settings]("swave.test") {
18 | def fromSubConfig(c: Config): Settings =
19 | Settings(timingDefaults = Timing.Settings fromSubConfig c.getConfig("timing"))
20 | }
21 |
22 | sealed abstract class Signal
23 |
24 | object Signal {
25 | final case class Request(n: Long) extends Signal { requireArg(n > 0, s"`n` must be > 0") }
26 | case object Cancel extends Signal
27 | final case class OnNext(value: Any) extends Signal
28 | case object OnComplete extends Signal
29 | final case class OnError(e: Throwable) extends Signal
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/core-macros/src/main/scala/swave/core/macros/ConnectInAndSealWith.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.macros
8 |
9 | private[macros] trait ConnectInAndSealWith { this: Util =>
10 | val c: scala.reflect.macros.whitebox.Context
11 | import c.universe._
12 |
13 | def connectInAndSealWith(f: Tree): List[Tree] = unblock {
14 | val q"($in0: $_) => $block0" = f
15 | val in = freshName("in")
16 | val block = replaceIdents(block0, in0 -> in)
17 |
18 | q"""
19 | initialState(awaitingOnSubscribe())
20 |
21 | def awaitingOnSubscribe() = state(
22 | intercept = false,
23 |
24 | onSubscribe = from ⇒ {
25 | _inputStages = from.stageImpl :: Nil
26 | ready(from)
27 | })
28 |
29 | def ready(in: Inport) = state(
30 | xSeal = () ⇒ {
31 | in.xSeal(region)
32 | val $in = in
33 | $block
34 | })
35 | """
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/hash/package.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | import java.security.MessageDigest
10 | import swave.core.io.Bytes
11 |
12 | package object hash {
13 |
14 | implicit class RichBytesStreamOpsHash[T, S[X] <: StreamOps[X]](val underlying: S[T]) extends AnyVal {
15 |
16 | def md2(implicit ev: Bytes[T]): S[T]#Repr[T] = underlying.via(Hash.md2[T])
17 | def md5(implicit ev: Bytes[T]): S[T]#Repr[T] = underlying.via(Hash.md5[T])
18 | def sha1(implicit ev: Bytes[T]): S[T]#Repr[T] = underlying.via(Hash.sha1[T])
19 | def sha256(implicit ev: Bytes[T]): S[T]#Repr[T] = underlying.via(Hash.sha256[T])
20 | def sha384(implicit ev: Bytes[T]): S[T]#Repr[T] = underlying.via(Hash.sha384[T])
21 | def sha512(implicit ev: Bytes[T]): S[T]#Repr[T] = underlying.via(Hash.sha512[T])
22 |
23 | def digest(md: MessageDigest)(implicit ev: Bytes[T]): S[T]#Repr[T] =
24 | underlying.via(Hash.digest(md))
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/AsyncDispatcherStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.{Inport, Outport}
11 | import swave.core.impl.stages.InOutStage
12 | import swave.core.macros.StageImplementation
13 |
14 | // format: OFF
15 | @StageImplementation
16 | private[core] final class AsyncDispatcherStage(dispatcherId: String) extends InOutStage {
17 |
18 | def kind = Stage.Kind.InOut.AsyncDispatcher(dispatcherId)
19 |
20 | connectInOutAndSealWith { (in, out) ⇒
21 | region.impl.requestDispatcherAssignment(dispatcherId)
22 | region.impl.requestBridging(in, this, out)
23 | running(in, out)
24 | }
25 |
26 | def running(in: Inport, out: Outport) = state(
27 | intercept = false,
28 |
29 | request = requestF(in),
30 | cancel = stopCancelF(in),
31 | onNext = onNextF(out),
32 | onComplete = stopCompleteF(out),
33 | onError = stopErrorF(out))
34 | }
35 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/DeduplicateStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.stages.InOutStage
11 | import swave.core.impl.{Inport, Outport}
12 | import swave.core.macros.StageImplementation
13 |
14 | // format: OFF
15 | @StageImplementation
16 | private[core] final class DeduplicateStage extends InOutStage {
17 |
18 | def kind = Stage.Kind.InOut.Deduplicate
19 |
20 | connectInOutAndSealWith { (in, out) ⇒ running(in, out, this) }
21 |
22 | def running(in: Inport, out: Outport, last: AnyRef): State = state(
23 | request = requestF(in),
24 | cancel = stopCancelF(in),
25 |
26 | onNext = (elem, _) ⇒ {
27 | if (elem != last) {
28 | out.onNext(elem)
29 | running(in, out, elem)
30 | } else {
31 | in.request(1)
32 | stay()
33 | }
34 | },
35 |
36 | onComplete = stopCompleteF(out),
37 | onError = stopErrorF(out))
38 | }
39 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/transformations/couplings.md:
--------------------------------------------------------------------------------
1 | Couplings
2 | =========
3 |
4 | @scaladoc[Couplings] are @ref[stream graph components] with one input, one output and no internal transformation logic.
5 | They are typically used to manually connect two ports of a stream graph that cannot be otherwise connected via the
6 | streaming DSL, e.g. for creating cycles.
7 |
8 | @@@ div { .centered }
9 | 
10 | @@@
11 |
12 | A `Coupling` is essentially nothing but a @ref[Drain] and @ref[Spout] of the same element type that are directly
13 | connected to each other internally. You can use the two sides of the `Coupling` independently at arbitrary points
14 | in a stream graph definition to create connections where you need them.
15 |
16 | Here is an example of a stream that contains a cycle and therefore requires the use of a `Coupling`:
17 |
18 | @@snip [-]($test$/CouplingSpec.scala) { #fibonacci }
19 |
20 | (For an in-depth discussion of this stream setup check out the @ref[Fibonacci Example]!)
21 |
22 | [Couplings]: swave.core.Coupling
23 | [stream graph components]: ../basics.md#streams-as-graphs
24 | [Spout]: ../spouts.md
25 | [Drain]: ../drains.md
26 | [Fibonacci Example]: ../show-off/fibonacci.md
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichFuture.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import java.util.concurrent.TimeoutException
10 | import scala.concurrent.duration._
11 | import scala.concurrent.{Await, Future, Promise}
12 | import swave.core.StreamEnv
13 |
14 | final class RichFuture[T](val underlying: Future[T]) extends AnyVal {
15 |
16 | def await(timeout: FiniteDuration = 1.second): T =
17 | underlying.value match {
18 | case Some(t) ⇒ t.get
19 | case None if timeout == Duration.Zero ⇒ throw new TimeoutException(s"Future was not completed")
20 | case _ ⇒ Await.result(underlying, timeout)
21 | }
22 |
23 | def delay(duration: FiniteDuration)(implicit env: StreamEnv): Future[T] = {
24 | import env.defaultDispatcher
25 | val promise = Promise[T]()
26 | underlying.onComplete { value ⇒
27 | env.scheduler.scheduleOnce(duration) { promise.complete(value); () }
28 | }
29 | promise.future
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichArrayBuffer.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import scala.annotation.tailrec
10 | import scala.collection.mutable
11 |
12 | final class RichArrayBuffer[A](val underlying: mutable.ArrayBuffer[A]) extends AnyVal {
13 |
14 | def inplaceSortBy[B](f: A ⇒ B)(implicit ord: Ordering[B]): Unit = {
15 | val buf = underlying.asInstanceOf[mutable.ArrayBuffer[AnyRef]]
16 | val array = buf.toArray
17 | java.util.Arrays.sort(array, ord.on(f).asInstanceOf[Ordering[AnyRef]])
18 | buf.clear()
19 | buf ++= array
20 | ()
21 | }
22 |
23 | def removeWhere(f: A ⇒ Boolean): Unit = {
24 | @tailrec def rec(ix: Int): Unit =
25 | if (ix >= 0) {
26 | if (f(underlying(ix))) underlying.remove(ix)
27 | rec(ix - 1)
28 | }
29 | rec(underlying.size - 1)
30 | }
31 |
32 | def removeIfPresent(elem: A): Unit =
33 | underlying.indexOf(elem) match {
34 | case -1 ⇒
35 | case ix ⇒ { underlying.remove(ix); () }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/docs/src/test/scala/swave/docs/CouplingSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.docs
8 |
9 | import org.scalatest.{FreeSpec, Matchers}
10 |
11 | class CouplingSpec extends FreeSpec with Matchers {
12 |
13 | "the examples in the `couplings` chapter should work as expected" - {
14 |
15 | "fibonacci" in {
16 | //#fibonacci
17 | import scala.concurrent.Future
18 | import swave.core._
19 |
20 | implicit val env = StreamEnv()
21 |
22 | def fibonacciNumbers = {
23 | val c = Coupling[Int]
24 | Spout(0, 1)
25 | .concat(c.out)
26 | .fanOutBroadcast(eagerCancel = true)
27 | .sub.buffer(2, Buffer.RequestStrategy.Always).sliding(2).map(_.sum).to(c.in)
28 | .subContinue
29 | }
30 |
31 | val result: Future[List[Int]] =
32 | fibonacciNumbers
33 | .take(8)
34 | .drainToList(limit = 100)
35 |
36 | result.value.get.get shouldEqual List(0, 1, 1, 2, 3, 5, 8, 13)
37 | //#fibonacci
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/core-macros/src/main/scala/swave/core/macros/ConnectOutAndSealWith.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.macros
8 |
9 | private[macros] trait ConnectOutAndSealWith { this: Util =>
10 | val c: scala.reflect.macros.whitebox.Context
11 | import c.universe._
12 |
13 | def connectOutAndSealWith(f: Tree): List[Tree] = unblock {
14 | val q"($out0: $_) => $block0" = f
15 | val out = freshName("out")
16 | val block = replaceIdents(block0, out0 -> out)
17 |
18 | q"""
19 | initialState(awaitingSubscribe())
20 |
21 | def awaitingSubscribe() = state(
22 | intercept = false,
23 |
24 | subscribe = from ⇒ {
25 | _outputStages = from.stageImpl :: Nil
26 | from.onSubscribe()
27 | ready(from)
28 | })
29 |
30 | def ready(out: Outport) = state(
31 | intercept = false,
32 |
33 | xSeal = () ⇒ {
34 | out.xSeal(region)
35 | val $out = out
36 | $block
37 | })
38 | """
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/Dispatchers.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | import com.typesafe.config.Config
10 | import scala.collection.JavaConverters._
11 | import swave.core.impl.util.SettingsCompanion
12 |
13 | abstract class Dispatchers private[core] {
14 |
15 | def settings: Dispatchers.Settings
16 |
17 | def defaultDispatcher: Dispatcher
18 |
19 | def apply(id: String): Dispatcher
20 | }
21 |
22 | object Dispatchers {
23 |
24 | final case class Settings(dispatcherDefs: Map[String, Dispatcher.Settings])
25 |
26 | object Settings extends SettingsCompanion[Settings]("swave.core.dispatcher") {
27 | def fromSubConfig(c: Config): Settings = {
28 | val defConf = c getConfig "default-config"
29 | val definition = c getConfig "definition"
30 | Settings {
31 | definition.root().keySet().iterator().asScala.foldLeft(Map.empty[String, Dispatcher.Settings]) { (map, name) ⇒
32 | map.updated(name, Dispatcher.Settings(name, definition getConfig name, defConf))
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/docs/src/paradox/project/license.md:
--------------------------------------------------------------------------------
1 | License
2 | =======
3 |
4 | *swave* is released under the [MPL 2.0][1], which is a simple and modern weak [copyleft][2] license.
5 |
6 | Here is the gist of the terms that are likely most important to you (disclaimer: the following points are not legally
7 | binding, only the license text itself is):
8 |
9 | If you'd like to use *swave* as a library in your own applications:
10 | : - ***swave* is safe for use in closed-source applications.**
11 | The MPL share-alike terms do not apply to applications built on top of or with the help of *swave*.
12 | : - **You do not need a commercial license.**
13 | The MPL applies to *swave's* own source code, not your applications.
14 |
15 | If you'd like to contribute to *swave*:
16 | : - You do not have to transfer any copyright.
17 | : - You do not have to sign a CLA.
18 | : - You can be sure that your contribution will always remain available in open-source form and
19 | will not *become* a closed-source commercial product (even though it might be *used* by such products!)
20 |
21 | For more background info on the license please also see the [official MPL 2.0 FAQ][3].
22 |
23 | [1]: https://www.mozilla.org/en-US/MPL/2.0/
24 | [2]: http://en.wikipedia.org/wiki/Copyleft
25 | [3]: https://www.mozilla.org/en-US/MPL/2.0/FAQ/
--------------------------------------------------------------------------------
/core/src/test/scala/swave/core/util/RichRefArraySpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import org.scalacheck.Gen
10 | import org.scalatest.prop.GeneratorDrivenPropertyChecks
11 | import org.scalatest.{FreeSpec, Matchers}
12 |
13 | class RichRefArraySpec extends FreeSpec with Matchers with GeneratorDrivenPropertyChecks {
14 |
15 | "RichRefArray" - {
16 | val stringArrays = Gen.containerOf[Array, String](Gen.alphaStr)
17 |
18 | "fastIndexOf" in {
19 | val arrayWithIndex =
20 | for {
21 | arr ← stringArrays
22 | ix ← Gen.chooseNum(0, arr.length + 1)
23 | } yield arr.map(Symbol(_)) → ix
24 |
25 | forAll(arrayWithIndex) {
26 | case (array, ix) ⇒
27 | val specimen = if (ix < array.length) array(ix) else 'foo
28 | array.fastIndexOf(specimen) shouldEqual array.indexOf(specimen)
29 | }
30 | }
31 |
32 | "reverse_!" in {
33 | forAll(stringArrays) { array ⇒
34 | val array2 = array.drop(0)
35 | array2.reverse_!()
36 | array2 shouldEqual array.reverse
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/show-off/overview.md:
--------------------------------------------------------------------------------
1 | Show-Off Overview
2 | =================
3 |
4 | In this section we'd like to show you a couple of hopefully illustrative examples that demonstrate how *swave* can be
5 | used to model real-world algorithms. If this is your first contact point with the *swave* documentation it could be
6 | that not all the code and the accompanying comments immediately make sense to you. However, in this case you should
7 | still be able to get a feel for what programming with *swave* looks like and maybe come back later, after having
8 | looked through subsequent chapters.
9 |
10 | These are the examples that are currently available:
11 |
12 | * @ref[MD5 Computation](md5.md)
13 | * @ref[Fahrenheit Conversion](fahrenheit.md)
14 | * @ref[Monte Carlo Pi](monte-carlo-pi.md)
15 | * @ref[Fibonacci](fibonacci.md)
16 |
17 |
18 | Contributions Welcome!
19 | ----------------------
20 |
21 | Since the range of possible applications for streaming with *swave* is so broad we are always looking for interesting
22 | examples to show here. So, if you think you have a nice and self-contained example that other users could benefit from
23 | we very much invite you to @ref[submit a PR][] (ideally referencing ticket number @github[#21](#21)) to include your
24 | example here.
25 |
26 |
27 | [submit a PR]: ../../project/contributing.md
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/lib/css/zenburn.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Zenburn style from voldmar.ru (c) Vladimir Epifanov
4 | based on dark.css by Ivan Sagalaev
5 |
6 | */
7 |
8 | .hljs {
9 | display: block;
10 | overflow-x: auto;
11 | padding: 0.5em;
12 | background: #3f3f3f;
13 | color: #dcdcdc;
14 | }
15 |
16 | .hljs-keyword,
17 | .hljs-selector-tag,
18 | .hljs-tag {
19 | color: #e3ceab;
20 | }
21 |
22 | .hljs-template-tag {
23 | color: #dcdcdc;
24 | }
25 |
26 | .hljs-number {
27 | color: #8cd0d3;
28 | }
29 |
30 | .hljs-variable,
31 | .hljs-template-variable,
32 | .hljs-attribute {
33 | color: #efdcbc;
34 | }
35 |
36 | .hljs-literal {
37 | color: #efefaf;
38 | }
39 |
40 | .hljs-subst {
41 | color: #8f8f8f;
42 | }
43 |
44 | .hljs-title,
45 | .hljs-name,
46 | .hljs-selector-id,
47 | .hljs-selector-class,
48 | .hljs-section,
49 | .hljs-type {
50 | color: #efef8f;
51 | }
52 |
53 | .hljs-symbol,
54 | .hljs-bullet,
55 | .hljs-link {
56 | color: #dca3a3;
57 | }
58 |
59 | .hljs-deletion,
60 | .hljs-string,
61 | .hljs-built_in,
62 | .hljs-builtin-name {
63 | color: #cc9393;
64 | }
65 |
66 | .hljs-addition,
67 | .hljs-comment,
68 | .hljs-quote,
69 | .hljs-meta {
70 | color: #7f9f7f;
71 | }
72 |
73 |
74 | .hljs-emphasis {
75 | font-style: italic;
76 | }
77 |
78 | .hljs-strong {
79 | font-weight: bold;
80 | }
81 |
--------------------------------------------------------------------------------
/docs/src/test/scala/swave/docs/DrainSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.docs
8 |
9 | import org.scalatest.{FreeSpec, Matchers}
10 |
11 | class DrainSpec extends FreeSpec with Matchers {
12 |
13 | "the examples in the `drains` chapter should work as expected" - {
14 |
15 | "examples" in {
16 | //#examples
17 | import scala.concurrent.Future
18 | import swave.core._
19 |
20 | implicit val env = StreamEnv()
21 |
22 | // a drain, which produces the sum of all `Int` elements it receives
23 | def sumDrain: Drain[Int, Future[Int]] =
24 | Drain.fold(0)(_ + _)
25 |
26 | Spout(1 to 100) // Spout[Int]
27 | .to(sumDrain) // StreamGraph[Int]
28 | .run() // StreamRun[Future[Int]
29 | .result // Future[Int]
30 | .value // Option[Try[Int]]
31 | .get // Try[Int]
32 | .get shouldEqual 5050
33 |
34 | // same but shorter
35 | Spout(1 to 100)
36 | .drainTo(sumDrain) // shortcut for `.to(sumDrain).run().result`
37 | .value.get.get shouldEqual 5050
38 | //#examples
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/lib/css/zenburn.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Zenburn style from voldmar.ru (c) Vladimir Epifanov
4 | based on dark.css by Ivan Sagalaev
5 |
6 | */
7 |
8 | .hljs {
9 | display: block;
10 | overflow-x: auto;
11 | padding: 0.5em;
12 | background: #3f3f3f;
13 | color: #dcdcdc;
14 | }
15 |
16 | .hljs-keyword,
17 | .hljs-selector-tag,
18 | .hljs-tag {
19 | color: #e3ceab;
20 | }
21 |
22 | .hljs-template-tag {
23 | color: #dcdcdc;
24 | }
25 |
26 | .hljs-number {
27 | color: #8cd0d3;
28 | }
29 |
30 | .hljs-variable,
31 | .hljs-template-variable,
32 | .hljs-attribute {
33 | color: #efdcbc;
34 | }
35 |
36 | .hljs-literal {
37 | color: #efefaf;
38 | }
39 |
40 | .hljs-subst {
41 | color: #8f8f8f;
42 | }
43 |
44 | .hljs-title,
45 | .hljs-name,
46 | .hljs-selector-id,
47 | .hljs-selector-class,
48 | .hljs-section,
49 | .hljs-type {
50 | color: #efef8f;
51 | }
52 |
53 | .hljs-symbol,
54 | .hljs-bullet,
55 | .hljs-link {
56 | color: #dca3a3;
57 | }
58 |
59 | .hljs-deletion,
60 | .hljs-string,
61 | .hljs-built_in,
62 | .hljs-builtin-name {
63 | color: #cc9393;
64 | }
65 |
66 | .hljs-addition,
67 | .hljs-comment,
68 | .hljs-quote,
69 | .hljs-meta {
70 | color: #7f9f7f;
71 | }
72 |
73 |
74 | .hljs-emphasis {
75 | font-style: italic;
76 | }
77 |
78 | .hljs-strong {
79 | font-weight: bold;
80 | }
81 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/lib/css/zenburn.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Zenburn style from voldmar.ru (c) Vladimir Epifanov
4 | based on dark.css by Ivan Sagalaev
5 |
6 | */
7 |
8 | .hljs {
9 | display: block;
10 | overflow-x: auto;
11 | padding: 0.5em;
12 | background: #3f3f3f;
13 | color: #dcdcdc;
14 | }
15 |
16 | .hljs-keyword,
17 | .hljs-selector-tag,
18 | .hljs-tag {
19 | color: #e3ceab;
20 | }
21 |
22 | .hljs-template-tag {
23 | color: #dcdcdc;
24 | }
25 |
26 | .hljs-number {
27 | color: #8cd0d3;
28 | }
29 |
30 | .hljs-variable,
31 | .hljs-template-variable,
32 | .hljs-attribute {
33 | color: #efdcbc;
34 | }
35 |
36 | .hljs-literal {
37 | color: #efefaf;
38 | }
39 |
40 | .hljs-subst {
41 | color: #8f8f8f;
42 | }
43 |
44 | .hljs-title,
45 | .hljs-name,
46 | .hljs-selector-id,
47 | .hljs-selector-class,
48 | .hljs-section,
49 | .hljs-type {
50 | color: #efef8f;
51 | }
52 |
53 | .hljs-symbol,
54 | .hljs-bullet,
55 | .hljs-link {
56 | color: #dca3a3;
57 | }
58 |
59 | .hljs-deletion,
60 | .hljs-string,
61 | .hljs-built_in,
62 | .hljs-builtin-name {
63 | color: #cc9393;
64 | }
65 |
66 | .hljs-addition,
67 | .hljs-comment,
68 | .hljs-quote,
69 | .hljs-meta {
70 | color: #7f9f7f;
71 | }
72 |
73 |
74 | .hljs-emphasis {
75 | font-style: italic;
76 | }
77 |
78 | .hljs-strong {
79 | font-weight: bold;
80 | }
81 |
--------------------------------------------------------------------------------
/core-tests/src/test/scala/swave/core/tck/SwavePublisherVerification.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.tck
8 |
9 | import org.reactivestreams.Publisher
10 | import org.reactivestreams.tck.{PublisherVerification, TestEnvironment}
11 | import org.scalatest.testng.TestNGSuiteLike
12 | import org.testng.SkipException
13 | import swave.core._
14 |
15 | abstract class SwavePublisherVerification[T](val testEnv: TestEnvironment, publisherShutdownTimeout: Long)
16 | extends PublisherVerification[T](testEnv, publisherShutdownTimeout) with TestNGSuiteLike with StreamEnvShutdown {
17 |
18 | def this(printlnDebug: Boolean) =
19 | this(
20 | new TestEnvironment(Timeouts.defaultTimeout.toMillis, printlnDebug),
21 | Timeouts.publisherShutdownTimeout.toMillis)
22 |
23 | def this() = this(false)
24 |
25 | override def createFailedPublisher(): Publisher[T] =
26 | Spout.failing[T](new Exception("Nope")).drainTo(Drain.toPublisher()).get
27 |
28 | override def required_spec313_cancelMustMakeThePublisherEventuallyDropAllReferencesToTheSubscriber(): Unit =
29 | throw new SkipException("Not relevant for publisher w/o fanout support")
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/Port.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl
8 |
9 | import swave.core.impl.stages.StageImpl
10 | import swave.core.{Module, Stage}
11 |
12 | private[swave] sealed trait Port {
13 | def stageImpl: StageImpl
14 |
15 | def xSeal(region: Region): Unit
16 | }
17 |
18 | private[swave] sealed trait Inport extends Port {
19 |
20 | def subscribe()(implicit from: Outport): Unit
21 |
22 | def request(n: Long)(implicit from: Outport): Unit
23 |
24 | def cancel()(implicit from: Outport): Unit
25 | }
26 |
27 | private[swave] sealed trait Outport extends Port {
28 |
29 | def onSubscribe()(implicit from: Inport): Unit
30 |
31 | def onNext(elem: AnyRef)(implicit from: Inport): Unit
32 |
33 | def onComplete()(implicit from: Inport): Unit
34 |
35 | def onError(error: Throwable)(implicit from: Inport): Unit
36 | }
37 |
38 | private[swave] abstract class PortImpl extends Stage with Inport with Outport {
39 | private[this] var _boundaryOf = List.empty[Module.ID]
40 |
41 | final def boundaryOf: List[Module.ID] = _boundaryOf
42 |
43 | final def markAsBoundaryOf(moduleID: Module.ID): Unit = _boundaryOf ::= moduleID
44 | }
45 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/MapStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import scala.util.control.NonFatal
10 | import swave.core.Stage
11 | import swave.core.impl.stages.InOutStage
12 | import swave.core.impl.{Inport, Outport}
13 | import swave.core.macros.StageImplementation
14 |
15 | // format: OFF
16 | @StageImplementation
17 | private[core] final class MapStage(f: Any ⇒ AnyRef) extends InOutStage {
18 |
19 | def kind = Stage.Kind.InOut.Map(f)
20 |
21 | connectInOutAndSealWith { (in, out) ⇒ running(in, out) }
22 |
23 | def running(in: Inport, out: Outport): State = state(
24 | intercept = false,
25 |
26 | request = requestF(in),
27 | cancel = stopCancelF(in),
28 |
29 | onNext = (elem, _) ⇒ {
30 | var funError: Throwable = null
31 | val mapped = try f(elem) catch { case NonFatal(e) => { funError = e; null } }
32 | if (funError eq null) {
33 | out.onNext(mapped)
34 | stay()
35 | } else {
36 | in.cancel()
37 | stopError(funError, out)
38 | }
39 | },
40 |
41 | onComplete = stopCompleteF(out),
42 | onError = stopErrorF(out))
43 | }
44 |
--------------------------------------------------------------------------------
/core/src/main/java/swave/core/impl/util/UnsafeArrayAccess.java:
--------------------------------------------------------------------------------
1 | package swave.core.impl.util;
2 |
3 | import static org.jctools.util.UnsafeAccess.UNSAFE;
4 |
5 | public final class UnsafeArrayAccess {
6 | private static final long REF_ARRAY_BASE;
7 | private static final int REF_ELEMENT_SHIFT;
8 | private static final long INT_ARRAY_BASE;
9 | private static final int INT_ELEMENT_SHIFT;
10 |
11 | static {
12 | int scale = UNSAFE.arrayIndexScale(Object[].class);
13 | if (4 == scale) REF_ELEMENT_SHIFT = 2;
14 | else if (8 == scale) REF_ELEMENT_SHIFT = 3;
15 | else throw new IllegalStateException("Unknown pointer size");
16 | REF_ARRAY_BASE = UNSAFE.arrayBaseOffset(Object[].class);
17 |
18 | scale = UNSAFE.arrayIndexScale(int[].class);
19 | if (4 == scale) INT_ELEMENT_SHIFT = 2;
20 | else if (8 == scale) INT_ELEMENT_SHIFT = 3;
21 | else throw new IllegalStateException("Unknown integer size");
22 | INT_ARRAY_BASE = UNSAFE.arrayBaseOffset(Object[].class);
23 | }
24 | private UnsafeArrayAccess() {
25 | }
26 |
27 | public static long calcRefArrayElementOffset(long index) {
28 | return REF_ARRAY_BASE + (index << REF_ELEMENT_SHIFT);
29 | }
30 |
31 | public static long calcIntArrayElementOffset(long index) {
32 | return INT_ARRAY_BASE + (index << INT_ELEMENT_SHIFT);
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/docs/src/test/scala/swave/docs/StreamOfStreamsSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.docs
8 |
9 | import org.scalatest.{FreeSpec, Matchers}
10 |
11 | class StreamOfStreamsSpec extends FreeSpec with Matchers {
12 |
13 | "the examples in the `streams-of-streams` chapter should work as expected" - {
14 |
15 | "takeEvery" in {
16 | //#takeEvery
17 | import scala.concurrent.Future
18 | import swave.core._
19 |
20 | implicit val env = StreamEnv()
21 |
22 | // simple extension for `Spout[T]`, could also be a value class
23 | implicit class RichSpout[T](underlying: Spout[T]) {
24 | def takeEvery(n: Long): Spout[T] =
25 | underlying // Spout[T]
26 | .injectSequential() // Spout[Spout[T]]
27 | .map(_.drop(n-1).take(1)) // Spout[Spout[T]]
28 | .flattenConcat() // Spout[T]
29 | }
30 |
31 | val result: Future[List[Int]] =
32 | Spout.ints(from = 1)
33 | .takeEvery(10)
34 | .take(5)
35 | .drainToList(limit = 100)
36 |
37 | result.value.get.get shouldEqual Seq(10, 20, 30, 40, 50)
38 | //#takeEvery
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/text/package.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | import java.nio.charset.{Charset, CodingErrorAction}
10 | import swave.core.io.Bytes
11 |
12 | package object text {
13 |
14 | implicit class RichBytesStreamOpsText[T, S[X] <: StreamOps[X]](val underlying: S[T]) extends AnyVal {
15 |
16 | def decode(charset: Charset,
17 | onMalformedInput: CodingErrorAction = CodingErrorAction.REPORT,
18 | onUnmappableCharacter: CodingErrorAction = CodingErrorAction.REPLACE)(
19 | implicit ev: Bytes[T]): S[T]#Repr[String] =
20 | underlying.via(Text.decode[T](charset, onMalformedInput, onUnmappableCharacter))
21 |
22 | def utf8Decode(implicit ev: Bytes[T]): S[T]#Repr[String] =
23 | underlying.via(Text.utf8Decode)
24 | }
25 |
26 | implicit class RichStringStreamOpsText[S <: StreamOps[String]](val underlying: S) extends AnyVal {
27 |
28 | def encode[T: Bytes](charset: Charset): S#Repr[T] =
29 | underlying.via(Text.encode(charset))
30 |
31 | def utf8Encode[T: Bytes]: S#Repr[T] =
32 | underlying.via(Text.utf8Encode)
33 |
34 | def lines: S#Repr[String] =
35 | underlying.via(Text.lines)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/drain/IgnoreDrainStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.drain
8 |
9 | import scala.concurrent.Promise
10 | import swave.core.Stage
11 | import swave.core.impl.Inport
12 | import swave.core.impl.stages.DrainStage
13 | import swave.core.macros.StageImplementation
14 |
15 | // format: OFF
16 | @StageImplementation
17 | private[core] final class IgnoreDrainStage(terminationPromise: Promise[Unit])
18 | extends DrainStage {
19 |
20 | def kind = Stage.Kind.Drain.Ignore(terminationPromise)
21 |
22 | connectInAndSealWith { in ⇒
23 | region.impl.registerForXStart(this)
24 | awaitingXStart(in)
25 | }
26 |
27 | /**
28 | * @param in the active upstream
29 | */
30 | def awaitingXStart(in: Inport) = state(
31 | xStart = () => {
32 | in.request(Long.MaxValue)
33 | running(in)
34 | })
35 |
36 | /**
37 | * @param in the active upstream
38 | */
39 | def running(in: Inport) = state(
40 | onNext = (_, _) ⇒ stay(),
41 |
42 | onComplete = _ ⇒ {
43 | terminationPromise.success(())
44 | stop()
45 | },
46 |
47 | onError = (e, _) ⇒ {
48 | terminationPromise.failure(e)
49 | stop(e)
50 | })
51 | }
52 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichByteArray.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import scala.annotation.tailrec
10 |
11 | final class RichByteArray(val underlying: Array[Byte]) extends AnyVal {
12 |
13 | /**
14 | * Tests two byte arrays for value equality in a way that defends against timing attacks.
15 | * Simple equality testing will stop at the end of a matching prefix thereby leaking information
16 | * about the length of the matching prefix which can be exploited for per-byte progressive brute-forcing.
17 | *
18 | * @note This function leaks information about the length of each byte array as well as
19 | * whether the two byte arrays have the same length.
20 | * @see [[http://codahale.com/a-lesson-in-timing-attacks/]]
21 | * @see [[http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/]]
22 | * @see [[http://emerose.com/timing-attacks-explained]]
23 | */
24 | def secure_==(other: Array[Byte]): Boolean = {
25 | @tailrec def rec(ix: Int, result: Int): Int =
26 | if (ix < underlying.length) rec(ix + 1, result | (underlying(ix) ^ other(ix))) else result
27 |
28 | other.length == underlying.length && rec(0, 0) == 0
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/OnStartStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import scala.util.control.NonFatal
10 | import swave.core.impl.{Inport, Outport}
11 | import swave.core.macros.StageImplementation
12 | import swave.core.Stage
13 | import swave.core.impl.stages.InOutStage
14 |
15 | // format: OFF
16 | @StageImplementation
17 | private[core] final class OnStartStage(callback: () ⇒ Unit) extends InOutStage {
18 |
19 | def kind = Stage.Kind.InOut.OnStart(callback)
20 |
21 | connectInOutAndSealWith { (in, out) ⇒
22 | region.impl.registerForXStart(this)
23 | awaitingXStart(in, out)
24 | }
25 |
26 | def awaitingXStart(in: Inport, out: Outport) = state(
27 | xStart = () => {
28 | try {
29 | callback()
30 | running(in, out)
31 | }
32 | catch {
33 | case NonFatal(e) =>
34 | in.cancel()
35 | stopError(e, out)
36 | }
37 | })
38 |
39 | def running(in: Inport, out: Outport) = state(
40 | intercept = false,
41 |
42 | request = requestF(in),
43 | cancel = stopCancelF(in),
44 | onNext = onNextF(out),
45 | onComplete = stopCompleteF(out),
46 | onError = stopErrorF(out))
47 | }
48 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/plugin/print-pdf/print-pdf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * phantomjs script for printing presentations to PDF.
3 | *
4 | * Example:
5 | * phantomjs print-pdf.js "http://lab.hakim.se/reveal-js?print-pdf" reveal-demo.pdf
6 | *
7 | * By Manuel Bieh (https://github.com/manuelbieh)
8 | */
9 |
10 | // html2pdf.js
11 | var page = new WebPage();
12 | var system = require( 'system' );
13 |
14 | var slideWidth = system.args[3] ? system.args[3].split( 'x' )[0] : 960;
15 | var slideHeight = system.args[3] ? system.args[3].split( 'x' )[1] : 700;
16 |
17 | page.viewportSize = {
18 | width: slideWidth,
19 | height: slideHeight
20 | };
21 |
22 | // TODO
23 | // Something is wrong with these config values. An input
24 | // paper width of 1920px actually results in a 756px wide
25 | // PDF.
26 | page.paperSize = {
27 | width: Math.round( slideWidth * 2 ),
28 | height: Math.round( slideHeight * 2 ),
29 | border: 0
30 | };
31 |
32 | var inputFile = system.args[1] || 'index.html?print-pdf';
33 | var outputFile = system.args[2] || 'slides.pdf';
34 |
35 | if( outputFile.match( /\.pdf$/gi ) === null ) {
36 | outputFile += '.pdf';
37 | }
38 |
39 | console.log( 'Printing PDF (Paper size: '+ page.paperSize.width + 'x' + page.paperSize.height +')' );
40 |
41 | page.open( inputFile, function( status ) {
42 | window.setTimeout( function() {
43 | console.log( 'Printed successfully' );
44 | page.render( outputFile );
45 | phantom.exit();
46 | }, 1000 );
47 | } );
48 |
49 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/plugin/print-pdf/print-pdf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * phantomjs script for printing presentations to PDF.
3 | *
4 | * Example:
5 | * phantomjs print-pdf.js "http://lab.hakim.se/reveal-js?print-pdf" reveal-demo.pdf
6 | *
7 | * By Manuel Bieh (https://github.com/manuelbieh)
8 | */
9 |
10 | // html2pdf.js
11 | var page = new WebPage();
12 | var system = require( 'system' );
13 |
14 | var slideWidth = system.args[3] ? system.args[3].split( 'x' )[0] : 960;
15 | var slideHeight = system.args[3] ? system.args[3].split( 'x' )[1] : 700;
16 |
17 | page.viewportSize = {
18 | width: slideWidth,
19 | height: slideHeight
20 | };
21 |
22 | // TODO
23 | // Something is wrong with these config values. An input
24 | // paper width of 1920px actually results in a 756px wide
25 | // PDF.
26 | page.paperSize = {
27 | width: Math.round( slideWidth * 2 ),
28 | height: Math.round( slideHeight * 2 ),
29 | border: 0
30 | };
31 |
32 | var inputFile = system.args[1] || 'index.html?print-pdf';
33 | var outputFile = system.args[2] || 'slides.pdf';
34 |
35 | if( outputFile.match( /\.pdf$/gi ) === null ) {
36 | outputFile += '.pdf';
37 | }
38 |
39 | console.log( 'Printing PDF (Paper size: '+ page.paperSize.width + 'x' + page.paperSize.height +')' );
40 |
41 | page.open( inputFile, function( status ) {
42 | window.setTimeout( function() {
43 | console.log( 'Printed successfully' );
44 | page.render( outputFile );
45 | phantom.exit();
46 | }, 1000 );
47 | } );
48 |
49 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/plugin/print-pdf/print-pdf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * phantomjs script for printing presentations to PDF.
3 | *
4 | * Example:
5 | * phantomjs print-pdf.js "http://lab.hakim.se/reveal-js?print-pdf" reveal-demo.pdf
6 | *
7 | * By Manuel Bieh (https://github.com/manuelbieh)
8 | */
9 |
10 | // html2pdf.js
11 | var page = new WebPage();
12 | var system = require( 'system' );
13 |
14 | var slideWidth = system.args[3] ? system.args[3].split( 'x' )[0] : 960;
15 | var slideHeight = system.args[3] ? system.args[3].split( 'x' )[1] : 700;
16 |
17 | page.viewportSize = {
18 | width: slideWidth,
19 | height: slideHeight
20 | };
21 |
22 | // TODO
23 | // Something is wrong with these config values. An input
24 | // paper width of 1920px actually results in a 756px wide
25 | // PDF.
26 | page.paperSize = {
27 | width: Math.round( slideWidth * 2 ),
28 | height: Math.round( slideHeight * 2 ),
29 | border: 0
30 | };
31 |
32 | var inputFile = system.args[1] || 'index.html?print-pdf';
33 | var outputFile = system.args[2] || 'slides.pdf';
34 |
35 | if( outputFile.match( /\.pdf$/gi ) === null ) {
36 | outputFile += '.pdf';
37 | }
38 |
39 | console.log( 'Printing PDF (Paper size: '+ page.paperSize.width + 'x' + page.paperSize.height +')' );
40 |
41 | page.open( inputFile, function( status ) {
42 | window.setTimeout( function() {
43 | console.log( 'Printed succesfully' );
44 | page.render( outputFile );
45 | phantom.exit();
46 | }, 1000 );
47 | } );
48 |
49 |
--------------------------------------------------------------------------------
/docs/src/test/scala/swave/docs/BasicSpec.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.docs
8 |
9 | import org.scalatest.FreeSpec
10 | import scala.concurrent.Future
11 | import swave.core._
12 |
13 | class BasicSpec extends FreeSpec {
14 |
15 | implicit val env = StreamEnv()
16 |
17 | "the examples in the `basics` chapter should work as expected" in {
18 |
19 | //#foo
20 | val foo: Spout[Char] = Spout('f', 'o', 'o')
21 | //#foo
22 |
23 | //#upperFoo
24 | val upperFoo: Spout[Char] = foo.map(_.toUpper)
25 | //#upperFoo
26 |
27 | //#streamGraph
28 | val streamGraph: StreamGraph[Future[Char]] = upperFoo.to(Drain.head)
29 | //#streamGraph
30 |
31 | def `only compiled, not actually run`() = {
32 | //#reuse
33 | // the stream of all natural numbers as Strings
34 | def numberStrings = Spout.ints(from = 1).map(_.toString)
35 |
36 | // print the first 10
37 | numberStrings.take(10).foreach(println)
38 |
39 | // print the 42nd
40 | println(numberStrings.drop(41).drainToHead())
41 |
42 | // concatenate the first hundred
43 | val s: Future[String] =
44 | numberStrings.take(100)
45 | .drainToMkString(limit = 1000, ", ")
46 | //#reuse
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/testkit/src/main/scala/swave/testkit/Timing.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.testkit
8 |
9 | import com.typesafe.config.Config
10 | import swave.core.impl.util.SettingsCompanion
11 |
12 | import scala.collection._
13 | import scala.concurrent.duration._
14 | import scala.collection.JavaConverters._
15 | import swave.core.macros._
16 | import swave.core.util._
17 |
18 | object Timing {
19 |
20 | final case class Settings(factor: Double, scalingChain: immutable.Seq[Double], singleExpectDefault: FiniteDuration) {
21 |
22 | requireArg(factor > 0.0 && !factor.isInfinite, "`click` must be finite and > 0")
23 | requireArg(
24 | scalingChain.nonEmpty && scalingChain.size <= 16,
25 | "`scalingChain` must be non-empty and have at most 16 elements")
26 | requireArg(singleExpectDefault > Duration.Zero, "`singleExpectDefault` must be > 0")
27 | }
28 |
29 | object Settings extends SettingsCompanion[Settings]("swave.test.timing") {
30 | def fromSubConfig(c: Config): Settings =
31 | Settings(
32 | factor = c getDouble "factor",
33 | scalingChain = c.getDoubleList("scaling-chain").asScala.map(_.doubleValue)(breakOut),
34 | singleExpectDefault = c getFiniteDuration "single-expect-default"
35 | )
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/drain/HeadDrainStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.drain
8 |
9 | import scala.concurrent.Promise
10 | import swave.core.macros.StageImplementation
11 | import swave.core.Stage
12 | import swave.core.impl.Inport
13 | import swave.core.impl.stages.DrainStage
14 |
15 | // format: OFF
16 | @StageImplementation
17 | private[core] final class HeadDrainStage(headPromise: Promise[AnyRef]) extends DrainStage {
18 |
19 | def kind = Stage.Kind.Drain.Head
20 |
21 | connectInAndSealWith { in ⇒
22 | region.impl.registerForXStart(this)
23 | awaitingXStart(in)
24 | }
25 |
26 | /**
27 | * @param in the active upstream
28 | */
29 | def awaitingXStart(in: Inport) = state(
30 | xStart = () => {
31 | in.request(1)
32 | receiveOne(in)
33 | })
34 |
35 | /**
36 | * @param in the active upstream
37 | */
38 | def receiveOne(in: Inport) = state(
39 | onNext = (elem, _) ⇒ {
40 | headPromise.success(elem)
41 | stopCancel(in)
42 | },
43 |
44 | onComplete = _ ⇒ {
45 | headPromise.failure(new NoSuchElementException)
46 | stop()
47 | },
48 |
49 | onError = (e, _) ⇒ {
50 | headPromise.failure(e)
51 | stop(e)
52 | })
53 | }
54 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/FilterStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import scala.util.control.NonFatal
10 | import swave.core.Stage
11 | import swave.core.impl.stages.InOutStage
12 | import swave.core.impl.{Inport, Outport}
13 | import swave.core.macros.StageImplementation
14 |
15 | // format: OFF
16 | @StageImplementation
17 | private[core] final class FilterStage(predicate: Any ⇒ Boolean, negated: Boolean) extends InOutStage {
18 |
19 | def kind = Stage.Kind.InOut.Filter(predicate, negated)
20 |
21 | connectInOutAndSealWith { (in, out) ⇒ running(in, out) }
22 |
23 | def running(in: Inport, out: Outport) = state(
24 | intercept = false,
25 |
26 | request = requestF(in),
27 | cancel = stopCancelF(in),
28 |
29 | onNext = (elem, _) ⇒ {
30 | var funError: Throwable = null
31 | val p = try predicate(elem) catch { case NonFatal(e) => { funError = e; false } }
32 | if (funError eq null) {
33 | if (p != negated) out.onNext(elem)
34 | else in.request(1)
35 | stay()
36 | } else {
37 | in.cancel()
38 | stopError(funError, out)
39 | }
40 | },
41 |
42 | onComplete = stopCompleteF(out),
43 | onError = stopErrorF(out))
44 | }
45 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/spout/RingBufferSpoutStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.spout
8 |
9 | import scala.annotation.tailrec
10 | import swave.core.Stage
11 | import swave.core.impl.Outport
12 | import swave.core.impl.stages.SpoutStage
13 | import swave.core.impl.util.RingBuffer
14 | import swave.core.macros.StageImplementation
15 |
16 | // format: OFF
17 | @StageImplementation(interceptAllRequests = true)
18 | private[core] final class RingBufferSpoutStage(buffer: RingBuffer[AnyRef]) extends SpoutStage {
19 |
20 | def kind = Stage.Kind.Spout.FromRingBuffer(buffer)
21 |
22 | connectOutAndSealWith { out ⇒
23 | if (buffer.isEmpty) {
24 | region.impl.registerForXStart(this)
25 | awaitingXStart(out)
26 | } else running(out)
27 | }
28 |
29 | def awaitingXStart(out: Outport) = state(
30 | xStart = () => stopComplete(out))
31 |
32 | def running(out: Outport) = state(
33 | request = (n, _) ⇒ {
34 | @tailrec def rec(n: Int): State = {
35 | out.onNext(buffer.unsafeRead())
36 | if (buffer.nonEmpty) {
37 | if (n > 1) rec(n - 1)
38 | else stay()
39 | } else stopComplete(out)
40 | }
41 |
42 | rec(n)
43 | },
44 |
45 | cancel = stopF)
46 | }
47 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/Split.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | sealed abstract class Split
10 |
11 | object Split {
12 | sealed abstract class Command
13 |
14 | /**
15 | * Emit the current element to the current sub-stream.
16 | * If there is no sub-stream open, start a new one by emitting a new sub-stream to the main downstream.
17 | */
18 | case object Emit extends Command
19 |
20 | /**
21 | * Drop the current element without any effect on a potentially open sub-stream or the main downstream.
22 | */
23 | case object Drop extends Command
24 |
25 | /**
26 | * Emit the current element to the current sub-stream and complete the sub-stream afterwards.
27 | * If there is no sub-stream open, emit a single-element sub-stream on the main downstream.
28 | */
29 | case object EmitComplete extends Command
30 |
31 | /**
32 | * If there is currently a sub-stream open, complete it.
33 | * Then emit a new sub-stream to the main downstream and emit the current element this this new sub-stream.
34 | */
35 | case object CompleteEmit extends Command
36 |
37 | /**
38 | * Drop the current element and complete the currently open sub-stream, if there is one.
39 | */
40 | case object DropComplete extends Command
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/Extension.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | import com.typesafe.config.Config
10 | import scala.concurrent.duration.FiniteDuration
11 | import swave.core.impl.util.SettingsCompanion
12 | import swave.core.util._
13 |
14 | trait Extension
15 |
16 | trait ExtensionId[T <: Extension] {
17 |
18 | /**
19 | * Returns an instance of the extension identified by this ExtensionId instance.
20 | */
21 | def apply(env: StreamEnv): T =
22 | env.getOrLoadExtension(this).await(env.settings.extensionSettings.constructionTimeout)
23 |
24 | def createExtension(env: StreamEnv): T
25 |
26 | // ExtensionId instances are used as keys in a ConcurrentHashMap,
27 | // therefore we pin down reference equality semantics for them here
28 | override final def hashCode: Int = System.identityHashCode(this)
29 | override final def equals(other: Any): Boolean = this eq other.asInstanceOf[AnyRef]
30 | }
31 |
32 | object Extension {
33 |
34 | final case class Settings(constructionTimeout: FiniteDuration)
35 |
36 | object Settings extends SettingsCompanion[Settings]("swave.core.extensions") {
37 | def fromSubConfig(c: Config): Settings =
38 | Settings(constructionTimeout = c getFiniteDuration "construction-timeout")
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichLong.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | private[swave] class RichLong(private val underlying: Long) extends AnyVal {
10 |
11 | /**
12 | * Add with result bounded by [Long.MinValue, Long.MaxValue].
13 | */
14 | def ⊹(other: Int): Long = ⊹(other.toLong)
15 |
16 | /**
17 | * Add with result bounded by [Long.MinValue, Long.MaxValue].
18 | */
19 | def ⊹(other: Long): Long = {
20 | val r = underlying + other
21 | // HD 2-12 Overflow iff both arguments have the opposite sign of the result
22 | if (((underlying ^ r) & (other ^ r)) < 0) {
23 | if (r < 0) Long.MaxValue else Long.MinValue
24 | } else r
25 | }
26 |
27 | /**
28 | * Multiply with result bounded by [Long.MinValue, Long.MaxValue].
29 | */
30 | def ×(other: Int): Long = ×(other.toLong)
31 |
32 | /**
33 | * Multiply with result bounded by [Long.MinValue, Long.MaxValue].
34 | */
35 | def ×(other: Long): Long = {
36 | val r = underlying * other
37 | if (((math.abs(underlying) | math.abs(other)) >>> 31 != 0) &&
38 | (other != 0 && (r / other != underlying) || underlying == Long.MinValue && other == -1)) {
39 | if ((underlying ^ other) < 0) Long.MinValue else Long.MaxValue
40 | } else r
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/docs/src/paradox/introduction/talks-on-swave.md:
--------------------------------------------------------------------------------
1 | Talks on *swave*
2 | ================
3 |
4 | The currently best talk on *swave* is [>>> swave - Reactive Streams in Scala <<<](https://youtu.be/htwmROeki0c)
5 | from [ScalaDays 2016 @ Berlin](http://event.scaladays.org/scaladays-berlin-2016).
6 |
7 | It nicely introduces the key ideas and concepts and gives a good overview over the project.
8 | While quite a few things have evolved since this talk was given there is only one important change to be aware of:
9 | The type called `swave.core.Stream[T]` in the talk is now called `swave.core.Spout[T]`.
10 |
11 |
12 | All talks in reverse chronological order
13 | ----------------------------------------
14 |
15 | Here we list all known talks and presentations related to *swave*.
16 | If you'd like to add one, please @ref[submit a PR](../project/contributing.md)!
17 |
18 | "swave - Reactive Streams in Scala" presented at [scala.io 2016](http://scala.io) (Oct 2016)
19 | : Slides: [/talks/2016/scala.io/index.html](../talks/2016/scala.io/index.html)
20 |
21 | "swave - Reactive Streams in Scala" presented at [ScalaDays 2016 @ Berlin](http://event.scaladays.org/scaladays-berlin-2016) (Jun 2016)
22 | : Slides: [/talks/2016/scaladays/index.html](../talks/2016/scaladays/index.html)
23 | : Video: https://youtu.be/htwmROeki0c
24 |
25 | "swave - A Preview" presented at [SCALAR 2016](http://scalar-conf.com/) (Apr 2016)
26 | : Slides: [/talks/2016/scalar/index.html](../talks/2016/scalar/index.html)
27 | : Video: https://youtu.be/0jq0-Ph2gpM
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/DropLastStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.stages.InOutStage
11 | import swave.core.impl.util.RingBuffer
12 | import swave.core.impl.{Inport, Outport}
13 | import swave.core.macros.StageImplementation
14 | import swave.core.util._
15 |
16 | // format: OFF
17 | @StageImplementation
18 | private[core] final class DropLastStage(count: Int) extends InOutStage {
19 |
20 | def kind = Stage.Kind.InOut.DropLast(count)
21 |
22 | private[this] val buffer = new RingBuffer[AnyRef](roundUpToPowerOf2(count))
23 |
24 | connectInOutAndSealWith { (in, out) ⇒
25 | region.impl.registerForXStart(this)
26 | awaitingXStart(in, out)
27 | }
28 |
29 | def awaitingXStart(in: Inport, out: Outport) = state(
30 | xStart = () => {
31 | in.request(count.toLong)
32 | running(in, out)
33 | })
34 |
35 | def running(in: Inport, out: Outport): State = state(
36 | request = requestF(in),
37 | cancel = stopCancelF(in),
38 |
39 | onNext = (elem, _) ⇒ {
40 | if (buffer.count == count) out.onNext(buffer.unsafeRead())
41 | buffer.write(elem)
42 | stay()
43 | },
44 |
45 | onComplete = stopCompleteF(out),
46 | onError = stopErrorF(out))
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/DispatchersImpl.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl
8 |
9 | import swave.core._
10 |
11 | private[core] final class DispatchersImpl private (val settings: Dispatchers.Settings,
12 | val defaultDispatcher: Dispatcher,
13 | dispatcherMap: Map[String, DispatcherImpl])
14 | extends Dispatchers {
15 |
16 | def apply(id: String) = dispatcherMap(id)
17 |
18 | /**
19 | * Triggers a shutdown and returns a function that
20 | * returns the ids of all dispatchers that are not yet terminated.
21 | */
22 | def shutdownAll(): () ⇒ List[String] = {
23 | val map = dispatcherMap.transform((_, dispatcher) ⇒ dispatcher.shutdown())
24 | () ⇒
25 | map.collect({ case (id, isTerminated) if !isTerminated() ⇒ id })(collection.breakOut)
26 | }
27 |
28 | }
29 |
30 | private[core] object DispatchersImpl {
31 | def apply(settings: Dispatchers.Settings): DispatchersImpl = {
32 | val dispatcherMap =
33 | settings.dispatcherDefs
34 | .transform((_, settings) ⇒ DispatcherImpl(settings))
35 | .withDefault(id ⇒ sys.error(s"Dispatcher '$id' is not defined"))
36 | new DispatchersImpl(settings, dispatcherMap("default"), dispatcherMap)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/TakeWhileStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import scala.util.control.NonFatal
10 | import swave.core.Stage
11 | import swave.core.impl.stages.InOutStage
12 | import swave.core.impl.{Inport, Outport}
13 | import swave.core.macros.StageImplementation
14 |
15 | // format: OFF
16 | @StageImplementation
17 | private[core] final class TakeWhileStage(predicate: Any ⇒ Boolean) extends InOutStage {
18 |
19 | def kind = Stage.Kind.InOut.TakeWhile(predicate)
20 |
21 | connectInOutAndSealWith { (in, out) ⇒ running(in, out) }
22 |
23 | def running(in: Inport, out: Outport) = state(
24 | intercept = false,
25 |
26 | request = requestF(in),
27 | cancel = stopCancelF(in),
28 |
29 | onNext = (elem, _) ⇒ {
30 | var funError: Throwable = null
31 | val p = try predicate(elem) catch { case NonFatal(e) => { funError = e; false } }
32 | if (funError eq null) {
33 | if (p) {
34 | out.onNext(elem)
35 | stay()
36 | } else {
37 | in.cancel()
38 | stopComplete(out)
39 | }
40 | } else {
41 | in.cancel()
42 | stopError(funError, out)
43 | }
44 | },
45 |
46 | onComplete = stopCompleteF(out),
47 | onError = stopErrorF(out))
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichList.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import scala.annotation.tailrec
10 |
11 | final class RichList[T](val underlying: List[T]) extends AnyVal {
12 |
13 | /**
14 | * Returns 0, 1 or 2 depending on the whether the list contains 0, 1 or more elements respectively.
15 | */
16 | def size012: Int =
17 | if (underlying eq Nil) 0
18 | else if (underlying.tail eq Nil) 1
19 | else 2
20 |
21 | /**
22 | * Reverses the list avoiding the extra allocation that is performed
23 | * by the default `list.reverse` if the list has one single element.
24 | */
25 | def fastReverse: List[T] =
26 | if ((underlying eq Nil) || (underlying.tail eq Nil)) underlying
27 | else underlying.reverse // does an unnecessary allocation for single-element lists
28 |
29 | /**
30 | * Removes the given element from the list and returns either a new list
31 | * or the identical (reference equality!) list if the element is not present.
32 | */
33 | def remove(elem: T): List[T] = {
34 | @tailrec def rec(revHead: List[T], tail: List[T]): List[T] =
35 | if (tail ne Nil) {
36 | if (tail.head == elem) revHead reverse_::: tail.tail
37 | else rec(tail.head :: revHead, tail.tail)
38 | } else underlying
39 |
40 | rec(Nil, underlying)
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/core-tests/src/test/resources/RegionSpec.examples.txt:
--------------------------------------------------------------------------------
1 | Example 1:
2 | = Spout.FromIterator: 0
3 | |
4 | o Map: 0
5 | |
6 | = Drain.Head: 0
7 |
8 | Example 2:
9 | = Spout.FromIterator: 1
10 | |
11 | o Take: 1
12 | |
13 | o AsyncBoundary: 1
14 | |
15 | o BufferWithBackpressure: 0
16 | |
17 | o Map: 0
18 | |
19 | = Drain.Head: 0
20 |
21 | Example 3:
22 | = Spout.FromIterator: 0
23 | |
24 | o-+ FanOut.Broadcast: 0
25 | | |
26 | o | Map: 0
27 | | |
28 | | o AsyncBoundary: 0
29 | | |
30 | | o BufferWithBackpressure: 0
31 | | |
32 | o-+ FanIn.Concat: 0
33 | |
34 | = Drain.Head: 0
35 |
36 | Example 4:
37 | = Spout.FromIterator: 3
38 | |
39 | o Map: 3
40 | |
41 | o AsyncBoundary: 3
42 | |
43 | o BufferWithBackpressure: 0
44 | |
45 | o-+ FanOut.Broadcast: 0
46 | | |
47 | o | Drop: 0
48 | | |
49 | | o Take: 0
50 | | |
51 | | o AsyncBoundary: 0
52 | | |
53 | | o BufferWithBackpressure: 0
54 | | |
55 | | o Map: 0
56 | | |
57 | | o Flatten.Concat: 0
58 | | |
59 | | | = Spout.FromIterator: 2
60 | | | |
61 | | | o Map: 2
62 | | | |
63 | | | o AsyncBoundary: 2
64 | | | |
65 | | | o BufferWithBackpressure: 0
66 | | | |
67 | o-|-+ FanIn.Concat: 0
68 | | |
69 | o-+ FanIn.Concat: 0
70 | |
71 | o-+ FanOut.Broadcast: 0
72 | | |
73 | | o Map: 0
74 | | |
75 | | o WithLimit: 0
76 | | |
77 | | o Fold: 0
78 | | |
79 | | o Map: 0
80 | | |
81 | | = Drain.Head: 0
82 | |
83 | o AsyncBoundary: 0
84 | |
85 | o BufferWithBackpressure: 1
86 | |
87 | o Deduplicate: 1
88 | |
89 | o AsyncDispatcher: 1
90 | |
91 | o WithLimit: 1
92 | |
93 | o Fold: 1
94 | |
95 | o Map: 1
96 | |
97 | = Drain.Head: 1
98 |
99 | -- last line -- do not remove --
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/lib/js/classList.js:
--------------------------------------------------------------------------------
1 | /*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
2 | if(typeof document!=="undefined"&&!("classList" in document.createElement("a"))){(function(j){var a="classList",f="prototype",m=(j.HTMLElement||j.Element)[f],b=Object,k=String[f].trim||function(){return this.replace(/^\s+|\s+$/g,"")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p= 0L and be < bound)
21 | }
22 | }
23 |
24 | "nextInt" in {
25 | val random = XorShiftRandom()
26 | forAll(Gen.posNum[Int]) { bound ⇒
27 | random.nextInt(bound) should (be >= 0 and be < bound)
28 | }
29 | }
30 |
31 | "nextDouble" in {
32 | val random = XorShiftRandom()
33 | forAll { (_: Unit) ⇒
34 | random.nextDouble() should (be >= 0.0 and be < 1.0)
35 | }
36 | }
37 |
38 | "shuffle" in {
39 | val random = XorShiftRandom()
40 | val array = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
41 | val array2 = java.util.Arrays.copyOf(array, array.length)
42 | random.shuffle_!(array2)
43 | array2 should not equal array // will fail once every approx. 10! = 3.628.800 test runs
44 | array2.sorted shouldEqual array
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/docs/src/paradox/usage/swave-akka-compat/index.md:
--------------------------------------------------------------------------------
1 | swave-akka-compat
2 | =================
3 |
4 | The `swave-akka-compat` modules provides for very easy interconnectivity between *swave* and @extref[Akka-Stream].
5 |
6 |
7 | Installation
8 | ------------
9 |
10 | See the @ref[Setup] chapter for details on how to pull `swave-akka-compat` into your build.
11 |
12 |
13 | Usage
14 | -----
15 |
16 | Once you have `swave-akka-compat` on your classpath this import:
17 |
18 | ```scala
19 | import swave.compat.akka._
20 | ```
21 |
22 | gives you six "decorators" that allow for almost seamless conversion of all major stream graph components between both
23 | worlds. You can convert *swave* components into *akka* ones like this:
24 |
25 | ```scala
26 | val akkaSource = spout.toAkkaSource
27 | val akkaFlow = pipe.toAkkaFlow
28 | val akkaSink = drain.toAkkaSink
29 | ```
30 |
31 | as well as the other way around:
32 |
33 | ```scala
34 | val spout = akkaSource.toSpout
35 | val pipe = akkaFlow.toPipe
36 | val drain = akkaSink.toDrain
37 | ```
38 |
39 | Additionally the import brings a `Bytes[T]` type class instance in scope that allows @ref[File IO] to seamlessly work
40 | with `akka.util.ByteString` as the main vehicle for raw bytes. See the section on the @ref[Bytes] type class for more
41 | info on this.
42 |
43 |
44 | API Docs (ScalaDoc)
45 | -------------------
46 |
47 | The ScalaDoc for *swave-scodec-compat* can be found @scaladoc[>>> HERE <<<](swave.compat.akka.index).
48 |
49 |
50 | [Akka-Stream]: akka:stream/index
51 | [Setup]: ../setup.md
52 | [File IO]: ../domain/file-io.md
53 | [Bytes]: ../domain/file-io.md#the-bytes-t-type-class
--------------------------------------------------------------------------------
/docs/src/paradox/_template/assets/vendor/nanoscroller/nanoscroller.css:
--------------------------------------------------------------------------------
1 | /** initial setup **/
2 | .nano {
3 | position : relative;
4 | width : 100%;
5 | height : 100%;
6 | overflow : hidden;
7 | }
8 | .nano > .nano-content {
9 | position : absolute;
10 | overflow : scroll;
11 | overflow-x : hidden;
12 | top : 0;
13 | right : 0;
14 | bottom : 0;
15 | left : 0;
16 | }
17 | .nano > .nano-content:focus {
18 | outline: thin dotted;
19 | }
20 | .nano > .nano-content::-webkit-scrollbar {
21 | display: none;
22 | }
23 | .has-scrollbar > .nano-content::-webkit-scrollbar {
24 | display: block;
25 | }
26 | .nano > .nano-pane {
27 | background : rgba(0,0,0,.25);
28 | position : absolute;
29 | width : 10px;
30 | right : 0;
31 | top : 0;
32 | bottom : 0;
33 | visibility : hidden\9; /* Target only IE7 and IE8 with this hack */
34 | opacity : .01;
35 | -webkit-transition : .2s;
36 | -moz-transition : .2s;
37 | -o-transition : .2s;
38 | transition : .2s;
39 | -moz-border-radius : 5px;
40 | -webkit-border-radius : 5px;
41 | border-radius : 5px;
42 | }
43 | .nano > .nano-pane > .nano-slider {
44 | background: #444;
45 | background: rgba(0,0,0,.5);
46 | position : relative;
47 | margin : 0 1px;
48 | -moz-border-radius : 3px;
49 | -webkit-border-radius : 3px;
50 | border-radius : 3px;
51 | }
52 | .nano:hover > .nano-pane, .nano-pane.active, .nano-pane.flashed {
53 | visibility : visible\9; /* Target only IE7 and IE8 with this hack */
54 | opacity : 0.99;
55 | }
56 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/img/small-inout.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/img/small-inout.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/spout/IteratorSpoutStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.spout
8 |
9 | import scala.annotation.tailrec
10 | import scala.util.control.NonFatal
11 | import swave.core.macros.StageImplementation
12 | import swave.core.Stage
13 | import swave.core.impl.Outport
14 | import swave.core.impl.stages.SpoutStage
15 |
16 | // format: OFF
17 | @StageImplementation(interceptAllRequests = true)
18 | private[core] final class IteratorSpoutStage(iterator: Iterator[AnyRef]) extends SpoutStage {
19 |
20 | def kind = Stage.Kind.Spout.FromIterator(iterator)
21 |
22 | connectOutAndSealWith { out ⇒
23 | if (!iterator.hasNext) {
24 | region.impl.registerForXStart(this)
25 | awaitingXStart(out)
26 | } else running(out)
27 | }
28 |
29 | def awaitingXStart(out: Outport) = state(
30 | xStart = () => stopComplete(out))
31 |
32 | def running(out: Outport) = state(
33 | request = (n, _) ⇒ {
34 | @tailrec def rec(n: Int): State = {
35 | var iterError: Throwable = null
36 | val next = try iterator.next() catch { case NonFatal(e) => { iterError = e; null } }
37 | if (iterError eq null) {
38 | out.onNext(next)
39 | if (iterator.hasNext) {
40 | if (n > 1) rec(n - 1)
41 | else stay()
42 | } else stopComplete(out)
43 | } else stopError(iterError, out)
44 | }
45 | rec(n)
46 | },
47 |
48 | cancel = stopF)
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/AnyRefExtractor.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | /**
10 | * Enables zero-overhead custom extractors for extractions that are reference types, e.g.
11 | * {{{
12 | * scala> case class Person(age: Int, name: String)
13 | * defined class Person
14 | *
15 | * scala> val Child = AnyRefExtractor[Person, Person](person => if (person.age < 18) person else null)
16 | * Child: AnyRefExtractor[Person,Person] = AnyRefExtractor@1e592ef2
17 | *
18 | * scala> val Child(x) = Person(9, "Alice")
19 | * x: Person = Person(9,Bob)
20 | *
21 | * scala> val Child(x) = Person(21, "Bob")
22 | * scala.MatchError: Person(21,Alice) (of class Person)
23 | * ... 29 elided
24 | * }}}
25 | *
26 | * @param f the function performing the extraction; must return the extraction or null if no extraction is available
27 | * @tparam A the type to extract from
28 | * @tparam B the type of the extraction (must be a reference type)
29 | */
30 | final class AnyRefExtractor[A, B <: AnyRef](f: A ⇒ B) {
31 | def unapply(value: A): AnyRefExtractor.Extraction[B] = new AnyRefExtractor.Extraction(f(value))
32 | }
33 |
34 | object AnyRefExtractor {
35 | class Extraction[T <: AnyRef](val extraction: T) extends AnyVal {
36 | def isEmpty: Boolean = extraction eq null
37 | def get: T = extraction
38 | }
39 |
40 | def apply[A, B <: AnyRef](f: A ⇒ B): AnyRefExtractor[A, B] = new AnyRefExtractor(f)
41 | }
42 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/FanOutStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages
8 |
9 | import scala.annotation.compileTimeOnly
10 | import swave.core.Stage
11 | import swave.core.impl.util.AbstractOutportList
12 | import swave.core.impl.{Inport, Outport}
13 |
14 | // format: OFF
15 | private[core] abstract class FanOutStage extends StageImpl {
16 | import FanOutStage._
17 |
18 | type OutportCtx >: Null <: OutportContext[OutportCtx]
19 |
20 | override def kind: Stage.Kind.FanOut
21 |
22 | protected final var _inputStages: List[Stage] = Nil
23 | protected final var _outputStages: List[Stage] = Nil
24 |
25 | final def inputStages: List[Stage] = _inputStages
26 | final def outputStages: List[Stage] = _outputStages
27 |
28 | @compileTimeOnly("Unresolved `connectFanOutAndSealWith` call")
29 | protected final def connectFanOutAndSealWith(f: (Inport, OutportCtx) ⇒ State): Unit = ()
30 |
31 | protected def createOutportCtx(out: Outport, tail: OutportCtx): OutportCtx
32 | }
33 |
34 | private[stages] object FanOutStage {
35 |
36 | private[stages] abstract class OutportContext[L >: Null <: OutportContext[L]](out: Outport, tail: L)
37 | extends AbstractOutportList[L](out, tail) {
38 | var remaining: Long = _ // requested by this `out` but not yet delivered, i.e. unfulfilled demand
39 | }
40 |
41 | private[stages] final class SimpleOutportContext(out: Outport, tail: SimpleOutportContext)
42 | extends OutportContext[SimpleOutportContext](out, tail)
43 | }
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/CollectStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import scala.util.control.NonFatal
10 | import swave.core.Stage
11 | import swave.core.impl.stages.InOutStage
12 | import swave.core.impl.{Inport, Outport}
13 | import swave.core.macros.StageImplementation
14 |
15 | // format: OFF
16 | @StageImplementation
17 | private[core] final class CollectStage(pf: PartialFunction[AnyRef, AnyRef]) extends InOutStage {
18 |
19 | def kind = Stage.Kind.InOut.Collect(pf)
20 |
21 | connectInOutAndSealWith { (in, out) ⇒
22 | val mismatchF: AnyRef => this.type =
23 | _ => this // we use `this` as a special result instance signalling the mismatch of a single collect
24 | running(in, out, mismatchF)
25 | }
26 |
27 | def running(in: Inport, out: Outport, mismatchFun: AnyRef => this.type) = state(
28 | intercept = false,
29 |
30 | request = requestF(in),
31 | cancel = stopCancelF(in),
32 |
33 | onNext = (elem, _) ⇒ {
34 | var funError: Throwable = null
35 | val collected = try pf.applyOrElse(elem, mismatchFun) catch { case NonFatal(e) => { funError = e; null } }
36 | if (funError eq null) {
37 | if (collected ne this) out.onNext(collected)
38 | else in.request(1)
39 | stay()
40 | } else {
41 | in.cancel()
42 | stopError(funError, out)
43 | }
44 | },
45 |
46 | onComplete = stopCompleteF(out),
47 | onError = stopErrorF(out))
48 | }
49 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/img/small-inject.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/img/small-inject.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/img/small-flatten.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/img/small-flatten.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/drain/ForeachDrainStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.drain
8 |
9 | import scala.util.control.NonFatal
10 | import scala.concurrent.Promise
11 | import swave.core.macros.StageImplementation
12 | import swave.core.Stage
13 | import swave.core.impl.Inport
14 | import swave.core.impl.stages.DrainStage
15 |
16 | // format: OFF
17 | @StageImplementation
18 | private[core] final class ForeachDrainStage(callback: AnyRef ⇒ Unit, terminationPromise: Promise[Unit])
19 | extends DrainStage {
20 |
21 | def kind = Stage.Kind.Drain.Foreach(callback, terminationPromise)
22 |
23 | connectInAndSealWith { in ⇒
24 | region.impl.registerForXStart(this)
25 | awaitingXStart(in)
26 | }
27 |
28 | /**
29 | * @param in the active upstream
30 | */
31 | def awaitingXStart(in: Inport) = state(
32 | xStart = () => {
33 | in.request(Long.MaxValue)
34 | running(in)
35 | })
36 |
37 | /**
38 | * @param in the active upstream
39 | */
40 | def running(in: Inport) = state(
41 | onNext = (elem, _) ⇒ {
42 | try {
43 | callback(elem)
44 | stay()
45 | } catch {
46 | case NonFatal(e) =>
47 | terminationPromise.failure(e)
48 | stopCancel(in)
49 | }
50 | },
51 |
52 | onComplete = _ ⇒ {
53 | terminationPromise.success(())
54 | stop()
55 | },
56 |
57 | onError = (e, _) ⇒ {
58 | terminationPromise.failure(e)
59 | stop(e)
60 | })
61 | }
62 |
--------------------------------------------------------------------------------
/docs/src/paradox/_template/assets/vendor/highlight/github.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | github.com style (c) Vasily Polovnyov
4 |
5 | */
6 |
7 | .hljs {
8 | display: block;
9 | overflow-x: auto;
10 | padding: 0.5em;
11 | color: #333;
12 | background: #f8f8f8;
13 | }
14 |
15 | .hljs-comment,
16 | .hljs-quote {
17 | color: #998;
18 | font-style: italic;
19 | }
20 |
21 | .hljs-keyword,
22 | .hljs-selector-tag,
23 | .hljs-subst {
24 | color: #333;
25 | font-weight: bold;
26 | }
27 |
28 | .hljs-number,
29 | .hljs-literal,
30 | .hljs-variable,
31 | .hljs-template-variable,
32 | .hljs-tag .hljs-attr {
33 | color: #008080;
34 | }
35 |
36 | .hljs-string,
37 | .hljs-doctag {
38 | color: #d14;
39 | }
40 |
41 | .hljs-title,
42 | .hljs-section,
43 | .hljs-selector-id {
44 | color: #900;
45 | font-weight: bold;
46 | }
47 |
48 | .hljs-subst {
49 | font-weight: normal;
50 | }
51 |
52 | .hljs-type,
53 | .hljs-class .hljs-title {
54 | color: #458;
55 | font-weight: bold;
56 | }
57 |
58 | .hljs-tag,
59 | .hljs-name,
60 | .hljs-attribute {
61 | color: #000080;
62 | font-weight: normal;
63 | }
64 |
65 | .hljs-regexp,
66 | .hljs-link {
67 | color: #009926;
68 | }
69 |
70 | .hljs-symbol,
71 | .hljs-bullet {
72 | color: #990073;
73 | }
74 |
75 | .hljs-built_in,
76 | .hljs-builtin-name {
77 | color: #0086b3;
78 | }
79 |
80 | .hljs-meta {
81 | color: #999;
82 | font-weight: bold;
83 | }
84 |
85 | .hljs-deletion {
86 | background: #fdd;
87 | }
88 |
89 | .hljs-addition {
90 | background: #dfd;
91 | }
92 |
93 | .hljs-emphasis {
94 | font-style: italic;
95 | }
96 |
97 | .hljs-strong {
98 | font-weight: bold;
99 | }
100 |
--------------------------------------------------------------------------------
/core/src/main/java/swave/core/impl/Statics.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright © 2016 Mathias Doenitz
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package swave.core.impl;
18 |
19 | final class Statics {
20 |
21 | static final Integer _0 = 0;
22 | static final Integer _1 = 1;
23 | static final Integer _2 = 2;
24 | static final Integer _3 = 3;
25 | static final Integer _4 = 4;
26 | static final Integer _5 = 5;
27 | static final Integer _6 = 6;
28 | static final Integer _7 = 7;
29 | static final Integer _8 = 8;
30 | static final Integer _9 = 9;
31 | static final Integer _10 = 10;
32 | static final Integer _11 = 11;
33 | static final Integer _12 = 12;
34 |
35 | static final java.lang.Integer[] NEG_INTS = {
36 | -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16,
37 | -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32
38 | };
39 | static final java.lang.Integer[] INTS_PLUS_100 = {
40 | 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
41 | 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132
42 | };
43 | }
--------------------------------------------------------------------------------
/docs/src/paradox/_template/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
30 |
--------------------------------------------------------------------------------
/core-macros/src/main/scala/swave/core/macros/ConnectFanInAndSealWith.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.macros
8 |
9 | private[macros] trait ConnectFanInAndSealWith { this: Util =>
10 | val c: scala.reflect.macros.whitebox.Context
11 | import c.universe._
12 |
13 | def connectFanInAndSealWith(f: Tree): List[Tree] = unblock {
14 | val q"($out0: $_) => $block0" = f
15 | val out = freshName("out")
16 | val block = replaceIdents(block0, out0 -> out)
17 |
18 | q"""
19 | initialState(connecting(null, subs))
20 | subs.foreach(_.in.subscribe()) // TODO: avoid function allocation
21 |
22 | def connecting(out: Outport, pendingSubs: InportList): State = state(
23 | intercept = false,
24 |
25 | onSubscribe = from ⇒ connecting(out, pendingSubs.remove_!(from)),
26 |
27 | subscribe = from ⇒ {
28 | if (out eq null) {
29 | _outputStages = from.stageImpl :: Nil
30 | from.onSubscribe()
31 | connecting(from, pendingSubs)
32 | } else failAlreadyConnected("Downstream", from)
33 | },
34 |
35 | xSeal = () ⇒ {
36 | if (out ne null) {
37 | if (pendingSubs.isEmpty) {
38 | out.xSeal(region)
39 | subs.foreach(_.in.xSeal(region)) // TODO: avoid function allocation
40 | val $out = out
41 | $block
42 | } else failUnclosedStreamGraph("upstream")
43 | } else failUnclosedStreamGraph("downstream")
44 | })
45 | """
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/TakeWithinStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import scala.concurrent.duration._
10 | import swave.core.impl.stages.InOutStage
11 | import swave.core.{Cancellable, Stage}
12 | import swave.core.impl.{Inport, Outport, RunContext}
13 | import swave.core.macros._
14 |
15 | // format: OFF
16 | @StageImplementation
17 | private[core] final class TakeWithinStage(duration: FiniteDuration) extends InOutStage {
18 |
19 | requireArg(duration >= Duration.Zero, "The `duration` must be non-negative")
20 |
21 | def kind = Stage.Kind.InOut.TakeWithin(duration)
22 |
23 | connectInOutAndSealWith { (in, out) ⇒
24 | region.impl.requestDispatcherAssignment()
25 | region.impl.registerForXStart(this)
26 | awaitingXStart(in, out)
27 | }
28 |
29 | def awaitingXStart(in: Inport, out: Outport) = state(
30 | xStart = () => running(in, out, region.impl.scheduleTimeout(this, duration)))
31 |
32 | def running(in: Inport, out: Outport, timer: Cancellable) = state(
33 | intercept = false,
34 |
35 | request = requestF(in),
36 |
37 | cancel = _ => {
38 | timer.cancel()
39 | stopCancel(in)
40 | },
41 |
42 | onNext = (elem, _) ⇒ {
43 | out.onNext(elem)
44 | stay()
45 | },
46 |
47 | onComplete = _ => {
48 | timer.cancel()
49 | stopComplete(out)
50 | },
51 |
52 | onError = (e, _) => {
53 | timer.cancel()
54 | stopError(e, out)
55 | },
56 |
57 | xEvent = { case RunContext.Timeout(t) if t eq timer => stopComplete(out) })
58 | }
59 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/spout/UnfoldSpoutStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.spout
8 |
9 | import scala.annotation.tailrec
10 | import scala.util.control.NonFatal
11 | import swave.core.Stage
12 | import swave.core.impl.Outport
13 | import swave.core.macros.StageImplementation
14 | import swave.core.Spout.Unfolding
15 | import swave.core.impl.stages.SpoutStage
16 |
17 | // format: OFF
18 | @StageImplementation(interceptAllRequests = true)
19 | private[core] final class UnfoldSpoutStage(zero: AnyRef, f: AnyRef => Unfolding[AnyRef, AnyRef]) extends SpoutStage {
20 |
21 | def kind = Stage.Kind.Spout.Unfold(zero, f)
22 |
23 | connectOutAndSealWith { out ⇒ running(out, zero) }
24 |
25 | def running(out: Outport, s: AnyRef): State = state(
26 | request = (n, _) ⇒ {
27 | @tailrec def rec(n: Int, s: AnyRef): State =
28 | if (n > 0) {
29 | var funError: Throwable = null
30 | val unfolding = try f(s) catch { case NonFatal(e) => { funError = e; null } }
31 | if (funError eq null) {
32 | unfolding match {
33 | case Unfolding.Emit(elem, next) =>
34 | out.onNext(elem)
35 | rec(n - 1, next)
36 | case Unfolding.EmitFinal(elem) =>
37 | out.onNext(elem)
38 | stopComplete(out)
39 | case Unfolding.Complete =>
40 | stopComplete(out)
41 | }
42 | } else stopError(funError, out)
43 | } else running(out, s)
44 | rec(n, s)
45 | },
46 |
47 | cancel = stopF)
48 | }
49 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/rs/helpers.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.rs
8 |
9 | import org.reactivestreams._
10 | import swave.core.impl.stages.StageImpl
11 |
12 | private[impl] class ForwardToRunnerSubscription(stage: StageImpl) extends Subscription {
13 | def request(n: Long) =
14 | if (n > 0) stage.region.enqueueRequest(stage, n, stage)
15 | else stage.region.enqueueXEvent(stage, ForwardToRunnerSubscription.IllegalRequest(n))
16 | def cancel() = stage.region.enqueueCancel(stage, stage)
17 | }
18 |
19 | private[impl] object ForwardToRunnerSubscription {
20 | final case class IllegalRequest(n: Long)
21 | }
22 |
23 | private[core] class SubPubProcessor[A, B](sub: Subscriber[A], pub: Publisher[B]) extends Processor[A, B] {
24 | override def subscribe(s: Subscriber[_ >: B]): Unit = pub.subscribe(s)
25 | override def onSubscribe(s: Subscription): Unit = sub.onSubscribe(s)
26 | override def onNext(elem: A): Unit = sub.onNext(elem)
27 | override def onComplete(): Unit = sub.onComplete()
28 | override def onError(e: Throwable): Unit = sub.onError(e)
29 | }
30 |
31 | private[impl] object RSCompliance {
32 | def verifyNonNull(value: AnyRef, subject: String, ruleNumber: String): Unit =
33 | if (value eq null)
34 | throw new NullPointerException(s"$subject must be non-null (see reactive-streams spec, rule $ruleNumber)")
35 |
36 | class IllegalRequestCountException
37 | extends IllegalArgumentException(
38 | "The number of elements requested must be > 0 (see reactive-streams spec, rule 3.9)")
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/img/line-fanin3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scaladays/img/line-fanin3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/WithLimitStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import scala.util.control.NonFatal
10 | import swave.core.{Stage, StreamLimitExceeded}
11 | import swave.core.impl.stages.InOutStage
12 | import swave.core.impl.{Inport, Outport}
13 | import swave.core.macros._
14 |
15 | // format: OFF
16 | @StageImplementation
17 | private[core] final class WithLimitStage(max: Long, cost: Any ⇒ Long) extends InOutStage {
18 |
19 | requireArg(max >= 0, "`max` must be >= 0")
20 |
21 | def kind = Stage.Kind.InOut.WithLimit(max, cost)
22 |
23 | connectInOutAndSealWith { (in, out) ⇒ running(in, out, max) }
24 |
25 | /**
26 | * @param in the active upstream
27 | * @param out the active downstream
28 | * @param remaining max number of elements still allowed before completion, >= 0
29 | */
30 | def running(in: Inport, out: Outport, remaining: Long): State = state(
31 | request = requestF(in),
32 | cancel = stopCancelF(in),
33 |
34 | onNext = (elem, _) ⇒ {
35 | var funError: Throwable = null
36 | val rem = try remaining - cost(elem) catch { case NonFatal(e) => { funError = e; 0L } }
37 | if (funError eq null) {
38 | if (rem >= 0) {
39 | out.onNext(elem)
40 | running(in, out, rem)
41 | } else {
42 | in.cancel()
43 | stopError(StreamLimitExceeded(max, elem), out)
44 | }
45 | } else {
46 | in.cancel()
47 | stopError(funError, out)
48 | }
49 | },
50 |
51 | onComplete = stopCompleteF(out),
52 | onError = stopErrorF(out))
53 | }
54 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/util/RichSeq.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.util
8 |
9 | import scala.annotation.tailrec
10 | import scala.collection.LinearSeq
11 | import scala.collection.generic.CanBuildFrom
12 | import swave.core.macros._
13 |
14 | final class RichSeq[A](val underlying: Seq[A]) extends AnyVal {
15 |
16 | def mapFind[B](f: A ⇒ Option[B]): Option[B] = {
17 | @tailrec def linearRec(seq: LinearSeq[A]): Option[B] =
18 | if (seq.nonEmpty) {
19 | val x = f(seq.head)
20 | if (x.isEmpty) linearRec(seq.tail) else x
21 | } else None
22 |
23 | @tailrec def indexedRec(ix: Int): Option[B] =
24 | if (ix < underlying.length) {
25 | val x = f(underlying(ix))
26 | if (x.isEmpty) indexedRec(ix + 1) else x
27 | } else None
28 |
29 | underlying match {
30 | case x: LinearSeq[A] ⇒ linearRec(x)
31 | case _ ⇒ indexedRec(0)
32 | }
33 | }
34 |
35 | def foreachWithIndex(f: (A, Int) ⇒ Unit): Unit = {
36 | requireState(underlying.isInstanceOf[IndexedSeq[A]])
37 | @tailrec def rec(ix: Int): Unit =
38 | if (ix < underlying.size) {
39 | f(underlying(ix), ix)
40 | rec(ix + 1)
41 | }
42 | rec(0)
43 | }
44 |
45 | def mapWithIndex[B, That](f: (A, Int) ⇒ B)(implicit bf: CanBuildFrom[Seq[A], B, That]): That = {
46 | requireState(underlying.isInstanceOf[IndexedSeq[A]])
47 | val b = bf(underlying)
48 | b.sizeHint(underlying)
49 | @tailrec def rec(ix: Int): Unit =
50 | if (ix < underlying.size) {
51 | b += f(underlying(ix), ix)
52 | rec(ix + 1)
53 | }
54 | rec(0)
55 | b.result()
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/inout/DropStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.inout
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.stages.InOutStage
11 | import swave.core.impl.{Inport, Outport}
12 | import swave.core.macros._
13 |
14 | // format: OFF
15 | @StageImplementation
16 | private[core] final class DropStage(count: Long) extends InOutStage {
17 |
18 | requireArg(count > 0, "`count` must be > 0")
19 |
20 | def kind = Stage.Kind.InOut.Drop(count)
21 |
22 | connectInOutAndSealWith { (in, out) ⇒
23 | region.impl.registerForXStart(this)
24 | running(in, out)
25 | }
26 |
27 | def running(in: Inport, out: Outport) = {
28 |
29 | def awaitingXStart() = state(
30 | xStart = () => {
31 | in.request(count)
32 | dropping(count)
33 | })
34 |
35 | /**
36 | * Waiting for elements from upstream to drop.
37 | *
38 | * @param remaining number of elems still to drop, >0
39 | */
40 | def dropping(remaining: Long): State = state(
41 | request = requestF(in),
42 | cancel = stopCancelF(in),
43 | onNext = (_, _) ⇒ if (remaining > 1) dropping(remaining - 1) else draining(),
44 | onComplete = stopCompleteF(out),
45 | onError = stopErrorF(out))
46 |
47 | /**
48 | * Simply forwarding elements from upstream to downstream.
49 | */
50 | def draining() = state(
51 | intercept = false,
52 |
53 | request = requestF(in),
54 | cancel = stopCancelF(in),
55 | onNext = onNextF(out),
56 | onComplete = stopCompleteF(out),
57 | onError = stopErrorF(out))
58 |
59 | awaitingXStart()
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/fanin/ConcatStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.fanin
8 |
9 | import swave.core.Stage
10 | import swave.core.impl.Outport
11 | import swave.core.impl.stages.FanInStage
12 | import swave.core.impl.util.InportList
13 | import swave.core.macros._
14 | import swave.core.util._
15 |
16 | // format: OFF
17 | @StageImplementation(fullInterceptions = true, manualInportList = "subs")
18 | private[core] final class ConcatStage(subs: InportList) extends FanInStage(subs) {
19 |
20 | requireArg(subs.nonEmpty, "Cannot `concat` an empty set of sub-streams")
21 |
22 | def kind = Stage.Kind.FanIn.Concat
23 |
24 | connectFanInAndSealWith { out ⇒ running(out, subs, 0) }
25 |
26 | /**
27 | * @param out the active downstream
28 | * @param ins the active upstreams
29 | * @param pending number of elements requested from upstream but not yet received, >= 0
30 | */
31 | def running(out: Outport, ins: InportList, pending: Long): State = state(
32 | request = (n, _) ⇒ {
33 | ins.in.request(n.toLong)
34 | running(out, ins, pending ⊹ n)
35 | },
36 |
37 | cancel = stopCancelF(ins),
38 |
39 | onNext = (elem, _) ⇒ {
40 | out.onNext(elem)
41 | running(out, ins, pending - 1)
42 | },
43 |
44 | onComplete = in ⇒ {
45 | if (in eq ins.in) {
46 | val tail = ins.tail
47 | if (tail.nonEmpty) {
48 | if (pending > 0) tail.in.request(pending)
49 | running(out, tail, pending)
50 | } else stopComplete(out)
51 | } else running(out, ins remove_! in, pending)
52 | },
53 |
54 | onError = cancelAllAndStopErrorF(ins, out))
55 | }
56 |
--------------------------------------------------------------------------------
/core-macros/src/main/scala/swave/core/macros/Macros.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core
8 |
9 | import scala.reflect.macros.blackbox
10 |
11 | package object macros {
12 |
13 | def requireArg(cond: Boolean): Unit = macro Macros.requireArgImpl
14 |
15 | def requireArg(cond: Boolean, msg: Any): Unit = macro Macros.requireArg1Impl
16 |
17 | def requireState(cond: Boolean): Unit = macro Macros.requireStateImpl
18 |
19 | def requireState(cond: Boolean, msg: Any): Unit = macro Macros.requireState1Impl
20 | }
21 |
22 | package macros {
23 | private[macros] object Macros {
24 |
25 | def requireArgImpl(c: blackbox.Context)(cond: c.Expr[Boolean]): c.Expr[Unit] = {
26 | import c.universe._
27 | reify {
28 | if (!cond.splice) throw new IllegalArgumentException
29 | }
30 | }
31 |
32 | def requireArg1Impl(c: blackbox.Context)(cond: c.Expr[Boolean], msg: c.Expr[Any]): c.Expr[Unit] = {
33 | import c.universe._
34 | reify {
35 | if (!cond.splice) {
36 | throw new IllegalArgumentException(msg.splice.toString)
37 | }
38 | }
39 | }
40 |
41 | def requireStateImpl(c: blackbox.Context)(cond: c.Expr[Boolean]): c.Expr[Unit] = {
42 | import c.universe._
43 | reify {
44 | if (!cond.splice) {
45 | throw new IllegalStateException
46 | }
47 | }
48 | }
49 |
50 | def requireState1Impl(c: blackbox.Context)(cond: c.Expr[Boolean], msg: c.Expr[Any]): c.Expr[Unit] = {
51 | import c.universe._
52 | reify {
53 | if (!cond.splice) {
54 | throw new IllegalStateException(msg.splice.toString)
55 | }
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scalar/img/not-the-other-way-around.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/graph/impl/LineRendering.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.graph.impl
8 |
9 | import java.lang.StringBuilder
10 | import swave.core.graph.{Digraph, GlyphSet}
11 | import scala.collection.immutable.VectorBuilder
12 | import Infrastructure._
13 |
14 | private[graph] object LineRendering {
15 |
16 | def renderLines[V](nodes: Vector[Node], glyphSet: GlyphSet): Digraph.Rendering[V] = {
17 | var charBuf: Array[Char] = Array.emptyCharArray
18 | val lines = new VectorBuilder[String]
19 | val sb = new StringBuilder
20 | var maxLineLength = 0
21 |
22 | val vertexRenderings =
23 | for (node ← nodes) yield {
24 | val maxChars = node.glyphs.size * glyphSet.columns * 2
25 | if (charBuf.length < maxChars) charBuf = new Array[Char](maxChars)
26 | lines.clear()
27 |
28 | for (glyphRow ← 0 until glyphSet.rows) {
29 | val endIx = node.glyphs.foldLeft(0)((ix, glyph) ⇒ glyphSet.place(glyph, glyphRow, charBuf, ix))
30 | sb.append(charBuf, 0, endIx)
31 | // trim whitespace at line end
32 | while (sb.length > 0 && Character.isWhitespace(sb.charAt(sb.length - 1))) sb.setLength(sb.length - 1)
33 | // if (glyphRow == glyphSet.rows / 2) sb.append(' ').append(node.xRank.level)
34 | val line = sb.toString
35 | maxLineLength = math.max(maxLineLength, line.length)
36 | lines += line
37 | sb.setLength(0)
38 | }
39 |
40 | Digraph.VertexRendering(node.vertex.asInstanceOf[V], lines.result())
41 | }
42 |
43 | Digraph.Rendering(glyphSet, maxLineLength, vertexRenderings)
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/core/src/main/scala/swave/core/impl/stages/drain/SubscriberDrainStage.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * This Source Code Form is subject to the terms of the Mozilla Public
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 | */
6 |
7 | package swave.core.impl.stages.drain
8 |
9 | import org.reactivestreams.Subscriber
10 | import swave.core.Stage
11 | import swave.core.impl.Inport
12 | import swave.core.impl.rs.ForwardToRunnerSubscription
13 | import swave.core.impl.stages.DrainStage
14 | import swave.core.macros.StageImplementation
15 |
16 | // format: OFF
17 | @StageImplementation
18 | private[core] final class SubscriberDrainStage(subscriber: Subscriber[AnyRef]) extends DrainStage {
19 |
20 | def kind = Stage.Kind.Drain.FromSubscriber(subscriber)
21 |
22 | connectInAndSealWith { in ⇒
23 | region.impl.requestDispatcherAssignment()
24 | region.impl.registerForXStart(this)
25 | awaitingXStart(in)
26 | }
27 |
28 | def awaitingXStart(in: Inport): State = state(
29 | xStart = () => {
30 | subscriber.onSubscribe(new ForwardToRunnerSubscription(this))
31 | running(in)
32 | })
33 |
34 | def running(in: Inport): State = state(
35 | intercept = false,
36 |
37 | request = requestF(in),
38 | cancel = stopCancelF(in),
39 |
40 | onNext = (elem, _) => {
41 | subscriber.onNext(elem)
42 | stay()
43 | },
44 |
45 | onComplete = _ => {
46 | subscriber.onComplete()
47 | stop()
48 | },
49 |
50 | onError = (e, _) => {
51 | subscriber.onError(e)
52 | stop(e)
53 | },
54 |
55 | xEvent = { case ForwardToRunnerSubscription.IllegalRequest(n) =>
56 | subscriber.onError(new IllegalArgumentException(
57 | "The number of elements requested must be > 0 (see reactive-streams spec, rule 3.9)"))
58 | stopCancel(in)
59 | })
60 | }
61 |
--------------------------------------------------------------------------------
/docs/src/paradox/talks/2016/scala.io/img/not-the-other-way-around.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------