Data Unit Converter — Kotlin source
Convert between digital data units - B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. Switch between decimal (1000) and binary (1024) bases, runs entirely in your browser.
This is the Kotlin implementation — the same logic the interactive tool runs, in a shareable, citable form.
// =============================================================================
// DataUnits.kt — CosmoDev polyglot showcase port of the
// `data-unit-converter` tool
// -----------------------------------------------------------------------------
// Language : Kotlin (1.9, standard library only)
// Source: ported from src/lib/dataUnits.ts (the canonical, live TypeScript
// lib); mirrors src/tool-sources/data-unit-converter/{python.py,rust.rs}
// License : display source — part of CosmoDev's polyglot tool pages
// (dev.cosmolabs.org). Shown verbatim alongside the JS/TS/Go/Rust/
// Python ports and the other language ports.
// -----------------------------------------------------------------------------
// Pure digital-data unit conversion. Convert between B, KB/KiB, MB/MiB,
// GB/GiB, TB/TiB: the decimal base 1000 pairs with KB/MB/GB/TB (SI) and the
// binary base 1024 with KiB/MiB/GiB/TiB (IEC). Deterministic and
// side-effect free; convertData returns Double.NaN for non-finite input,
// unknown unit symbols, or an invalid base — never throws.
// =============================================================================
package org.cosmolabs.cosmodev
import kotlin.math.pow
/**
* Pure digital-data unit conversion for the Data Unit Converter tool on
* CosmoDev (dev.cosmolabs.org). Exposed as an `object` — a stateless
* namespace of pure functions, the idiomatic Kotlin replacement for a static
* utility class.
*/
object DataUnits {
/**
* Units available under each base, ordered smallest (B) to largest. The
* UI uses this to populate the per-base unit pickers. Read-only maps and
* lists throughout — nothing here is mutable.
*/
val units: Map<Int, List<String>> = mapOf(
1000 to listOf("B", "KB", "MB", "GB", "TB"),
1024 to listOf("B", "KiB", "MiB", "GiB", "TiB"),
)
/**
* Power-of-base rank for each unit symbol: "B" is rank 0 and each prefix
* step adds 1. KB and KiB are both rank 1 — the unit picks the rank, the
* base decides whether a rank means ×1000 or ×1024.
*/
private val exponents: Map<String, Int> = mapOf(
"B" to 0,
"KB" to 1, "MB" to 2, "GB" to 3, "TB" to 4,
"KiB" to 1, "MiB" to 2, "GiB" to 3, "TiB" to 4,
)
/**
* Converts a value between two digital-data units under the given base.
*
* Strategy: reduce to bytes via `value × base^fromExp`, then divide by
* `base^toExp`. Returns [Double.NaN] for non-finite input (Inf/NaN),
* unknown unit symbols, or a base other than 1000/1024 — never throws
* (mirrors the TypeScript contract).
*
* @param value the magnitude to convert, in [fromUnit]
* @param fromUnit source unit symbol, e.g. "MB"
* @param toUnit target unit symbol, e.g. "GiB"
* @param base conversion radix: 1000 (decimal/SI) or 1024 (binary/IEC)
* @return the converted magnitude, or [Double.NaN] on invalid input
*/
fun convertData(value: Double, fromUnit: String, toUnit: String, base: Int): Double {
// Reject Inf/NaN early so they don't propagate through the multiplication.
if (value.isNaN() || value.isInfinite()) return Double.NaN
// Only the two canonical bases are valid; anything else is a caller bug.
if (base != 1000 && base != 1024) return Double.NaN
// Unknown unit symbols miss the map (null) — treat as invalid.
val fromExp = exponents[fromUnit] ?: return Double.NaN
val toExp = exponents[toUnit] ?: return Double.NaN
val radix = base.toDouble()
return (value * radix.pow(fromExp)) / radix.pow(toExp)
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →