Skip to content

Commit

Permalink
Create Bitrate class (#1)
Browse files Browse the repository at this point in the history
* Create empty Bitrate module

* Create Bitrate

* Update example
  • Loading branch information
boswelja authored Apr 5, 2024
1 parent d21134a commit 15c15ac
Show file tree
Hide file tree
Showing 7 changed files with 466 additions and 0 deletions.
1 change: 1 addition & 0 deletions bitrate/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
3 changes: 3 additions & 0 deletions bitrate/MODULE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Module bitrate

Store and convert between units of data transfer speed. For example, `100Mbit/s` --> `0.1Gbit/s`.
140 changes: 140 additions & 0 deletions bitrate/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import org.jetbrains.dokka.gradle.DokkaTaskPartial
import java.net.URL

plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.android.library)

alias(libs.plugins.detekt)

alias(libs.plugins.dokka)

id("maven-publish")
id("signing")
}

group = findProperty("group")!!
version = findProperty("version")!!

android {
namespace = "com.boswelja.bitrate"

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}

lint {
sarifReport = true
htmlReport = false
}

publishing {
singleVariant("release") {
withJavadocJar()
withSourcesJar()
}
}
}

kotlin {
androidTarget {
publishLibraryVariants("release")
}
jvm()
jvmToolchain(17)

sourceSets {
commonMain {
dependencies {
implementation(kotlin("stdlib"))
}
}
commonTest {
dependencies {
implementation(kotlin("test"))
}
}
}
}

detekt {
buildUponDefaultConfig = true
config.setFrom("$rootDir/config/detekt.yml")
basePath = rootDir.absolutePath
}

signing {
val signingKey: String? by project
val signingPassword: String? by project
useInMemoryPgpKeys(signingKey, signingPassword)
sign(publishing.publications)
}

publishing {
repositories {
if (System.getenv("PUBLISHING") == "true") {
maven("https://maven.pkg.github.com/boswelja/kotlin-datatypes") {
val githubUsername: String? by project.properties
val githubToken: String? by project.properties
name = "github"
credentials {
username = githubUsername
password = githubToken
}
}
maven("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
val ossrhUsername: String? by project
val ossrhPassword: String? by project
name = "oss"
credentials {
username = ossrhUsername
password = ossrhPassword
}
}
}
}

publications.withType<MavenPublication> {
pom {
name = "bitrate"
description = "A Bitrate class that allows you to convert between any unit of data transfer speed"
url = "https://github.com/boswelja/kotlin-datatypes/tree/main/bitrate"
licenses {
license {
name = "MIT"
url = "https://github.com/boswelja/kotlin-datatypes/blob/main/LICENSE"
}
}
developers {
developer {
id = "boswelja"
name = "Jack Boswell (boswelja)"
email = "[email protected]"
url = "https://github.com/boswelja"
}
}
scm {
connection.set("scm:git:github.com/boswelja/kotlin-datatypes.git")
developerConnection.set("scm:git:ssh://github.com/boswelja/kotlin-datatypes.git")
url.set("https://github.com/boswelja/kotlin-datatypes")
}
}
}
}

tasks.withType<DokkaTaskPartial>().configureEach {
dokkaSourceSets.configureEach {
includes.from("MODULE.md")
sourceLink {
localDirectory.set(projectDir.resolve("src"))
remoteUrl.set(URL("https://github.com/boswelja/kotlin-datatypes/tree/main/bitrate/src"))
remoteLineSuffix.set("#L")
}
}
}
215 changes: 215 additions & 0 deletions bitrate/src/commonMain/kotlin/com/boswelja/bitrate/Bitrate.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package com.boswelja.bitrate

import kotlin.math.roundToLong

