Toolbox of utilities/helpers for Kotlin development.
Implementations of List
, Set
, and Map
with strong guarantees around mutability. Each of these collections can be snapshot
to reference their current values without reflecting future changes. A StateFlow
of snapshots
is accessible for receiving hot notifications of mutations. Returned collections and iterators automatically reference the snapshot
of when they were created.
These collections do not implement the various mutable collection interfaces. To mutate these collections, you must use an explicit mutator function. These mutator functions use a lambda to modify the list, and if concurrent mutations occur these lambdas may be ran more than once. In this way each mutation is guaranteed atomic, but you must be careful with side effects.
mutate
updates the collection without returning a value.snapshotAndMutate
updates the collection and returns the snapshot which was used in the successful mutation.mutateAndSnapshot
updates the collection and returns the snapshot which results from the mutation.
Convert a map to a Plain Old JavaScript Object by transforming the keys to strings and the values to any of the JavaScript types.
Map
is not directly accessible from Javascript code. For example:
val simple = mapOf(1 to "a")
val json = js("JSON.stringify(simple)") as String
println(json)
>>>
{
"_keys_up5z3z$_0": null,
"_values_6nw1f1$_0": null,
<and lots of other name-mangled properties>
}
val value = js("simple['1']") as String
println(value)
>>> ClassCastException: Illegal cast
Using this convertor to emit Object
with the expected properties:
val simple = mapOf(1 to "a").toJsObject { it.key.toString() to it.value }
val json = js("JSON.stringify(simple)") as String
println(json)
>>> {"1":"a"}
val value = js("simple['1']") as String
println(value)
>>> a
Utilities for Coroutines.
val combined = combine(
flow1,
flow2,
// ...
flow9,
flow10,
) { value1, value2, /* ... */, value9, value10 ->
// ...
}
Logging has been pulled into its own library, Khronicle.
First, update your gradle files. Be aware that Tuulbox versions and Khronicle versions are not the same.
// For general usage
- implementation("com.juul.tuulbox:logging:$tuulboxVersion")
+ implementation("com.juul.khronicle:khronicle-core:$khronicleVersion")
// For Android only
- implementation("com.juul.tuulbox:logging-android:$tuulboxVersion")
+ implementation("com.juul.khronicle:khronicle-android:$khronicleVersion")
// For Ktor integration only
- implementation("com.juul.tuulbox:logging-ktor-client:$tuulboxVersion")
+ implementation("com.juul.khronicle:khronicle-ktor-client:$khronicleVersion")
Then, update your code. Class names have been kept the same, but package names have changed. This
should be as simple as a find-and-replace of com.juul.tuulbox.logging
with com.juul.khronicle
.
Utilities for manipulating functions.
For a full functional ecosystem, complete with Monad
and the like, prefer Arrow.
Toolbox of utilities for dates and times, building on KotlinX DateTime.
Various interval Flow
s are provided, such as: instantFlow
, localDateTimeFlow
, and localDateFlow
. For example:
localDateTimeFlow().collect {
println("The time is now: $it")
}
Note: Because this is built on top of KotlinX DateTime, core library desugaring must be enabled for Android targets.
Utilities for test suites.
assertContains(
array = arrayOf(1, 2, 3),
value = 2,
)
assertContains(
range = 1..10,
value = 5,
)
Utilities for working with binary data.
val bitSet = 0.bits
bitSet[30] = true
bitSet.asPrimitive() // 1073741824
/* | Index | ... | 3 | 2 | 1 | 0 |
* |-------|-----|---|---|---|---|
* | Bit | ... | 1 | 0 | 1 | 0 |
*/
val bitSet = 10.bits
bitSet[0] // false
bitSet[1] // true
bitSet[2] // false
bitSet[3] // true
/* | Index | ... | 3 | 2 | 1 | 0 |
* |-------|-----|---|---|---|---|
* | Bit | ... | 1 | 1 | 0 | 0 |
*/
val bitSet = 12L.bits
bitSet[0] // false
bitSet[1] // false
bitSet[2] // true
bitSet[3] // true
val bitSet = 0L.bits
bitSet[40] = true
bitSet.asPrimitive() // 1099511627776L
Tuulbox can be configured via Gradle Kotlin DSL as follows:
plugins {
id("com.android.application") // or id("com.android.library")
kotlin("multiplatform")
}
repositories {
mavenCentral()
}
kotlin {
jvm() // and/or android()
js().browser() // and/or js().node()
macosX64()
sourceSets {
val commonMain by getting {
dependencies {
implementation("com.juul.tuulbox:collections:$version")
implementation("com.juul.tuulbox:coroutines:$version")
implementation("com.juul.tuulbox:encoding:$version")
implementation("com.juul.tuulbox:functional:$version")
implementation("com.juul.tuulbox:temporal:$version")
}
}
val commonTest by getting {
dependencies {
implementation("com.juul.tuulbox:test:$version")
}
}
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("com.juul.tuulbox:collections:$version")
implementation("com.juul.tuulbox:coroutines:$version")
implementation("com.juul.tuulbox:encoding:$version")
implementation("com.juul.tuulbox:functional:$version")
implementation("com.juul.tuulbox:temporal:$version")
testImplementation("com.juul.tuulbox:test:$version")
}
Copyright 2021 JUUL Labs, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.