packages feed

tricorder-0.2.2.0: src/Tricorder/Build/ByteSize.hs

module Tricorder.Build.ByteSize
    ( ByteSize (..)
    , Unit (..)
    , asBytes
    , toRTSSize
    , fromText
    )
where

import Text.Megaparsec (Parsec, eof, parseMaybe)
import Text.Megaparsec.Char (space, string')
import Text.Megaparsec.Char.Lexer (decimal)
import Prelude hiding (toText)

import Text.Show qualified as S


data ByteSize = ByteSize {amount :: Integer, unit :: Unit}
    deriving stock (Eq, Generic, Ord)


instance Show ByteSize where
    show ByteSize {amount, unit} = show amount <> show unit


data Unit
    = B
    | KB
    | KiB
    | MB
    | MiB
    | GB
    | GiB
    | TB
    | TiB
    | PB
    | PiB
    deriving stock (Eq, Generic, Ord, Show)


asBytes :: ByteSize -> Integer
asBytes bs = bs.amount * multiplier bs.unit


multiplier :: Unit -> Integer
multiplier = \case
    B -> 1
    KB -> 1000
    KiB -> 1024
    MB -> 1000 `pow` 2
    MiB -> 1024 `pow` 2
    GB -> 1000 `pow` 3
    GiB -> 1024 `pow` 3
    TB -> 1000 `pow` 4
    TiB -> 1024 `pow` 4
    PB -> 1000 `pow` 5
    PiB -> 1024 `pow` 5
  where
    pow :: Integer -> Integer -> Integer
    pow = (^)


toRTSSize :: ByteSize -> Text
toRTSSize bs = show $ bs.amount * multiplier bs.unit


fromText :: Text -> Maybe ByteSize
fromText = parseMaybe byteSizeP


byteSizeP :: Parser ByteSize
byteSizeP = do
    amount <- decimal
    space
    unit <- unitP
    pure $ ByteSize {amount, unit}


unitP :: Parser Unit
unitP =
    asum
        [ string' "kb" *> pure KB
        , string' "kib" *> pure KiB
        , string' "mb" *> pure MB
        , string' "mib" *> pure MiB
        , string' "gb" *> pure GB
        , string' "gib" *> pure GiB
        , string' "tb" *> pure TB
        , string' "tib" *> pure TiB
        , string' "pb" *> pure PB
        , string' "pib" *> pure PiB
        , string' "b" *> pure B
        , eof *> pure B
        ]


type Parser = Parsec Void Text