    {-# LANGUAGE AllowAmbiguousTypes #-}
    {-# LANGUAGE CPP #-}
    {-# LANGUAGE NamedFieldPuns #-}
    {-# LANGUAGE RankNTypes #-}
    {-# LANGUAGE TypeFamilies #-}

    module Clash.Signal.Internal.Ambiguous
      ( knownVDomain
      , clockPeriod
      , activeEdge
      , resetKind
      , initBehavior
      , resetPolarity
      ) where

    import           Clash.Signal.Internal
    import           Clash.Promoted.Nat         (SNat)

    -- | Get the clock period from a KnownDomain context
    clockPeriod
      :: forall dom period
       . (KnownDomain dom, DomainPeriod dom ~ period)
      => SNat period
    clockPeriod :: forall (dom :: Domain) (period :: Nat).
    (KnownDomain dom, DomainPeriod dom ~ period) =>
    SNat period
    clockPeriod =
      case forall (dom :: Domain).
    KnownDomain dom =>
    SDomainConfiguration dom (KnownConf dom)
    knownDomain @dom of
        SDomainConfiguration{SNat period
    sPeriod :: SNat period
    sPeriod :: forall (dom :: Domain) (period :: Nat) (edge :: ActiveEdge)
           (reset :: ResetKind) (init :: InitBehavior)
           (polarity :: ResetPolarity).
    SDomainConfiguration
      dom ('DomainConfiguration dom period edge reset init polarity)
    -> SNat period
    sPeriod} ->
          SNat period
    SNat period
    sPeriod
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE clockPeriod #-}
    -- @NOINLINE: https://github.com/clash-lang/clash-compiler/issues/662

    -- | Get 'ActiveEdge' from a KnownDomain context. Example usage:
    --
    -- @
    -- f :: forall dom . KnownDomain dom => ....
    -- f a b c =
    --   case activeEdge @dom of
    --     SRising -> foo
    --     SFalling -> bar
    -- @
    activeEdge
      :: forall dom edge
       . (KnownDomain dom, DomainActiveEdge dom ~ edge)
      => SActiveEdge edge
    activeEdge :: forall (dom :: Domain) (edge :: ActiveEdge).
    (KnownDomain dom, DomainActiveEdge dom ~ edge) =>
    SActiveEdge edge
    activeEdge =
      case forall (dom :: Domain).
    KnownDomain dom =>
    SDomainConfiguration dom (KnownConf dom)
    knownDomain @dom of
        SDomainConfiguration{SActiveEdge edge
    sActiveEdge :: SActiveEdge edge
    sActiveEdge :: forall (dom :: Domain) (period :: Nat) (edge :: ActiveEdge)
           (reset :: ResetKind) (init :: InitBehavior)
           (polarity :: ResetPolarity).
    SDomainConfiguration
      dom ('DomainConfiguration dom period edge reset init polarity)
    -> SActiveEdge edge
    sActiveEdge} ->
          SActiveEdge edge
    SActiveEdge edge
    sActiveEdge
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE activeEdge #-}
    -- @NOINLINE: https://github.com/clash-lang/clash-compiler/issues/662

    -- | Get 'ResetKind' from a KnownDomain context. Example usage:
    --
    -- @
    -- f :: forall dom . KnownDomain dom => ....
    -- f a b c =
    --   case resetKind @dom of
    --     SAsynchronous -> foo
    --     SSynchronous -> bar
    -- @
    resetKind
      :: forall dom sync
       . (KnownDomain dom, DomainResetKind dom ~ sync)
      => SResetKind sync
    resetKind :: forall (dom :: Domain) (sync :: ResetKind).
    (KnownDomain dom, DomainResetKind dom ~ sync) =>
    SResetKind sync
    resetKind =
      case forall (dom :: Domain).
    KnownDomain dom =>
    SDomainConfiguration dom (KnownConf dom)
    knownDomain @dom of
        SDomainConfiguration{SResetKind reset
    sResetKind :: SResetKind reset
    sResetKind :: forall (dom :: Domain) (period :: Nat) (edge :: ActiveEdge)
           (reset :: ResetKind) (init :: InitBehavior)
           (polarity :: ResetPolarity).
    SDomainConfiguration
      dom ('DomainConfiguration dom period edge reset init polarity)
    -> SResetKind reset
    sResetKind} ->
          SResetKind sync
    SResetKind reset
    sResetKind
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE resetKind #-}
    -- @NOINLINE: https://github.com/clash-lang/clash-compiler/issues/662

    -- | Get 'InitBehavior' from a KnownDomain context. Example usage:
    --
    -- @
    -- f :: forall dom . KnownDomain dom => ....
    -- f a b c =
    --   case initBehavior @dom of
    --     SDefined -> foo
    --     SUnknown -> bar
    -- @
    initBehavior
      :: forall dom init
       . (KnownDomain dom, DomainInitBehavior dom ~ init)
      => SInitBehavior init
    initBehavior :: forall (dom :: Domain) (init :: InitBehavior).
    (KnownDomain dom, DomainInitBehavior dom ~ init) =>
    SInitBehavior init
    initBehavior =
      case forall (dom :: Domain).
    KnownDomain dom =>
    SDomainConfiguration dom (KnownConf dom)
    knownDomain @dom of
        SDomainConfiguration{SInitBehavior init
    sInitBehavior :: SInitBehavior init
    sInitBehavior :: forall (dom :: Domain) (period :: Nat) (edge :: ActiveEdge)
           (reset :: ResetKind) (init :: InitBehavior)
           (polarity :: ResetPolarity).
    SDomainConfiguration
      dom ('DomainConfiguration dom period edge reset init polarity)
    -> SInitBehavior init
    sInitBehavior} ->
          SInitBehavior init
    SInitBehavior init
    sInitBehavior
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE initBehavior #-}
    -- @NOINLINE: https://github.com/clash-lang/clash-compiler/issues/662

    -- | Get 'ResetPolarity' from a KnownDomain context. Example usage:
    --
    -- @
    -- f :: forall dom . KnownDomain dom => ....
    -- f a b c =
    --   case resetPolarity @dom of
    --     SActiveHigh -> foo
    --     SActiveLow -> bar
    -- @
    resetPolarity
      :: forall dom polarity
       . (KnownDomain dom, DomainResetPolarity dom ~ polarity)
      => SResetPolarity polarity
    resetPolarity :: forall (dom :: Domain) (polarity :: ResetPolarity).
    (KnownDomain dom, DomainResetPolarity dom ~ polarity) =>
    SResetPolarity polarity
    resetPolarity =
      case forall (dom :: Domain).
    KnownDomain dom =>
    SDomainConfiguration dom (KnownConf dom)
    knownDomain @dom of
        SDomainConfiguration{SResetPolarity polarity
    sResetPolarity :: SResetPolarity polarity
    sResetPolarity :: forall (dom :: Domain) (period :: Nat) (edge :: ActiveEdge)
           (reset :: ResetKind) (init :: InitBehavior)
           (polarity :: ResetPolarity).
    SDomainConfiguration
      dom ('DomainConfiguration dom period edge reset init polarity)
    -> SResetPolarity polarity
    sResetPolarity} ->
          SResetPolarity polarity
    SResetPolarity polarity
    sResetPolarity
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE resetPolarity #-}
    -- @NOINLINE: https://github.com/clash-lang/clash-compiler/issues/662

    -- | Like 'knownDomain but yields a 'VDomainConfiguration'. Should only be used
    -- in combination with 'createDomain'.
    knownVDomain
      :: forall dom
       . KnownDomain dom
      => VDomainConfiguration
    knownVDomain :: forall (dom :: Domain). KnownDomain dom => VDomainConfiguration
    knownVDomain =
      SDomainConfiguration dom (KnownConf dom) -> VDomainConfiguration
    forall (dom :: Domain) (conf :: DomainConfiguration).
    SDomainConfiguration dom conf -> VDomainConfiguration
    vDomain (forall (dom :: Domain).
    KnownDomain dom =>
    SDomainConfiguration dom (KnownConf dom)
    knownDomain @dom)