packages feed

clash-shockwaves-1.0.1: src/Clash/Shockwaves/Internal/Waveform.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fconstraint-solver-iterations=10 #-}

{- |
Copyright  :  (C) 2025-2026, QBayLogic B.V.
License    :  BSD2 (see the file LICENSE)
Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>

The 'Waveform' class, functions derived from it, special 'Waveform' variants such as
'WaveformLUT', and 'Waveform' instances for default types.
-}
module Clash.Shockwaves.Internal.Waveform where

import Clash.Prelude

import Clash.Shockwaves.BitList (BitList)
import qualified Clash.Shockwaves.BitList as BL
import Clash.Shockwaves.Internal.TH.Waveform (deriveWaveformTuples)
import Clash.Shockwaves.Internal.Translator
import Clash.Shockwaves.Internal.Types
import Clash.Shockwaves.Internal.Util

import Data.Char (isAlpha)
import qualified Data.List as L
import Data.Maybe (fromMaybe, listToMaybe)
import Data.Proxy
import Data.Typeable
import GHC.Generics

-- for standard type instances
import Data.Int (Int16, Int32, Int64, Int8)
import Data.Word (Word16, Word32, Word64, Word8)

import Clash.Num.Erroring (Erroring)
import Clash.Num.Overflowing (Overflowing)
import Clash.Num.Saturating (Saturating)
import Clash.Num.Wrapping (Wrapping)
import Clash.Num.Zeroing (Zeroing)
import Data.Complex (Complex)
import Data.Functor.Identity (Identity)
import Data.Ord (Down)

{- FOURMOLU_DISABLE -}
#ifndef MAX_TUPLE_SIZE
#ifdef LARGE_TUPLES

#if MIN_VERSION_ghc(9,0,0)
import GHC.Settings.Constants (mAX_TUPLE_SIZE)
#else
import Constants (mAX_TUPLE_SIZE)
#endif
#define MAX_TUPLE_SIZE (fromIntegral mAX_TUPLE_SIZE)

#else
#ifdef HADDOCK_ONLY
#define MAX_TUPLE_SIZE 3
#else
#define MAX_TUPLE_SIZE 12
#endif
#endif
#endif
{- FOURMOLU_ENABLE -}

-- making values

-- | Get a 'Render' from a 'Value' using 'WSDefault' and precedence 11.
rFromVal :: Value -> Render
rFromVal v = Just (v, WSDefault, 11)

-- | Get a t'Translation' from a 'Value' using 'WSDefault' and precedence 11.
tFromVal :: Value -> Translation
tFromVal v = Translation (rFromVal v) []

-- | Create an error value from an optional error message.
errMsg :: Maybe Value -> Value
errMsg = maybe "undefined" (\e -> "{undefined: " <> e <> "}")

-- | First 'WaveStyle' in an infinite list of values.
styHead :: [WaveStyle] -> WaveStyle
styHead (s : _) = s
styHead _ = error "style list must be long enough"

-- making translators

{- | Wrap a t'Translator' in a 'TStyled' translator using some style, unless the
provided style is 'WSDefault'.
-}
wrapStyle :: WaveStyle -> Translator -> Translator
wrapStyle WSDefault t = t
wrapStyle s t = tStyled s t

{- | Wrap a t'Translator' in a 'TStyled' variant translator with the
provided style.
-}
tStyled :: WaveStyle -> Translator -> Translator
tStyled s (Translator w v) = Translator w $ TStyled s (Translator w v)

{- | Wrap a t'Translator' in a 'TDuplicate' variant translator with the
provided subsignal name.
-}
tDup :: SubSignal -> Translator -> Translator
tDup name (Translator w t) = Translator w $ TDuplicate name (Translator w t)

-- | Generate a translator reference for a type.
tRef :: (Waveform a) => Proxy a -> Translator
tRef (_ :: Proxy a) =
  Translator (width @a)
    $ TRef
      (typeName @a)
      TypeRef
        { translateBinRef = translateBin @a
        , translatorRef = translator @a
        , structureRef = structure @a
        }

-- | Create a constant translator that consumes 0 bits and has no subsignals.
tConst :: Render -> Translator
tConst r = Translator 0 $ TConst $ Translation r []

