membrain-0.0.0.0: src/Membrain/Units.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE TypeOperators #-}
#if ( __GLASGOW_HASKELL__ >= 806 )
{-# LANGUAGE NoStarIsType #-}
#endif
{- | This module contains type aliases for memory data units. According to the
official standard, there exist two naming conventions for memory units. Standard
measure prefixes are multipliers of @10@. But there are alternative prefixes
which end with @bi@ and they are represented as powers of @2@. The difference
can be displayed in the following table:
+------------+----------------+----------+
| Name | Multipliers | In bytes |
+============+================+==========+
| 'Kilobyte' | \( 10 ^ 3 \) | 1000 |
+------------+----------------+----------+
| 'Kibibyte' | \( 2 ^ {10} \) | 1024 |
+------------+----------------+----------+
| 'Megabyte' | \( 10 ^ 6 \) | 1000000 |
+------------+----------------+----------+
| 'Mebibyte' | \( 2 ^ {20} \) | 1048576 |
+------------+----------------+----------+
-}
module Membrain.Units
( -- * Simple
Bit
, Nibble
, Byte
-- * Decimal
, Kilobyte
, Megabyte
, Gigabyte
, Terabyte
, Petabyte
, Exabyte
, Zettabyte
, Yottabyte
-- * Binary
, Kibibyte
, Mebibyte
, Gibibyte
, Tebibyte
, Pebibyte
, Exbibyte
, Zebibyte
, Yobibyte
-- * Unit symbols
, UnitSymbol
, KnownUnitSymbol
, unitSymbol
) where
import Data.Proxy (Proxy (..))
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
import GHC.TypeNats (type (*), Nat)
type Bit = 1
type Nibble = 4
type Byte = 8
type Kilobyte = 1000 * Byte
type Megabyte = 1000 * Kilobyte
type Gigabyte = 1000 * Megabyte
type Terabyte = 1000 * Gigabyte
type Petabyte = 1000 * Terabyte
type Exabyte = 1000 * Petabyte
type Zettabyte = 1000 * Exabyte
type Yottabyte = 1000 * Zettabyte
type Kibibyte = 1024 * Byte
type Mebibyte = 1024 * Kibibyte
type Gibibyte = 1024 * Mebibyte
type Tebibyte = 1024 * Gibibyte
type Pebibyte = 1024 * Tebibyte
type Exbibyte = 1024 * Pebibyte
type Zebibyte = 1024 * Exbibyte
type Yobibyte = 1024 * Zebibyte
{- | Type-level function to map memory units multipliers to proper symbols.
>>> :kind! UnitSymbol Bit
UnitSymbol Bit :: Symbol
= "b"
>>> :kind! UnitSymbol Byte
UnitSymbol Byte :: Symbol
= "B"
>>> :kind! UnitSymbol Kilobyte
UnitSymbol Kilobyte :: Symbol
= "kB"
>>> :kind! UnitSymbol Mebibyte
UnitSymbol Mebibyte :: Symbol
= "MiB"
-}
type family UnitSymbol (unit :: Nat) = (res :: Symbol) | res -> unit
type instance UnitSymbol 1 = "b"
type instance UnitSymbol 4 = "n"
type instance UnitSymbol 8 = "B"
type instance UnitSymbol 8000 = "kB"
type instance UnitSymbol 8000000 = "MB"
type instance UnitSymbol 8000000000 = "GB"
type instance UnitSymbol 8000000000000 = "TB"
type instance UnitSymbol 8000000000000000 = "PB"
type instance UnitSymbol 8000000000000000000 = "EB"
type instance UnitSymbol 8000000000000000000000 = "ZB"
type instance UnitSymbol 8000000000000000000000000 = "YB"
type instance UnitSymbol 8192 = "KiB"
type instance UnitSymbol 8388608 = "MiB"
type instance UnitSymbol 8589934592 = "GiB"
type instance UnitSymbol 8796093022208 = "TiB"
type instance UnitSymbol 9007199254740992 = "PiB"
type instance UnitSymbol 9223372036854775808 = "EiB"
type instance UnitSymbol 9444732965739290427392 = "ZiB"
type instance UnitSymbol 9671406556917033397649408 = "YiB"
-- | Constraint alias for 'KnownSymbol' calculated by 'UnitSymbol'.
type KnownUnitSymbol (mem :: Nat) = KnownSymbol (UnitSymbol mem)
{- | Term-level function to get value of the 'UnitSymbol' type family. Can be used
only with @-XTypeApplications@.
>>> unitSymbol @Terabyte
"TB"
>>> unitSymbol @Yobibyte
"YiB"
-}
unitSymbol :: forall (mem :: Nat) . KnownUnitSymbol mem => String
unitSymbol = symbolVal $ Proxy @(UnitSymbol mem)
{-# INLINE unitSymbol #-}