{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE CPP #-}

#if MIN_VERSION_base(4, 20, 0)
{-# LANGUAGE RequiredTypeArguments #-}
#endif

{- ORMOLU_DISABLE -}

-- | Provides typeclasses for convert between byte sizes.
--
-- @since 0.1
module Data.Bytes.Class.Conversion
  ( -- * High-level
    Conversion (..),

#if MIN_VERSION_base(4, 20, 0)
    convert,
#endif

    -- * Low-level
    convertSize,
    convertWitness,
  )
where

{- ORMOLU_ENABLE -}

import Data.Bytes.Size
  ( SSize (SB, SE, SG, SK, SM, SP, ST, SY, SZ),
    SingSize (singSize),
    Size (B, E, G, K, M, P, T, Y, Z),
  )
import Numeric.Algebra (MGroup ((.%.)), MSemigroup ((.*.)))
import Numeric.Literal.Integer (FromInteger (afromInteger))

-- $setup
-- >>> import Data.Bytes.Internal (Bytes (..))
-- >>> import Data.Bytes.Size (Size (..), Sized (..))

-- | This class allows one to transform a bytes type to any 'Size'. For types
-- with existentially quantified 'Size' (e.g. 'Data.Bytes.SomeSize',
-- 'Data.Bytes.Network.NetBytes.SomeNetSize'), this will "undo" the existential quantification.
--
-- @since 0.1
class Conversion a where
  -- | @since 0.1
  type Converted (t :: Size) a = r | r -> t

  -- | @convert_ \@_ \@t x@ converts @x@ to size @t@.
  --
  -- ==== __Examples__
  --
  -- >>> let bytes = MkBytes 50_000 :: Bytes 'M Int
  -- >>> let gBytes = convert_ @_ @G bytes
  -- >>> :type gBytes
  -- gBytes :: Bytes G Int
  -- >>> gBytes
  -- MkBytes 50
  --
  -- >>> let bytes = hideSize (MkBytes 0.2 :: Bytes 'T Float)
  -- >>> let mBytes = convert_ @_ @M bytes
  -- >>> :type mBytes
  -- mBytes :: Bytes M Float
  -- >>> mBytes
  -- MkBytes 200000.0
  --
  -- @since 0.1
  convert_ :: (SingSize t) => a -> Converted t a

#if MIN_VERSION_base(4, 20, 0)

-- | Alternative to 'convert_' with -XTypeApplications, using
-- -XRequiredTypeArguments.
--
-- ==== __Examples__
--
-- >>> let bytes = MkBytes 50_000 :: Bytes 'M Int
-- >>> let gBytes = convert G bytes
-- >>> :type gBytes
-- gBytes :: Bytes G Int
-- >>> gBytes
-- MkBytes 50
--
-- @since 0.1
convert ::
  forall t ->
  (SingSize t) =>
  forall a.
  (Conversion a) =>
  a ->
  Converted t a
convert :: forall (t :: Size) ->
forall a. (SingSize t, Conversion a) => a -> Converted t a
convert _ = a -> Converted t a
forall a (t :: Size).
(Conversion a, SingSize t) =>
a -> Converted t a
forall (t :: Size). SingSize t => a -> Converted t a
convert_

#endif

-- | Low level function for converting a numeric literal /from/ the inferred
-- 'SingSize' /to/ the parameter 'Size'. For instance,
--
-- >>> convertWitness @K M 5_000
-- 5
--
-- This is slightly more principled than 'convertSize', but the higher level
-- byte types and functions should still be preferred
-- (e.g. 'Data.Bytes', 'Data.Bytes.Class.Normalize').
--
-- @since 0.1
convertWitness ::
  forall s n.
  ( FromInteger n,
    MGroup n,
    SingSize s
  ) =>
  Size ->
  n ->
  n
convertWitness :: forall (s :: Size) n.
(FromInteger n, MGroup n, SingSize s) =>
Size -> n -> n
convertWitness Size
toUnits n
n = case forall (s :: Size). SingSize s => SSize s
singSize @s of
  SSize s
SB -> Size -> Size -> n -> n
forall n. (FromInteger n, MGroup n) => Size -> Size -> n -> n
convertSize Size
B Size
toUnits n
n
  SSize s
SK -> Size -> Size -> n -> n
forall n. (FromInteger n, MGroup n) => Size -> Size -> n -> n
convertSize Size
K Size
toUnits n
n
  SSize s
SM -> Size -> Size -> n -> n
forall n. (FromInteger n, MGroup n) => Size -> Size -> n -> n
convertSize Size
M Size
toUnits n
n
  SSize s
SG -> Size -> Size -> n -> n
forall n. (FromInteger n, MGroup n) => Size -> Size -> n -> n
convertSize Size
G Size
toUnits n
n
  SSize s
ST -> Size -> Size -> n -> n
forall n. (FromInteger n, MGroup n) => Size -> Size -> n -> n
convertSize Size
T Size
toUnits n
n
  SSize s
SP -> Size -> Size -> n -> n
forall n. (FromInteger n, MGroup n) => Size -> Size -> n -> n
convertSize Size
P Size
toUnits n
n
  SSize s
SE -> Size -> Size -> n -> n
forall n. (FromInteger n, MGroup n) => Size -> Size -> n -> n
convertSize Size
E Size
toUnits n
n
  SSize s
SZ -> Size -> Size -> n -> n
forall n. (FromInteger n, MGroup n) => Size -> Size -> n -> n
convertSize Size
Z Size
toUnits n
n
  SSize s
SY -> Size -> Size -> n -> n
forall n. (FromInteger n, MGroup n) => Size -> Size -> n -> n
convertSize Size
Y Size
toUnits n
n
{-# INLINEABLE convertWitness #-}

-- | Low level function for converting a numeric literal between
-- byte sizes. @convert b1 b2@ converts /from/ @b1@ /to/ @b2@,
-- e.g. @convert G K = \\n -> n * 1_000_000@. The higher level
-- byte types and functions should be preferred
-- (e.g. 'Conversion', "Data.Bytes.Class.Normalize"), but this is
-- here when it is needed.
--
-- @since 0.1
convertSize ::
  forall n.
  ( FromInteger n,
    MGroup n
  ) =>
  Size ->
  Size ->
  n ->
  n
convertSize :: forall n. (FromInteger n, MGroup n) => Size -> Size -> n -> n
convertSize Size
B Size
B n
n = n
n
convertSize Size
B Size
K n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
B Size
M n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
B Size
G n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
B Size
T n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000
convertSize Size
B Size
P n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000
convertSize Size
B Size
E n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000
convertSize Size
B Size
Z n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000_000
convertSize Size
B Size
Y n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000_000_000
convertSize Size
K Size
B n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
K Size
K n
n = n
n
convertSize Size
K Size
M n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
K Size
G n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
K Size
T n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
K Size
P n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000
convertSize Size
K Size
E n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000
convertSize Size
K Size
Z n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000
convertSize Size
K Size
Y n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000_000
convertSize Size
M Size
B n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
M Size
K n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
M Size
M n
n = n
n
convertSize Size
M Size
G n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
M Size
T n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
M Size
P n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
M Size
E n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000
convertSize Size
M Size
Z n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000
convertSize Size
M Size
Y n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000
convertSize Size
G Size
B n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
G Size
K n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
G Size
M n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
G Size
G n
n = n
n
convertSize Size
G Size
T n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
G Size
P n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
G Size
E n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
G Size
Z n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000
convertSize Size
G Size
Y n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000
convertSize Size
T Size
B n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000
convertSize Size
T Size
K n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
T Size
M n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
T Size
G n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
T Size
T n
n = n
n
convertSize Size
T Size
P n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
T Size
E n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
T Size
Z n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
T Size
Y n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000
convertSize Size
P Size
B n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000
convertSize Size
P Size
K n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000
convertSize Size
P Size
M n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
P Size
G n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
P Size
T n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
P Size
P n
n = n
n
convertSize Size
P Size
E n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
P Size
Z n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
P Size
Y n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
E Size
B n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000
convertSize Size
E Size
K n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000
convertSize Size
E Size
M n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000
convertSize Size
E Size
G n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
E Size
T n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
E Size
P n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
E Size
E n
n = n
n
convertSize Size
E Size
Z n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
E Size
Y n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
Z Size
B n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000_000
convertSize Size
Z Size
K n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000
convertSize Size
Z Size
M n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000
convertSize Size
Z Size
G n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000
convertSize Size
Z Size
T n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
Z Size
P n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
Z Size
E n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
Z Size
Z n
n = n
n
convertSize Size
Z Size
Y n
n = n
n n -> n -> n
forall g. MGroup g => g -> g -> g
.%. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
Y Size
B n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000_000_000
convertSize Size
Y Size
K n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000_000
convertSize Size
Y Size
M n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000_000
convertSize Size
Y Size
G n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000_000
convertSize Size
Y Size
T n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000_000
convertSize Size
Y Size
P n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000_000
convertSize Size
Y Size
E n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000_000
convertSize Size
Y Size
Z n
n = n
n n -> n -> n
forall s. MSemigroup s => s -> s -> s
.*. Integer -> n
forall a. (FromInteger a, HasCallStack) => Integer -> a
afromInteger Integer
1_000
convertSize Size
Y Size
Y n
n = n
n
{-# INLINEABLE convertSize #-}