packages feed

exon-1.7.3.0: lib/Exon/Class/Newtype.hs

-- | Description: Internal
module Exon.Class.Newtype where

import Exon.Data.Segment (Segment)
import Exon.Generic (IsNewtype, OverNt)
import Unsafe.Coerce (unsafeCoerce)

-- | Internal auxiliary class that applies a function to the value inside of a nested chain of 'Generic' newtypes.
class OverNewtype (current :: Type) (wrapped :: Maybe Type) (inner :: Type) | current -> inner where
  overNewtype :: (NonEmpty (Segment inner) -> inner) -> NonEmpty (Segment current) -> current

instance (
    OverNt current wrapped,
    IsNewtype wrapped next,
    OverNewtype wrapped next inner
  ) => OverNewtype current ('Just wrapped) inner where
    overNewtype f segments =
      unsafeCoerce (overNewtype @wrapped @next @inner f (unsafeCoerce segments))
    {-# inline overNewtype #-}

instance OverNewtype current 'Nothing current where
  overNewtype = id
  {-# inline overNewtype #-}

-- | Internal auxiliary class that applies a function to the value inside of a nested chain of 'Generic' newtypes.
--
-- The method only passes its arguments to 'overNewtypes', but the class hides the intermediate parameter.
class OverNewtypes (result :: Type) (inner :: Type) | result -> inner where
  overNewtypes :: (NonEmpty (Segment inner) -> inner) -> NonEmpty (Segment result) -> result

instance (
    IsNewtype result wrapped,
    OverNewtype result wrapped inner
  ) => OverNewtypes result inner where
    overNewtypes = overNewtype @result @wrapped
    {-# inline overNewtypes #-}