-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
1,047 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#Rx features | ||
part of [`kovenant-rx`](../index.md#artifacts) | ||
|
||
--- | ||
Addon project for converting back and forth between `Kovenant` `Promise`s and rx `Observable`s. | ||
|
||
|
||
##ToPromise | ||
Any `Observable` can be turned into a `Promise` but understand that there is a fundamental difference between the two. | ||
A `Promise` represents a single value that either is successful or failed. An `Observable` on the other hand represents | ||
a stream of values which results in the following possible states: | ||
|
||
* emit nothing. | ||
* emit an error. | ||
* emit completed without data | ||
* emit completed after single value | ||
* emit completed after multiple values | ||
* emit multiple values but never completed | ||
|
||
To convert from an `Observable` to a `Promise` you simply do: | ||
|
||
```kt | ||
val values = arrayOf(1, 2, 3, 4, 5) | ||
val observable = Observable.from(values) | ||
val promise = observable.toPromise() | ||
``` | ||
|
||
By default `toPromise()` will create a promise that will resolve successful with the first emitted value. It will | ||
resolve as failed if there are no values emitted but the `Observable` emits completed. This will thus lead to: | ||
|
||
* emit nothing - _promise doesn't complete_ | ||
* emit an error - _promise resolves as failed, if no other value was emitted_ | ||
* emit completed without data - _promise resolves as failed_ | ||
* emit completed after single value - _promise resolves successful with value_ | ||
* emit completed after multiple values - _promise resolves successful with first value_ | ||
* emit multiple values but never completed - _promise resolves successful with first value_ | ||
|
||
###EmitStrategy | ||
By default `toPromise()` resolves successful with the first emitted value. If you'd rather resolve by the last emitted | ||
value you can change the behaviour by calling: | ||
|
||
```kt | ||
val promise = observable.toPromise(strategy = EmitStrategy.LAST) | ||
``` | ||
|
||
###EmptyPolicy | ||
By default `toPromise()` resolves as failed if the `Observable` is completed but hasn't emitted a value. To control | ||
the behaviour of the promise when the `Observable` is empty you can create one of the following EmptyPolicies: | ||
|
||
```kt | ||
//resolve with value | ||
EmptyPolicy.resolve (42) | ||
|
||
//resolve with factory value | ||
EmptyPolicy.resolve { 42 } | ||
|
||
//reject with eception | ||
EmptyPolicy.reject(Exception()) | ||
|
||
//reject with exception factory | ||
EmptyPolicy.reject { Exception() } | ||
|
||
``` | ||
|
||
And you can use them like this: | ||
|
||
```kt | ||
val promise = observable.toPromise(emptyPolicy = EmptyPolicy.resolve (42)) | ||
``` | ||
|
||
There is also a shorthand for this common case, so you can always resolve successful with a default value: | ||
|
||
```kt | ||
val promise = observable.toPromise(42) | ||
//or with a factory | ||
val promise = observable.toPromise() { 42 } | ||
``` | ||
|
||
##ToListPromise | ||
Instead of converting an `Observable` to a single value we can also simply put al te results in a `List`. This is as | ||
simple as: | ||
|
||
```kt | ||
val promise = observable.toListPromise() | ||
``` | ||
The only requirement for this to work is that the `Observable` actually emits completed at some point in the | ||
future. | ||
|
||
##ToObservable | ||
|
||
To turn a `Promise` into an `Observable` you can simply call `toObservable()`. Note that by default the | ||
`Observable` is observed on the callback `Dispatcher` of the `Promise` in question. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package nl.komponents.kovenant.unsafe | ||
|
||
import sun.misc.Unsafe | ||
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater | ||
import kotlin.reflect.KClass | ||
|
||
class UnsafeAtomicReferenceFieldUpdater<C : Any, V : Any>(targetClass: KClass<C>, | ||
fieldName: String) : AtomicReferenceFieldUpdater<C, V>() { | ||
companion object { | ||
private val unsafe = getUnsafe() | ||
} | ||
|
||
private val offset: Long | ||
|
||
init { | ||
val field = targetClass.java.getDeclaredField(fieldName) | ||
offset = unsafe.objectFieldOffset(field) | ||
} | ||
|
||
override fun lazySet(target: C, newValue: V?) = unsafe.putOrderedObject(target, offset, newValue) | ||
override fun compareAndSet(target: C, expected: V?, update: V?): Boolean = unsafe.compareAndSwapObject(target, offset, expected, update) | ||
|
||
override fun set(target: C, newValue: V?) = unsafe.putObjectVolatile(target, offset, newValue); | ||
|
||
@Suppress("UNCHECKED_CAST") | ||
override fun get(target: C): V? = unsafe.getObjectVolatile(target, offset) as V | ||
|
||
//Equals AtomicReferenceFieldUpdater implementation on Java 8 | ||
override fun weakCompareAndSet(target: C, expected: V?, update: V?): Boolean = compareAndSet(target, expected, update) | ||
} | ||
|
||
|
||
fun hasUnsafe(): Boolean { | ||
try { | ||
Class.forName("sun.misc.Unsafe") | ||
return true | ||
} catch(e: ClassNotFoundException) { | ||
return false | ||
} | ||
} | ||
|
||
private fun getUnsafe(): Unsafe { | ||
try { | ||
val field = Unsafe::class.java.getDeclaredField("theUnsafe"); | ||
field.isAccessible = true; | ||
return field.get(null) as Unsafe; | ||
|
||
} catch (e: Exception) { | ||
throw RuntimeException("unsafe doesn't exist or is not accessible") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.