packages feed

bluefin-internal-0.3.5.0: src/Bluefin/Internal/OneWayCoercible.hs

{-# OPTIONS_HADDOCK not-home #-}

module Bluefin.Internal.OneWayCoercible
  ( module Bluefin.Internal.OneWayCoercible,
    Generic,
  )
where

import Data.Coerce (Coercible, coerce)
import Data.Type.Coercion (Coercion (Coercion))
import GHC.Generics
import Unsafe.Coerce (unsafeCoerce)

gOneWayCoercion ::
  forall a b. (GOneWayCoercible (Rep a) (Rep b)) => OneWayCoercion a b
gOneWayCoercion = unsafeOneWayCoercion

gOneWayCoercible ::
  (GOneWayCoercible (Rep (h e)) (Rep (h es))) =>
  -- | ͘
  OneWayCoercibleD (h e) (h es)
gOneWayCoercible = MkOneWayCoercibleD gOneWayCoercion

gOneWayCoercible2 ::
  (GOneWayCoercible (Rep (h e e')) (Rep (h es es'))) =>
  OneWayCoercibleD (h e e') (h es es')
gOneWayCoercible2 = MkOneWayCoercibleD gOneWayCoercion

oneWayCoercible :: (Coercible a b) => OneWayCoercibleD a b
oneWayCoercible = MkOneWayCoercibleD (MkOneWayCoercion Coercion)

unsafeOneWayCoercion :: forall a b. OneWayCoercion a b
unsafeOneWayCoercion = MkOneWayCoercion (unsafeCoerce (Coercion @a @a))

unsafeOneWayCoercible :: forall a b. OneWayCoercibleD a b
unsafeOneWayCoercible = MkOneWayCoercibleD unsafeOneWayCoercion

newtype OneWayCoercion a b = MkOneWayCoercion (Coercion a b)

newtype OneWayCoercibleD a b = MkOneWayCoercibleD (OneWayCoercion a b)

oneWayCoercion :: (OneWayCoercible a b) => OneWayCoercion a b
oneWayCoercion = case oneWayCoercibleImpl of
  MkOneWayCoercibleD oneWay -> oneWay

oneWayCoerce :: forall a b. (OneWayCoercible a b) => a -> b
oneWayCoerce = oneWayCoerceWith (oneWayCoercion @a @b)

oneWayCoerceWith :: OneWayCoercion a b -> a -> b
oneWayCoerceWith (MkOneWayCoercion Coercion) = coerce

unsafeCoercionOfOneWayCoercion :: OneWayCoercion a b -> Coercion a b
unsafeCoercionOfOneWayCoercion (MkOneWayCoercion c) = c

unsafeCoercionOfOneWayCoercible ::
  forall a b. (OneWayCoercible a b) => Coercion a b
unsafeCoercionOfOneWayCoercible = case oneWayCoercion @a @b of
  MkOneWayCoercion c -> c

class OneWayCoercible a b where
  oneWayCoercibleImpl :: OneWayCoercibleD a b

instance {-# INCOHERENT #-} OneWayCoercible s s where
  oneWayCoercibleImpl = oneWayCoercible

instance OneWayCoercible () () where
  oneWayCoercibleImpl = oneWayCoercible

instance
  (OneWayCoercible a1 a2) =>
  OneWayCoercible (Maybe a1) (Maybe a2)
  where
  oneWayCoercibleImpl = case unsafeCoercionOfOneWayCoercible @a1 @a2 of
    Coercion -> oneWayCoercible

instance
  (OneWayCoercible a1 a2, OneWayCoercible b1 b2) =>
  OneWayCoercible (Either a1 b1) (Either a2 b2)
  where
  oneWayCoercibleImpl = case unsafeCoercionOfOneWayCoercible @a1 @a2 of
    Coercion -> case unsafeCoercionOfOneWayCoercible @b1 @b2 of
      Coercion -> oneWayCoercible

-- | Other sizes of tuples follow this pattern. We will add them when
-- someone needs them.
instance
  (OneWayCoercible a1 a2, OneWayCoercible b1 b2) =>
  OneWayCoercible (a1, b1) (a2, b2)
  where
  oneWayCoercibleImpl = case unsafeCoercionOfOneWayCoercible @a1 @a2 of
    Coercion -> case unsafeCoercionOfOneWayCoercible @b1 @b2 of
      Coercion -> oneWayCoercible

trans :: OneWayCoercion a b -> OneWayCoercion b c -> OneWayCoercion a c
trans c1 c2 = case unsafeCoercionOfOneWayCoercion c1 of
  Coercion -> case unsafeCoercionOfOneWayCoercion c2 of
    Coercion -> MkOneWayCoercion Coercion

class GOneWayCoercible a b

instance GOneWayCoercible U1 U1

instance
  (OneWayCoercible c c') =>
  GOneWayCoercible (K1 i c) (K1 i' c')

instance
  (GOneWayCoercible f f') =>
  GOneWayCoercible (M1 i t f) (M1 i' t' f')

instance
  (GOneWayCoercible f f', GOneWayCoercible g g') =>
  GOneWayCoercible (f :*: g) (f' :*: g')

instance
  (OneWayCoercible a a', OneWayCoercible b b') =>
  OneWayCoercible (a' -> b) (a -> b')
  where
  oneWayCoercibleImpl = case oneWayCoercion @a @a' of
    MkOneWayCoercion Coercion -> case oneWayCoercion @b @b' of
      MkOneWayCoercion Coercion ->
        MkOneWayCoercibleD (MkOneWayCoercion Coercion)

instance
  OneWayCoercible (h e) (h es) =>
  OneWayCoercible (Rec1 h e) (Rec1 h es)
  where
  oneWayCoercibleImpl = gOneWayCoercible

instance
  OneWayCoercible (h e) (h es) =>
  OneWayCoercible (M1 i t h e) (M1 i t h es)
  where
  oneWayCoercibleImpl = gOneWayCoercible

instance
  (OneWayCoercible (h1 e) (h1 es), OneWayCoercible (h2 e) (h2 es)) =>
  OneWayCoercible ((h1 :*: h2) e) ((h1 :*: h2) es)
  where oneWayCoercibleImpl = gOneWayCoercible