-- | Create a LUT translator for a type, using the translation function of 'WaveformLUT'.
tLut :: forall a. (Waveform a, WaveformLUT a) => Proxy a -> Translator
tLut _ =
  Translator (width @a)
    $ TLut
      (typeName @a)
      TypeRef
        { translateBinRef = translateL @a . BL.binUnpack
        , structureRef = structureL @a
        , translatorRef = translator @a
        }

------------------------------------------ WAVEFORM --------------------------------------

{- |

'Waveform' is the main class for making types displayable in the waveform viewer.
The class is responsible for defining an appropriate translator and subsignal
structure, as well as registering types.

To make a LUT approache possible, the class must also be able to translate values,
and to register individual values.

By default, 'GHC.Generics.Generic' is used to automatically derive this behaviour.
Extra classes are provided to help implement lookup tables or common types,
like numerical translators. Custom implementations are also very possible.
-}
class (Typeable a, BitPack a) => Waveform a where
  {- | Provide the type name.
  Overriding this value is only really useful for derive via strategies.
  -}
  typeName :: TypeName
  typeName = typeNameP (Proxy @a)

  -- | The translator used for the data type. Must match the structure value.
  translator :: Translator
  default translator :: (WaveformG (Rep a ())) => Translator
  translator = translatorG @(Rep a ()) (width @a) (styles' @a)

  {- | List of styles used for constructors.

  Since assigning different constructors different colors is a very common usecase
  of the waveform style,
  this list can be overridden to provides styles for the constructors, in order.
  To not change a style, use 'WSDefault'.
  -}
  styles :: [WaveStyle]
  styles = []

  -- | Runtime bitsize of the type.
  width :: Int
  width = bitsize (Proxy @a)

{- | Function to translate values. This function creates a translation from
the binary representation of the data using translateBin, and the translator.
-}
translate :: forall a. (Waveform a, BitPack a) => a -> Translation
translate = translateBin @a . BL.binPack

{- | Translate binary data.
Normally, this simply translates the value according to the translator.
For LUTs, this involves translating the value back to the original type and
translating it using a specially defined translation function.
-}
translateBin :: forall a. (Waveform a) => BitList -> Translation
translateBin = translateBinT (translator @a)

-- | Register this type and all its subtypes.
addTypes :: forall a. (Waveform a) => TypeMap -> TypeMap
addTypes = addTypesT $ tRef (Proxy @a)

-- | Helper function that fills the 'styles' list with 'WSDefault'.
styles' :: forall a. (Waveform a) => [WaveStyle]
styles' = styles @a <> L.repeat WSDefault

-- | Check if the type requires LUTs for translation.
hasLut :: forall a. (Waveform a) => Bool
hasLut = hasLutT $ translator @a

-- | Return the structure of a type.
structure :: forall a. (Waveform a) => Structure
structure = structureT $ translator @a

-- | Add all (sub) values that use 'TLut' to their respective LUTs.
addValue :: forall a. (Waveform a) => a -> [LUTMap -> LUTMap]
addValue = addValueT (translator @a) . BL.binPack

------------------------------------------- GENERIC -------------------------------------

{- | A class for obtaining the required behaviour of 'Waveform' through "GHC.Generics".
The exact details might change later; use at your own risk.
-}
class WaveformG a where
  {- | Given a bitsize and list of styles for the constructors, provide a translator.

  Defined only for full types and constructors
  -}
  translatorG :: Int -> [WaveStyle] -> Translator

  {- | Return a list of translators for constructors as subsignals.

  Defined for constructors, @:+:@ and types with multiple constructors.
  -}
  constrTranslatorsG :: [WaveStyle] -> [Translator]

  {- | Return a list of translators for fields.

  Defined for fields, @:*:@, constructors, and types with a single constructor.
  Product type subsignals are labeled (numbered) for types and constructors only.
  -}
  fieldTranslatorsG :: [(SubSignal, Translator)]

  {- | Bitsize of a type. Only used to determine the width of constructors
  (and their fields).

  Defined for constructors, @:*:@, and fields.
  -}
  widthG :: Int -- for individual constructors

  {- | For LUTs.
  Create translation subsignals from supplied 'Render' value.
  Duplicate the value if there are multiple constructors, and just translate the fields.
  If getting the constructor fails, create no subsignals.

  Defined for types, @:+:@ and constructors.
  -}
  translateWithG :: Render -> a -> [(SubSignal, Translation)]

  {- | For LUTs.
  Translate all fields of a (the) constructor.

  Defined for constructors, @:*:@, fields and types with 1 constructor.
  -}
  translateFieldsG :: a -> [(SubSignal, Translation)]

-- void type (assuming it has a custom bitpack implementation)
instance WaveformG (D1 m1 V1 k) where
  translatorG _ _ = tConst Nothing
  constrTranslatorsG _ = undefined
  fieldTranslatorsG = undefined

  widthG = undefined

  translateWithG _ _ = []
  translateFieldsG = undefined

-- single constructor type
instance (WaveformG (C1 m2 s k), WaveformG (s k)) => WaveformG (D1 m1 (C1 m2 s) k) where
  translatorG = translatorG @(C1 m2 s k)
  constrTranslatorsG = undefined
  fieldTranslatorsG = fieldTranslatorsG @(C1 m2 s k)

  widthG = undefined

  translateWithG r x = case translateWithG r (unM1 x) of
    [(_, Translation _ subs)] -> subs -- remove duplicated singal from constructor
    _ -> undefined
  translateFieldsG x = translateFieldsG (unM1 x)

-- multiple constructors type
instance (WaveformG ((a :+: b) k)) => WaveformG (D1 m1 (a :+: b) k) where
  translatorG w sty = Translator w . TSum $ constrTranslatorsG @((a :+: b) k) sty
  constrTranslatorsG = constrTranslatorsG @((a :+: b) k)
  fieldTranslatorsG = undefined

  widthG = undefined

  translateWithG r x = fromMaybe [] $ safeWHNF $ translateWithG r (unM1 x)
  translateFieldsG = undefined

-- multiple constructors
instance (WaveformG (a k), WaveformG (b k)) => WaveformG ((a :+: b) k) where
  translatorG = undefined
  constrTranslatorsG sty = a <> b
   where
    a = constrTranslatorsG @(a k) sty
    b = constrTranslatorsG @(b k) (L.drop (L.length a) sty)
  fieldTranslatorsG = undefined

  widthG = undefined

  translateWithG r xy = case safeWHNF xy of
    Just (L1 x) -> translateWithG r x
    Just (R1 y) -> translateWithG r y
    Nothing -> []
  translateFieldsG = undefined

-- struct constructor
instance
  (WaveformG (fields k), KnownSymbol name) =>
  WaveformG (C1 (MetaCons name fix True) fields k)
  where
  translatorG _ sty = t'
   where
    t' = case styHead sty of
      WSDefault ->
        if L.length subs == 1
          then
            tStyled (WSInherit 0) t
          else t
      s -> tStyled s t
    subs = fieldTranslatorsG @(C1 (MetaCons name fix True) fields k)
    t =
      Translator (widthG @(fields k))
        $ TProduct
          { start = sym @name <> "{"
          , sep = ", "
          , stop = "}"
          , preci = -1
          , preco = 11
          , labels = L.map ((<> " = ") . fst) subs
          , subs = subs
          }

  constrTranslatorsG sty =
    [ tDup (sym @name)
        $ translatorG @(C1 (MetaCons name fix True) fields k) undefined sty
    ]
  fieldTranslatorsG = fieldTranslatorsG @(fields k)

  widthG = undefined

  translateWithG r x = [(sym @name, Translation r $ translateFieldsG x)]
  translateFieldsG x = translateFieldsG (unM1 x)

-- applicative product
instance
  (WaveformG (fields k), KnownSymbol name, PrecF fix) =>
  WaveformG (C1 (MetaCons name fix False) fields k)
  where
  translatorG _ sty = t'
   where
    t' = case styHead sty of
      WSDefault ->
        if L.length subs == 1
          then
            tStyled (WSInherit 0) t
          else t
      s -> tStyled s t
    subs = fieldTranslatorsG @(C1 (MetaCons name fix False) fields k)
    t =
      if isOperator
        then
          Translator (widthG @(fields k))
            $ TProduct
              { start = ""
              , sep = " " <> sym @name <> " "
              , stop = ""
              , preci = precF @fix
              , preco = precF @fix
              , labels = []
              , subs = subs
              }
        else
          Translator (widthG @(fields k))
            $ TProduct
              { start = case subs of
                  [] -> sname
                  _ -> sname <> " "
              , sep = " "
              , stop = ""
              , preci = 10
              , preco = case subs of
                  [] -> 11
                  _ -> 10
              , labels = []
              , subs = subs
              }

    sname = safeName (sym @name)
    isOperator = not (isAlpha $ fromMaybe '_' $ listToMaybe $ sym @name) && (L.length subs == 2)

  constrTranslatorsG sty =
    [ tDup (sym @name)
        $ translatorG @(C1 (MetaCons name fix False) fields k) undefined sty
    ]
  fieldTranslatorsG = enumLabel $ fieldTranslatorsG @(fields k)

  widthG = undefined

  translateWithG r x = [(sym @name, Translation r $ translateFieldsG x)]
  translateFieldsG x = enumLabel $ translateFieldsG (unM1 x)

-- no fields
instance WaveformG (U1 k) where
  translatorG = undefined
  constrTranslatorsG = undefined
  fieldTranslatorsG = []

  widthG = 0

  translateWithG _ _ = undefined
  translateFieldsG _ = []

-- | Lazily get left field.
left :: (a :*: b) k -> a k
left (x :*: _y) = x

-- | Lazily get right field.
right :: (a :*: b) k -> b k
right (_x :*: y) = y

-- multiple fields
instance (WaveformG (a k), WaveformG (b k)) => WaveformG ((a :*: b) k) where
  translatorG = undefined
  constrTranslatorsG = undefined
  fieldTranslatorsG = fieldTranslatorsG @(a k) <> fieldTranslatorsG @(b k)

  widthG = widthG @(a k) + widthG @(b k)

  translateWithG _ _ = undefined
  translateFieldsG xy = translateFieldsG (left xy) <> translateFieldsG (right xy)

-- struct field
instance
  (Waveform t, KnownSymbol name) =>
  WaveformG (S1 (MetaSel (Just name) p q r) (Rec0 t) k)
  where
  translatorG = undefined
  constrTranslatorsG = undefined
  fieldTranslatorsG = [(sym @name, tRef (Proxy @t))]

  widthG = width @t

  translateWithG _ _ = undefined
  translateFieldsG x = [(sym @name, translate $ unK1 $ unM1 x)]

-- unnamed field
instance (Waveform t) => WaveformG (S1 (MetaSel Nothing p q r) (Rec0 t) k) where
  translatorG = undefined
  constrTranslatorsG = undefined
  fieldTranslatorsG = [("", tRef (Proxy @t))]

  widthG = width @t

  translateWithG _ _ = undefined
  translateFieldsG x = [("", translate $ unK1 $ unM1 x)]

------------------------------------------------ LUTS ------------------------------------

{- |
Class for easily defining custom translations for a type by using LUTs.
To use this class, a type must derive 'Waveform' via 'WaveformForLUT'.

Bye default, the implementation uses 'GHC.Generics.Generic' for defining subsignals
and operator precedence, and 'Show' for displaying the value.
-}
class (Typeable a, BitPack a) => WaveformLUT a where
  -- | Provides the hierarchy of subsignals.
  structureL :: Structure
  default structureL :: (WaveformG (Rep a ())) => Structure
  structureL = structureT $ translatorG @(Rep a ()) 0 (L.repeat WSDefault)

  {- | Translate a value. The translations must adhere to the structure defined in 'structureL'.
  This function must be robust to @undefined@ values!
  -}
  translateL :: a -> Translation
  default translateL ::
    (Generic a, Show a, WaveformG (Rep a ()), PrecG (Rep a ())) => a -> Translation
  translateL = translateWith renderShow splitL

-- | Make sure a t'Translation' is fully defined. If not, return a t'Translation' with @"undefined"@.
safeTranslation :: Translation -> Translation
safeTranslation = safeValOr (errorT "undefined")

{- | Given a function that renders a value, and a function that (given this 'Render')
prodices the subsignals, create a translation.
If rendering fails, @"undefined"@ is displayed. If creating the subsignals fails, no subsignals are shown.
-}
translateWith ::
  (a -> Render) -> (Render -> a -> [(SubSignal, Translation)]) -> a -> Translation
translateWith d s x = Translation ren subs
 where
  ren = safeValOr (errorR "undefined") $ d x
  subs =
    safeValOr []
      $ s ren x

-- | Display a value with 'Show', the default wave style, and operator precedence determined using 'Generic'.
renderShow :: (Show a, Generic a, PrecG (Rep a ())) => a -> Render
renderShow = renderWith show (const WSDefault) precL

-- | Display a value with the provided functions for creating the text value, style and operator precedence.
renderWith :: (a -> Value) -> (a -> WaveStyle) -> (a -> Prec) -> a -> Render
renderWith v s p x = Just (v x, s x, p x)

{- | Display an atomic value (such as a number) using the provided function to obtain the value.
(normal wavestyle, precedence 11).
-}
translateAtomWith :: (a -> Value) -> a -> Translation
translateAtomWith f = translateWith (renderWith f (const WSDefault) (const 11)) noSplit

-- | Display an atomic value (like a number) with 'Show'. See 'translateAtomWith'.
translateAtomShow :: (Show a) => a -> Translation
translateAtomShow = translateAtomWith show

{- | Render an atomic value representing a signed number.
If the render value is found to start with @-@, the precedence is set to 0.
-}
translateAtomSigWith :: (Show a) => (a -> Value) -> a -> Translation
translateAtomSigWith f = translateWith go noSplit
 where
  go x = Just (v, WSDefault, p)
   where
    v = f x
    p = case v of
      '-' : _ -> 0
      _ -> 11

{- | Render an atomic value representing a signed number using 'show'.
See 'translateAtomSigWith'.
-}
translateAtomSigShow :: (Show a) => a -> Translation
translateAtomSigShow = translateAtomSigWith show

{- | Create subsignals for the constructors and fields.
Constructor translations are a copy of the toplevel render value provided.
-}
splitL :: (Generic a, WaveformG (Rep a ())) => Render -> a -> [(SubSignal, Translation)]
splitL r x = translateWithG r (from @_ @() x)

-- | Create no subsignals for this type.
noSplit :: Render -> a -> [(SubSignal, Translation)]
noSplit _r _x = []

-- | Get the operator precedence of a value.
precL :: (PrecG (Rep a ()), Generic a) => a -> Prec
precL x = precG (from @_ @() x)

{- | Type for deriving 'Waveform' for types implementing 'WaveformLUT'.

@
type T = ... deriving (...)
deriving via WaveformForLUT T instance Waveform T

isntance WaveformLUT T where
  ...
@
-}
newtype WaveformForLUT a = WfLUT a deriving (Generic, BitPack, Typeable)

instance
  (Waveform a, WaveformLUT a, BitPack a, Typeable a) =>
  Waveform (WaveformForLUT a)
  where
  typeName = typeNameP (Proxy @a)

  translator = tLut (Proxy @a)

----------------------------------------------- PREC ----------------------------------

-- Stuff for figuring out the operator precedence of a type.

{- | Helper class for determining the precedence and number of fields of a
value's constructor.
-}
class (Generic a) => PrecG a where
  -- | Operator precedence of a value.
  precG :: a -> Prec

  {- | Return the number of fields of a constructor.
  This is needed to determine whether a constructor is atomic or not.
  -}
  nFields :: Integer
  nFields = undefined

-- get constructor(s)
instance (PrecG (c k)) => PrecG (D1 m1 c k) where
  precG M1{unM1 = x} = precG x

-- no constructors (void tpye)
instance PrecG (V1 k) where
  precG _ = 11

-- multiple constructors
instance (PrecG (a k), PrecG (b k)) => PrecG ((a :+: b) k) where
  precG (L1 x) = precG x
  precG (R1 y) = precG y

-- struct
instance
  (PrecG (fields k), PrecF fix) =>
  PrecG (C1 (MetaCons name fix True) fields k)
  where
  precG _ = 11

-- applicative
instance
  (PrecG (fields k), PrecF fix) =>
  PrecG (C1 (MetaCons name fix False) fields k)
  where
  precG _ = if nFields @(fields k) == 0 then 11 else precF @fix

-- count fields
instance PrecG (U1 k) where
  precG = undefined
  nFields = 0

instance (PrecG (a k), PrecG (b k)) => PrecG ((a :*: b) k) where
  precG = undefined
  nFields = nFields @(a k) + nFields @(b k)

instance PrecG (S1 (MetaSel n p q r) t k) where
  precG = undefined
  nFields = 1

-- | Class for obtaining the runtime precedence of a typelevel fixity value.
class PrecF (f :: FixityI) where
  -- | Return the precedence of a fixity value as an 'Integer'.
  precF :: Prec

instance PrecF PrefixI where
  precF = 10
instance (KnownNat p) => PrecF (InfixI a p) where
  precF = natVal (Proxy @p)

---------------------------------------- OTHER VARIANTS ----------------------------------

-- CONST

{- | Helper class for defining a constant translation value. To use this,
derive Waveform via WaveformForConst.
-}
class (BitPack a, Typeable a) => WaveformConst a where
  -- | The constant translation value. Overwrite this if the translation has subsignals.
  constTrans :: Translation
  constTrans = Translation (constRen @a) []

  -- | Constant render value. Overwrite this if the constant value has no subsignals.
  constRen :: Render
  constRen = undefined

  {-# MINIMAL constTrans | constRen #-}

-- | Helper class for deriving 'Waveform' for types implementing 'WaveformConst'.
newtype WaveformForConst a = WfConst a deriving (Generic, BitPack, Typeable)

instance
  (WaveformConst a, BitPack a, Typeable a) =>
  Waveform (WaveformForConst a)
  where
  typeName = typeNameP (Proxy @a)
  translator = Translator (bitsize $ Proxy @a) $ TConst $ constTrans @a

-- NUMBERS

{- | Helper class for deriving 'Waveform' for numerical types.
Options are provided at the type level (signed, format).

Example:
@
deriving via WaveformForNumber NFSig ('Just '(3,"_")) instance Waveform (Signed 3)
@
-}
newtype WaveformForNumber (f :: NumberFormat) (s :: Maybe NSPair) a
  = WfNum a
  deriving (Generic, BitPack, Typeable)

-- | Pair of a 'Nat' and 'Symbol', used for type-level spacer values.
type NSPair = (Nat, Symbol)

instance
  ( BitPack a
  , Typeable a
  , Typeable f
  , Typeable s
  , KnownNFormat f
  , KnownNSpacer s
  ) =>
  Waveform (WaveformForNumber (f :: NumberFormat) (s :: Maybe NSPair) a)
  where
  typeName = typeNameP (Proxy @a)
  translator =
    Translator (width @(WaveformForNumber f s a))
      $ TNumber
        { format = formatVal (Proxy @f)
        , spacer = spacerVal (Proxy @s)
        , prefix = case formatVal (Proxy @f) of
            NFBin -> "0b"
            NFOct -> "0o"
            NFHex -> "0X"
            _ -> ""
        , warn = False
        }

-- | Default spacer for decimal values (@_@ every 3 digits)
type DecSpacer = 'Just '(3, "_")

-- | Default spacer for hexadecimal values (@_@ every 2 digits)
type HexSpacer = 'Just '(2, "_")

-- | Default spacer for octal values (@_@ every 4 digits)
type OctSpacer = 'Just '(4, "_")

-- | Default spacer for binary values (@_@ every 8 digits)
type BinSpacer = 'Just '(8, "_")

-- | Add @_@ every /n/ digits.
type SpacerEvery n = 'Just '(n, "_")

-- | Do not add spacers.
type NoSpacer = 'Nothing :: (Maybe NSPair)

-- | Class for turning a type level 'NumberFormat' into a runtime value.
class KnownNFormat (f :: NumberFormat) where
  formatVal :: forall proxy. proxy f -> NumberFormat

instance KnownNFormat NFSig where
  formatVal _ = NFSig
instance KnownNFormat NFUns where
  formatVal _ = NFUns
instance KnownNFormat NFHex where
  formatVal _ = NFHex
instance KnownNFormat NFOct where
  formatVal _ = NFOct
instance KnownNFormat NFBin where
  formatVal _ = NFBin

-- | Type to get the runtime value of a type-level number spacer.
class KnownNSpacer (f :: Maybe NSPair) where
  spacerVal :: proxy f -> Maybe (Integer, String)

instance KnownNSpacer 'Nothing where
  spacerVal _ = Nothing
instance (KnownNat n, KnownSymbol s) => KnownNSpacer ('Just '(n, s)) where
  spacerVal _ = Just (natVal (Proxy @n), sym @s)

--------------------------------------- IMPLEMENTATIONS ----------------------------------

instance WaveformConst () where
  constRen = rFromVal "()"
deriving via WaveformForConst () instance Waveform ()

-- | Configure styles through style variables @bool_false@ and @bool_true@.
instance Waveform Bool where
  translator =
    Translator 1
      $ TSum
        [ tConst $ Just ("False", "$bool_false", 11)
        , tConst $ Just ("True", "$bool_true", 11)
        ]

-- | Configure styles through style variables @maybe_nothing@ and @maybe_just@.
instance (Waveform a) => Waveform (Maybe a) where
  translator =
    Translator (width @(Maybe a))
      $ TSum
        [ Translator 0 $ TConst $ Translation (Just ("Nothing", "$maybe_nothing", 11)) []
        , tStyled (WSVar "maybe_just" (WSInherit 0))
            $ Translator (width @a)
            $ TProduct
              { start = "Just "
              , sep = ""
              , stop = ""
              , labels = []
              , preci = 10
              , preco = 10
              , subs = [("Just.0", tRef (Proxy @a))]
              }
        ]

-- | Configure styles through style variables @either_left@ and @either_right@.
instance (Waveform a, Waveform b) => Waveform (Either a b) where
  styles = ["$either_left", "$either_right"]

instance (BitPack Char) => WaveformLUT Char where
  structureL = Structure []
  translateL = translateAtomShow
deriving via WaveformForLUT Char instance (BitPack Char) => Waveform Char

instance WaveformLUT Bit where
  structureL = Structure []
  translateL = translateAtomShow
deriving via WaveformForLUT Bit instance Waveform Bit

instance WaveformLUT Double where
  structureL = Structure []
  translateL = translateAtomSigShow
deriving via WaveformForLUT Double instance Waveform Double

instance WaveformLUT Float where
  structureL = Structure []
  translateL = translateAtomSigShow
deriving via WaveformForLUT Float instance Waveform Float

deriving via WaveformForNumber NFSig DecSpacer Int instance Waveform Int
deriving via WaveformForNumber NFSig DecSpacer Int8 instance Waveform Int8
deriving via WaveformForNumber NFSig DecSpacer Int16 instance Waveform Int16
deriving via WaveformForNumber NFSig DecSpacer Int32 instance Waveform Int32
deriving via WaveformForNumber NFSig DecSpacer Int64 instance Waveform Int64

instance Waveform Ordering

deriving via WaveformForNumber NFUns DecSpacer Word instance Waveform Word
deriving via WaveformForNumber NFUns DecSpacer Word8 instance Waveform Word8
deriving via WaveformForNumber NFUns DecSpacer Word16 instance Waveform Word16
deriving via WaveformForNumber NFUns DecSpacer Word32 instance Waveform Word32
deriving via WaveformForNumber NFUns DecSpacer Word64 instance Waveform Word64

deriving via
  WaveformForNumber NFSig DecSpacer (Signed n)
  instance
    (KnownNat n) => Waveform (Signed n)
deriving via
  WaveformForNumber NFUns DecSpacer (Unsigned n)
  instance
    (KnownNat n) => Waveform (Unsigned n)
deriving via
  WaveformForNumber NFUns DecSpacer (Index n)
  instance
    (1 <= n, KnownNat n) => Waveform (Index n)

instance (Waveform a) => Waveform (Complex a)

instance (Waveform a) => Waveform (Down a)

instance (Waveform a) => Waveform (Identity a)

-- number wrappers
instance (Waveform a) => Waveform (Zeroing a) where
  translator = tDup "zeroing" $ tRef (Proxy @a)

instance (Waveform a) => Waveform (Wrapping a) where
  translator = tDup "wrapping" $ tRef (Proxy @a)

instance (Waveform a) => Waveform (Saturating a) where
  translator = tDup "saturating" $ tRef (Proxy @a)

instance (Waveform a) => Waveform (Overflowing a) where
  translator = tDup "overflowing" $ tRef (Proxy @a)

instance (Waveform a) => Waveform (Erroring a) where
  translator = tDup "erroring" $ tRef (Proxy @a)

-- vectors
instance (KnownNat n, Waveform a) => Waveform (Vec n a) where
  translator =
    Translator (width @(Vec n a))
      $ if natVal (Proxy @n) /= 0
        then
          TArray
            { start = ""
            , sep = " :> "
            , stop = " :> Nil"
            , preci = 5
            , preco = 5
            , len = fromIntegral $ natVal (Proxy @n)
            , sub = tRef (Proxy @a)
            }
        else
          TConst $ tFromVal "Nil"

deriving via
  WaveformForNumber NFBin BinSpacer (BitVector n)
  instance
    (KnownNat n) => Waveform (BitVector n)

-- fixed point
instance
  (BitPack (Fixed r i f), KnownNat i, KnownNat f, Show (Fixed r i f), Typeable r) =>
  WaveformLUT (Fixed r i f)
  where
  structureL = Structure []
  translateL = translateAtomSigShow
deriving via
  WaveformForLUT (Fixed r i f)
  instance
    (BitPack (Fixed r i f), KnownNat i, KnownNat f, Show (Fixed r i f), Typeable r) =>
    Waveform (Fixed r i f)

-- snat
instance (KnownNat n, BitPack (SNat n)) => WaveformConst (SNat n) where
  constRen = rFromVal $ show $ natVal $ Proxy @n
deriving via
  WaveformForConst (SNat n)
  instance
    (KnownNat n, BitPack (SNat n)) => Waveform (SNat n)

-- RTree implementation

-- | Helper family for implementing 'Waveform' for 'RTree'.
type family RTreeIsLeaf d where
  RTreeIsLeaf 0 = True
  RTreeIsLeaf d = False

instance
  (Waveform a, KnownNat d, WaveformRTree (RTreeIsLeaf d) d a) =>
  Waveform (RTree d a)
  where
  translator = translatorRTree @(RTreeIsLeaf d) @d @a

-- | Helper class for implementing 'Waveform' for 'RTree'.
class WaveformRTree (isLeaf :: Bool) d a where
  translatorRTree :: Translator

instance (Waveform a) => WaveformRTree True 0 a where
  translatorRTree = tRef (Proxy @a)

instance
  (Waveform (RTree d1 a), Waveform a, d ~ d1 + 1, KnownNat d, KnownNat d1) =>
  WaveformRTree False d a
  where
  translatorRTree =
    Translator (bitsize $ Proxy @(RTree d a))
      $ TProduct
        { start = "<"
        , sep = ","
        , stop = ">"
        , labels = []
        , preci = -1
        , preco = 11
        , subs = [("left", tsub), ("right", tsub)]
        }
   where
    tsub = tRef (Proxy @(RTree d1 a))

{- | A translator for displaying values with zero or more fields like tuples.
This function will error if called for a type that has more than one constructor!
-}
tupleTranslator :: forall t. (BitPack t, WaveformG (Rep t ())) => Translator
tupleTranslator =
  Translator (bitsize (Proxy @t))
    $ TProduct
      { start = "("
      , sep = ","
      , stop = ")"
      , labels = []
      , preci = -1
      , preco = 11
      , subs = fieldTranslatorsG @(Rep t ())
      }

{- | __NB__: The documentation only shows instances up to /3/-tuples. By
default, instances up to and including /12/-tuples will exist. If the flag
@large-tuples@ is set instances up to the GHC imposed limit will exist. The
GHC imposed limit is either 62 or 64 depending on the GHC version.
-}
deriveWaveformTuples 2 MAX_TUPLE_SIZE