-- | Here is a quick example: -- -- > ByteValue (1024 * 1024 * 3) Bytes -- > -- the above will evaluate to: ByteValue 3145728.0 Bytes -- -- > getShortHand . getAppropriateUnits $ ByteValue (1024 * 1024 * 3) Bytes -- > -- the above will evaluate to: "3.00 MB" module Data.ByteUnits where import Safe (lastMay) import Numeric data ByteUnit = Bytes | KiloBytes | MegaBytes | GigaBytes | TeraBytes | PetaBytes | ExaBytes deriving (Show, Eq) data ByteValue = ByteValue Float ByteUnit deriving (Show, Eq) -- | Also allows comparing sizes, but because it uses float - it might not be 100% accurate -- -- >>> ByteValue 1024 MegaBytes == ByteValue 1 GigaBytes -- False -- -- >>> ByteValue 1023 MegaBytes < ByteValue 1 GigaBytes -- True instance Ord ByteValue where compare a b = compare (getBytes a) (getBytes b) -- | Gets the value of bytes from a ByteValue type -- getBytes :: ByteValue -> Float getBytes (ByteValue v bu) = case bu of Bytes -> v KiloBytes -> v * (1024 ** 1) MegaBytes -> v * (1024 ** 2) GigaBytes -> v * (1024 ** 3) TeraBytes -> v * (1024 ** 4) PetaBytes -> v * (1024 ** 4) ExaBytes -> v * (1024 ** 5) -- | Converts the ByteValue to an ByteValue with the specified ByteUnit -- -- >>> convertByteUnit (ByteValue 500 GigaBytes) MegaBytes -- ByteValue 512000.0 MegaBytes convertByteUnit :: ByteValue -> ByteUnit -> ByteValue convertByteUnit bv bu = case bu of Bytes -> ByteValue bytes Bytes KiloBytes -> ByteValue (bytes / (1024 ** 1)) KiloBytes MegaBytes -> ByteValue (bytes / (1024 ** 2)) MegaBytes GigaBytes -> ByteValue (bytes / (1024 ** 3)) GigaBytes TeraBytes -> ByteValue (bytes / (1024 ** 4)) TeraBytes PetaBytes -> ByteValue (bytes / (1024 ** 4)) PetaBytes ExaBytes -> ByteValue (bytes / (1024 ** 5)) ExaBytes where bytes = getBytes bv -- | Converts to the largest unit size provided the float value is > 1 -- -- >>> getAppropriateUnits (ByteValue 1024 Bytes) -- ByteValue 1 KiloBytes -- -- >>> getAppropriateUnits (ByteValue (3.5 * 1024* 1024) Bytes) -- ByteValue 3.5 MegaBytes getAppropriateUnits :: ByteValue -> ByteValue getAppropriateUnits bv = do let bUnits = [Bytes, KiloBytes, MegaBytes, GigaBytes, TeraBytes, PetaBytes, ExaBytes] let bytes = getBytes bv let units = fmap (\bu -> convertByteUnit (ByteValue bytes Bytes) bu) bUnits let appropriateUnits = filter (\(ByteValue v' _) -> (v' >= 1.0)) units case (lastMay appropriateUnits) of Just (bv') -> bv' Nothing -> bv -- | Converts to a short string representation -- -- >>> getShortHand $ ByteValue 100 MegaBytes -- "100.00 MB" getShortHand :: ByteValue -> String getShortHand (ByteValue v bu) = (showFFloat (Just 2) v) (" " ++buShort) where buShort = case bu of Bytes -> "B" KiloBytes -> "KB" MegaBytes -> "MB" GigaBytes -> "GB" TeraBytes -> "TB" PetaBytes -> "PB" ExaBytes -> "EB"