├── 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 | ![swave](.../swave-logo.svg "swave") 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 | ![A Coupling](.../coupling.svg) 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 | Produced by OmniGraffle 6.5 2016-06-17 08:44:40 +0000Canvas 11Layer 1 4 | -------------------------------------------------------------------------------- /docs/src/paradox/talks/2016/scaladays/img/small-inout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Produced by OmniGraffle 6.5 2016-06-17 08:44:40 +0000Canvas 11Layer 1 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 | Produced by OmniGraffle 6.5 2016-06-17 08:44:40 +0000Canvas 11Layer 1 4 | -------------------------------------------------------------------------------- /docs/src/paradox/talks/2016/scaladays/img/small-inject.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Produced by OmniGraffle 6.5 2016-06-17 08:44:40 +0000Canvas 11Layer 1 4 | -------------------------------------------------------------------------------- /docs/src/paradox/talks/2016/scala.io/img/small-flatten.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Produced by OmniGraffle 6.5 2016-06-17 08:44:40 +0000Canvas 11Layer 1 4 | -------------------------------------------------------------------------------- /docs/src/paradox/talks/2016/scaladays/img/small-flatten.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Produced by OmniGraffle 6.5 2016-06-17 08:44:40 +0000Canvas 11Layer 1 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 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 28 | 29 | 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 | Produced by OmniGraffle 6.5 2016-06-17 10:30:01 +0000Canvas 12Layer 1 4 | -------------------------------------------------------------------------------- /docs/src/paradox/talks/2016/scaladays/img/line-fanin3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Produced by OmniGraffle 6.5 2016-06-17 10:30:01 +0000Canvas 12Layer 1 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 | Produced by OmniGraffle 6.5 2016-04-15 08:04:48 +0000Canvas 13Layer 1But not the other way around! 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 | Produced by OmniGraffle 6.5 2016-04-15 08:04:48 +0000Canvas 13Layer 1But not the other way around! 4 | --------------------------------------------------------------------------------