
   Copyright 2020 Awake Networks 

   Licensed under the Apache License , Version 2.0 ( the " License " ) ; 
   you may not use this file except in compliance with the License . 
   You may obtain a copy of the License at 

       -2.0 

   Unless required by applicable law or agreed to in writing , software 
   distributed under the License is distributed on an " AS IS " BASIS , 
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied . 
   See the License for the specific language governing permissions and 
   limitations under the License . 

  Copyright 2020 Awake Networks

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      -2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-}

# LANGUAGE DataKinds #
# LANGUAGE FunctionalDependencies #
# LANGUAGE MagicHash #
# LANGUAGE PolyKinds #
# LANGUAGE ScopedTypeVariables #
# LANGUAGE TypeOperators #

-- | Augmentations to type classes such as 'Semigroup' and 'Monoid' that may
-- be used to track the type-level width information of builder primitives.
module Proto3.Wire.Reverse.Width
  ( AssocPlusNat(..)
  , CommPlusNat(..)
  , PChoose(..)
  , Max
  , AssocMaxNat(..)
  , CommMaxNat(..)
  ) where

import Data.Type.Bool (If)
import GHC.Exts (Proxy#)
import GHC.TypeLits (type (<=?), type (+))
import Parameterized.Data.Semigroup (PNullary)

-- | Associativity of '+' in type parameters.
class AssocPlusNat n u v w
  where
    assocLPlusNat ::
      Proxy# '(u, v, w) ->
      PNullary n (u + (v + w)) ->
      PNullary n ((u + v) + w)

    assocRPlusNat ::
      Proxy# '(u, v, w) ->
      PNullary n ((u + v) + w) ->
      PNullary n (u + (v + w))

-- | Commutativity of '+' in type parameters.
class CommPlusNat n u v
  where
    commPlusNat ::
      Proxy# '(u, v) ->
      PNullary n (u + v) ->
      PNullary n (v + u)

-- | Chooses between alternatives based on a condition,
-- adjusting a type-level parameter appropriately.
--
-- Note that while this type class makes sense for bounded builder primitives,
-- it should not be instantiated for fixed-width primitives of differing
-- widths (at least, not without padding to equalize the widths) because
-- the choice between alternatives introduces a run-time variation in width.
  Instead please use ordinary ` Data.Bool.bool ` or @if _ then _ else _ @.
class PChoose n f t w | f t -> w
  where
  | Like ` Data.Bool.bool ` , chooses the first argument on ' False '
  and the second on ' True ' , either way promoting the type - level
  ` GHC.TypeLits .   to the larger of the given ` GHC.TypeLits . Nat`s .
    --
    -- Defaults to the natural implementation in terms of 'pif'.
    pbool :: PNullary n f -> PNullary n t -> Bool -> PNullary n w
    pbool f t b = pif b t f
    {-# INLINE CONLIKE pbool #-}

  | Like @if _ then _ else@ , chooses the first argument on ' True '
  and the second on ' False ' , either way promoting the type - level
  ` GHC.TypeLits .   to the larger of the given ` GHC.TypeLits . Nat`s .
    --
    -- Defaults to the natural implementation in terms of 'pbool'.
    pif :: Bool -> PNullary n t -> PNullary n f -> PNullary n w
    pif c t e = pbool e t c
    {-# INLINE CONLIKE pif #-}

# MINIMAL pbool | pif #

  | The larger of two ` GHC.TypeLits . Nat`s .
type Max u v = If (v <=? u) u v

  | Associativity of '  ' in type parameters .
class AssocMaxNat n u v w
  where
    assocLMaxNat ::
      Proxy# '(u, v, w) ->
      PNullary n (Max u (Max v w)) ->
      PNullary n (Max (Max u v) w)

    assocRMaxNat ::
      Proxy# '(u, v, w) ->
      PNullary n (Max (Max u v) w) ->
      PNullary n (Max u (Max v w))

  | Commutativity of '  ' in type parameters .
class CommMaxNat n u v
  where
    commMaxNat ::
      Proxy# '(u, v) ->
      PNullary n (Max u v) ->
      PNullary n (Max v u)

 | Augmentations to type classes such as 'Semigroup' and 'Monoid' that may
 be used to track the type-level width information of builder primitives.
 | Associativity of '+' in type parameters.
 | Commutativity of '+' in type parameters.
 | Chooses between alternatives based on a condition,
 adjusting a type-level parameter appropriately.

 Note that while this type class makes sense for bounded builder primitives,
 it should not be instantiated for fixed-width primitives of differing
 widths (at least, not without padding to equalize the widths) because
 the choice between alternatives introduces a run-time variation in width.

 Defaults to the natural implementation in terms of 'pif'.
# INLINE CONLIKE pbool #

 Defaults to the natural implementation in terms of 'pbool'.
# INLINE CONLIKE pif #

   Copyright 2020 Awake Networks 

   Licensed under the Apache License , Version 2.0 ( the " License " ) ; 
   you may not use this file except in compliance with the License . 
   You may obtain a copy of the License at 

       -2.0 

   Unless required by applicable law or agreed to in writing , software 
   distributed under the License is distributed on an " AS IS " BASIS , 
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied . 
   See the License for the specific language governing permissions and 
   limitations under the License . 

  Copyright 2020 Awake Networks

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      -2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-}

# LANGUAGE DataKinds #
# LANGUAGE FunctionalDependencies #
# LANGUAGE MagicHash #
# LANGUAGE PolyKinds #
# LANGUAGE ScopedTypeVariables #
# LANGUAGE TypeOperators #

module Proto3.Wire.Reverse.Width
  ( AssocPlusNat(..)
  , CommPlusNat(..)
  , PChoose(..)
  , Max
  , AssocMaxNat(..)
  , CommMaxNat(..)
  ) where

import Data.Type.Bool (If)
import GHC.Exts (Proxy#)
import GHC.TypeLits (type (<=?), type (+))
import Parameterized.Data.Semigroup (PNullary)

class AssocPlusNat n u v w
  where
    assocLPlusNat ::
      Proxy# '(u, v, w) ->
      PNullary n (u + (v + w)) ->
      PNullary n ((u + v) + w)

    assocRPlusNat ::
      Proxy# '(u, v, w) ->
      PNullary n ((u + v) + w) ->
      PNullary n (u + (v + w))

class CommPlusNat n u v
  where
    commPlusNat ::
      Proxy# '(u, v) ->
      PNullary n (u + v) ->
      PNullary n (v + u)

  Instead please use ordinary ` Data.Bool.bool ` or @if _ then _ else _ @.
class PChoose n f t w | f t -> w
  where
  | Like ` Data.Bool.bool ` , chooses the first argument on ' False '
  and the second on ' True ' , either way promoting the type - level
  ` GHC.TypeLits .   to the larger of the given ` GHC.TypeLits . Nat`s .
    pbool :: PNullary n f -> PNullary n t -> Bool -> PNullary n w
    pbool f t b = pif b t f

  | Like @if _ then _ else@ , chooses the first argument on ' True '
  and the second on ' False ' , either way promoting the type - level
  ` GHC.TypeLits .   to the larger of the given ` GHC.TypeLits . Nat`s .
    pif :: Bool -> PNullary n t -> PNullary n f -> PNullary n w
    pif c t e = pbool e t c

# MINIMAL pbool | pif #

  | The larger of two ` GHC.TypeLits . Nat`s .
type Max u v = If (v <=? u) u v

  | Associativity of '  ' in type parameters .
class AssocMaxNat n u v w
  where
    assocLMaxNat ::
      Proxy# '(u, v, w) ->
      PNullary n (Max u (Max v w)) ->
      PNullary n (Max (Max u v) w)

    assocRMaxNat ::
      Proxy# '(u, v, w) ->
      PNullary n (Max (Max u v) w) ->
      PNullary n (Max u (Max v w))

  | Commutativity of '  ' in type parameters .
class CommMaxNat n u v
  where
    commMaxNat ::
      Proxy# '(u, v) ->
      PNullary n (Max u v) ->
      PNullary n (Max v u)