/**
* Represents an amount of bits that are processed per second.
*
* Bitrate can represent ±8 exabits/s.
*
* To construct a Bitrate, use the extension functions [kilobits], [megabits], [gigabits], and so on.
*
* To get the value of this Capacity expressed in a particular CapacityUnit, use the functions
* [toLong], [toDouble], and so on.
*/
@JvmInline
value class Bitrate internal constructor(private val rawValue: Long) : Comparable<Bitrate> {

override fun compareTo(other: Bitrate): Int {
return rawValue.compareTo(other.rawValue)
}

/**
* Adds [other] to this Bitrate. This currently does **not** handle integer overflow.
*/
operator fun plus(other: Bitrate): Bitrate {
return Bitrate(rawValue + other.rawValue)
}

/**
* Subtracts [other] from this Bitrate. This currently does **not** handle integer overflow.
*/
operator fun minus(other: Bitrate): Bitrate {
return Bitrate(rawValue - other.rawValue)
}

/**
* Converts this Bitrate to the given [BitrateUnit], returning a Double representing the
* precise value.
*/
fun toDouble(unit: BitrateUnit): Double {
return rawValue.toDouble() / unit.bitFactor
}

/**
* Converts this Bitrate to the given [BitrateUnit], rounding to the nearest whole number.
*/
fun toLong(unit: BitrateUnit): Long {
return toDouble(unit).roundToLong()
}

@Suppress("unused")
companion object {

private fun Int.toBitrate(unit: BitrateUnit): Bitrate = Bitrate(this * unit.bitFactor)
private fun Long.toBitrate(unit: BitrateUnit): Bitrate = Bitrate(this * unit.bitFactor)
private fun Float.toBitrate(unit: BitrateUnit): Bitrate = Bitrate((this * unit.bitFactor).roundToLong())
private fun Double.toBitrate(unit: BitrateUnit): Bitrate = Bitrate((this * unit.bitFactor).roundToLong())

// region bits
/** Converts an [Int] representation of bits to a [Bitrate]. */
val Int.bits: Bitrate get() = Bitrate(toLong())

/** Converts a [Long] representation of bits to a [Bitrate]. */
val Long.bits: Bitrate get() = Bitrate(this)
// endregion

// region binary units
/** Converts an [Int] representation of kibibits to a [Bitrate]. */
val Int.kibibits: Bitrate get() = toBitrate(BitrateUnit.KIBIBITS)

/** Converts an [Int] representation of mebibits to a [Bitrate]. */
val Int.mebibits: Bitrate get() = toBitrate(BitrateUnit.MEBIBITS)

/** Converts an [Int] representation of gibibits to a [Bitrate]. */
val Int.gibibits: Bitrate get() = toBitrate(BitrateUnit.GIBIBITS)

/** Converts an [Int] representation of tebibits to a [Bitrate]. */
val Int.tebibits: Bitrate get() = toBitrate(BitrateUnit.TEBIBITS)

/** Converts an [Int] representation of pebibits to a [Bitrate]. */
val Int.pebibits: Bitrate get() = toBitrate(BitrateUnit.PEBIBITS)

/** Converts an [Int] representation of exibits to a [Bitrate]. */
val Int.exbibits: Bitrate get() = toBitrate(BitrateUnit.EXBIBITS)

/** Converts a [Long] representation of kibibits to a [Bitrate]. */
val Long.kibibits: Bitrate get() = toBitrate(BitrateUnit.KIBIBITS)

/** Converts a [Long] representation of mebibits to a [Bitrate]. */
val Long.mebibits: Bitrate get() = toBitrate(BitrateUnit.MEBIBITS)

/** Converts a [Long] representation of gibibits to a [Bitrate]. */
val Long.gibibits: Bitrate get() = toBitrate(BitrateUnit.GIBIBITS)

/** Converts a [Long] representation of tebibits to a [Bitrate]. */
val Long.tebibits: Bitrate get() = toBitrate(BitrateUnit.TEBIBITS)

/** Converts a [Long] representation of pebibits to a [Bitrate]. */
val Long.pebibits: Bitrate get() = toBitrate(BitrateUnit.PEBIBITS)

/** Converts a [Long] representation of exibits to a [Bitrate]. */
val Long.exbibits: Bitrate get() = toBitrate(BitrateUnit.EXBIBITS)

/** Converts a [Float] representation of kibibits to a [Bitrate]. */
val Float.kibibits: Bitrate get() = toBitrate(BitrateUnit.KIBIBITS)

/** Converts a [Float] representation of mebibits to a [Bitrate]. */
val Float.mebibits: Bitrate get() = toBitrate(BitrateUnit.MEBIBITS)

/** Converts a [Float] representation of gibibits to a [Bitrate]. */
val Float.gibibits: Bitrate get() = toBitrate(BitrateUnit.GIBIBITS)

/** Converts a [Float] representation of tebibits to a [Bitrate]. */
val Float.tebibits: Bitrate get() = toBitrate(BitrateUnit.TEBIBITS)

/** Converts a [Float] representation of pebibits to a [Bitrate]. */
val Float.pebibits: Bitrate get() = toBitrate(BitrateUnit.PEBIBITS)

/** Converts a [Float] representation of exibits to a [Bitrate]. */
val Float.exbibits: Bitrate get() = toBitrate(BitrateUnit.EXBIBITS)

/** Converts a [Double] representation of kibibits to a [Bitrate]. */
val Double.kibibits: Bitrate get() = toBitrate(BitrateUnit.KIBIBITS)

/** Converts a [Double] representation of mebibits to a [Bitrate]. */
val Double.mebibits: Bitrate get() = toBitrate(BitrateUnit.MEBIBITS)

/** Converts a [Double] representation of gibibits to a [Bitrate]. */
val Double.gibibits: Bitrate get() = toBitrate(BitrateUnit.GIBIBITS)

/** Converts a [Double] representation of tebibits to a [Bitrate]. */
val Double.tebibits: Bitrate get() = toBitrate(BitrateUnit.TEBIBITS)

/** Converts a [Double] representation of pebibits to a [Bitrate]. */
val Double.pebibits: Bitrate get() = toBitrate(BitrateUnit.PEBIBITS)

/** Converts a [Double] representation of exbibits to a [Bitrate]. */
val Double.exbibits: Bitrate get() = toBitrate(BitrateUnit.EXBIBITS)
//endregion

// region decimal units
/** Converts an [Int] representation of kilobits to a [Bitrate]. */
val Int.kilobits: Bitrate get() = toBitrate(BitrateUnit.KILOBITS)

/** Converts an [Int] representation of megabits to a [Bitrate]. */
val Int.megabits: Bitrate get() = toBitrate(BitrateUnit.MEGABITS)

/** Converts an [Int] representation of gigabits to a [Bitrate]. */
val Int.gigabits: Bitrate get() = toBitrate(BitrateUnit.GIGABITS)

/** Converts an [Int] representation of terabits to a [Bitrate]. */
val Int.terabits: Bitrate get() = toBitrate(BitrateUnit.TERABITS)

/** Converts an [Int] representation of petabits to a [Bitrate]. */
val Int.petabits: Bitrate get() = toBitrate(BitrateUnit.PETABITS)

/** Converts an [Int] representation of exabits to a [Bitrate]. */
val Int.exabits: Bitrate get() = toBitrate(BitrateUnit.EXABITS)

/** Converts a [Long] representation of kilobits to a [Bitrate]. */
val Long.kilobits: Bitrate get() = toBitrate(BitrateUnit.KILOBITS)

/** Converts a [Long] representation of megabits to a [Bitrate]. */
val Long.megabits: Bitrate get() = toBitrate(BitrateUnit.MEGABITS)

/** Converts a [Long] representation of gigabits to a [Bitrate]. */
val Long.gigabits: Bitrate get() = toBitrate(BitrateUnit.GIGABITS)

/** Converts a [Long] representation of terabits to a [Bitrate]. */
val Long.terabits: Bitrate get() = toBitrate(BitrateUnit.TERABITS)

/** Converts a [Long] representation of petabits to a [Bitrate]. */
val Long.petabits: Bitrate get() = toBitrate(BitrateUnit.PETABITS)

/** Converts a [Long] representation of exabits to a [Bitrate]. */
val Long.exabits: Bitrate get() = toBitrate(BitrateUnit.EXABITS)

/** Converts a [Float] representation of kilobits to a [Bitrate]. */
val Float.kilobits: Bitrate get() = toBitrate(BitrateUnit.KILOBITS)

/** Converts a [Float] representation of megabits to a [Bitrate]. */
val Float.megabits: Bitrate get() = toBitrate(BitrateUnit.MEGABITS)

/** Converts a [Float] representation of gigabits to a [Bitrate]. */
val Float.gigabits: Bitrate get() = toBitrate(BitrateUnit.GIGABITS)

/** Converts a [Float] representation of terabits to a [Bitrate]. */
val Float.terabits: Bitrate get() = toBitrate(BitrateUnit.TERABITS)

/** Converts a [Float] representation of petabits to a [Bitrate]. */
val Float.petabits: Bitrate get() = toBitrate(BitrateUnit.PETABITS)

/** Converts a [Float] representation of exabits to a [Bitrate]. */
val Float.exabits: Bitrate get() = toBitrate(BitrateUnit.EXABITS)

/** Converts a [Double] representation of kilobits to a [Bitrate]. */
val Double.kilobits: Bitrate get() = toBitrate(BitrateUnit.KILOBITS)

/** Converts a [Double] representation of megabits to a [Bitrate]. */
val Double.megabits: Bitrate get() = toBitrate(BitrateUnit.MEGABITS)

/** Converts a [Double] representation of gigabits to a [Bitrate]. */
val Double.gigabits: Bitrate get() = toBitrate(BitrateUnit.GIGABITS)

/** Converts a [Double] representation of terabits to a [Bitrate]. */
val Double.terabits: Bitrate get() = toBitrate(BitrateUnit.TERABITS)

/** Converts a [Double] representation of petabits to a [Bitrate]. */
val Double.petabits: Bitrate get() = toBitrate(BitrateUnit.PETABITS)

/** Converts a [Double] representation of exabits to a [Bitrate]. */
val Double.exabits: Bitrate get() = toBitrate(BitrateUnit.EXABITS)
//endregion
}
}
25 changes: 25 additions & 0 deletions bitrate/src/commonMain/kotlin/com/boswelja/bitrate/BitrateUnit.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.boswelja.bitrate

/**
* Defines various units supported by [Bitrate]. We can convert to/from any of these.
*/
@Suppress("MagicNumber")
enum class BitrateUnit(internal val bitFactor: Long) {
BITS(1),

// Binary units
KIBIBITS(1024),
MEBIBITS(1048576),
GIBIBITS(1073741824),
TEBIBITS(1_099_511_627_776),
PEBIBITS(1_125_899_906_842_624),
EXBIBITS(1_152_921_504_606_846_976),

// Metric units
KILOBITS(1_000),
MEGABITS(1_000_000),
GIGABITS(1_000_000_000),
TERABITS(1_000_000_000_000),
PETABITS(1_000_000_000_000_000),
EXABITS(1_000_000_000_000_000_000)
}
Loading

0 comments on commit 15c15ac

Please sign in to comment.