packages feed

calamity-0.1.30.2: Calamity/Internal/ShapeCoerce.hs

{- | Something to coerce between two records with the same field names and
 compatible field types
-}
module Calamity.Internal.ShapeCoerce (
    shapeCoerce,
    ShapeCoerce,
    GShapeCoerce (..),
) where

import Data.Coerce (Coercible, coerce)
import GHC.Generics

type ShapeCoerce a b = (Generic a, Generic b, GShapeCoerce (Rep a) (Rep b))

shapeCoerce :: (Generic a, Generic b, GShapeCoerce (Rep a) (Rep b)) => a -> b
shapeCoerce = to . gshapeCoerce . from

class GShapeCoerce f g where
    gshapeCoerce :: f a -> g b

instance (GShapeCoerce fa ga, GShapeCoerce fb gb) => GShapeCoerce (fa :*: fb) (ga :*: gb) where
    gshapeCoerce (la :*: lb) = gshapeCoerce la :*: gshapeCoerce lb

instance GShapeCoerce f g => GShapeCoerce (M1 D da f) (M1 D db g) where
    gshapeCoerce (M1 a) = M1 (gshapeCoerce a)

instance GShapeCoerce f g => GShapeCoerce (M1 C da f) (M1 C db g) where
    gshapeCoerce (M1 a) = M1 (gshapeCoerce a)

instance GShapeCoerce f g => GShapeCoerce (S1 ( 'MetaSel ( 'Just name) fsu fss fl) f) (S1 ( 'MetaSel ( 'Just name') gsu gss gl) g) where
    gshapeCoerce (M1 a) = M1 (gshapeCoerce a)

instance GShapeCoerce f g => GShapeCoerce (S1 ( 'MetaSel 'Nothing fsu fss fl) f) (S1 ( 'MetaSel 'Nothing gsu gss gl) g) where
    gshapeCoerce (M1 a) = M1 (gshapeCoerce a)

instance Coercible a b => GShapeCoerce (Rec0 a) (Rec0 b) where
    gshapeCoerce (K1 a) = K1 $ coerce a