    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    {-|
    Module      : HsLua.Class.Pushable
    Copyright   : © 2007–2012 Gracjan Polak;
                  © 2012–2016 Ömer Sinan Ağacan;
                  © 2017-2024 Albert Krewinkel
    License     : MIT
    Maintainer  : Albert Krewinkel <tarleb@hslua.org>
    Stability   : beta
    Portability : FlexibleInstances, ScopedTypeVariables

    Sending haskell objects to the lua stack.
    -}
    module HsLua.Class.Pushable
      ( Pushable (..)
      , pushList
      ) where

    import Data.ByteString (ByteString)
    import Data.Map (Map)
    import Data.Text (Text)
    import Data.Set (Set)
    import HsLua.Core as Lua
    import HsLua.Marshalling hiding (pushList)
    import Foreign.Ptr (Ptr)

    import qualified Data.ByteString.Lazy as BL
    import qualified HsLua.Marshalling as Push

    -- | A value that can be pushed to the Lua stack.
    class Pushable a where
      -- | Pushes a value onto Lua stack, casting it into meaningfully nearest Lua
      -- type.
      push :: LuaError e => a -> LuaE e ()

    instance Pushable () where
      push :: forall e. LuaError e => () -> LuaE e ()
    push = LuaE e () -> () -> LuaE e ()
    forall a b. a -> b -> a
    const LuaE e ()
    forall e. LuaE e ()
    pushnil

    instance Pushable Lua.Integer where
      push :: forall e. LuaError e => Integer -> LuaE e ()
    push = Integer -> LuaE e ()
    forall e. Integer -> LuaE e ()
    pushinteger

    instance Pushable Lua.Number where
      push :: forall e. LuaError e => Number -> LuaE e ()
    push = Number -> LuaE e ()
    forall e. Number -> LuaE e ()
    pushnumber

    instance Pushable ByteString where
      push :: forall e. LuaError e => ByteString -> LuaE e ()
    push = ByteString -> LuaE e ()
    forall e. ByteString -> LuaE e ()
    pushstring

    instance Pushable Bool where
      push :: forall e. LuaError e => Bool -> LuaE e ()
    push = Bool -> LuaE e ()
    forall e. Bool -> LuaE e ()
    pushboolean

    instance Pushable CFunction where
      push :: forall e. LuaError e => CFunction -> LuaE e ()
    push = CFunction -> LuaE e ()
    forall e. CFunction -> LuaE e ()
    pushcfunction

    instance Pushable (Ptr a) where
      push :: forall e. LuaError e => Ptr a -> LuaE e ()
    push = Ptr a -> LuaE e ()
    forall a e. Ptr a -> LuaE e ()
    pushlightuserdata

    instance Pushable Text where
      push :: forall e. LuaError e => Text -> LuaE e ()
    push = Pusher e Text
    forall e. Pusher e Text
    pushText

    instance Pushable BL.ByteString where
      push :: forall e. LuaError e => ByteString -> LuaE e ()
    push = Pusher e ByteString
    forall e. Pusher e ByteString
    pushLazyByteString

    instance Pushable Prelude.Integer where
      push :: forall e. LuaError e => Integer -> LuaE e ()
    push = Integer -> LuaE e ()
    forall a e. (Integral a, Show a) => a -> LuaE e ()
    pushIntegral

    instance Pushable Int where
      push :: forall e. LuaError e => Int -> LuaE e ()
    push = Int -> LuaE e ()
    forall a e. (Integral a, Show a) => a -> LuaE e ()
    pushIntegral

    instance Pushable Float where
      push :: forall e. LuaError e => Float -> LuaE e ()
    push = Float -> LuaE e ()
    forall a e. RealFloat a => a -> LuaE e ()
    pushRealFloat

    instance Pushable Double where
      push :: forall e. LuaError e => Double -> LuaE e ()
    push = Double -> LuaE e ()
    forall a e. RealFloat a => a -> LuaE e ()
    pushRealFloat

    instance {-# OVERLAPS #-} Pushable [Char] where
      push :: forall e. LuaError e => [Char] -> LuaE e ()
    push = [Char] -> LuaE e ()
    forall e. [Char] -> LuaE e ()
    pushString

    instance Pushable a => Pushable [a] where
      push :: forall e. LuaError e => [a] -> LuaE e ()
    push = Pusher e a -> [a] -> LuaE e ()
    forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
    Push.pushList Pusher e a
    forall e. LuaError e => a -> LuaE e ()
    forall a e. (Pushable a, LuaError e) => a -> LuaE e ()
    push

    instance (Pushable a, Pushable b) => Pushable (Map a b) where
      push :: forall e. LuaError e => Map a b -> LuaE e ()
    push = Pusher e a -> Pusher e b -> Pusher e (Map a b)
    forall e a b.
    LuaError e =>
    Pusher e a -> Pusher e b -> Pusher e (Map a b)
    pushMap Pusher e a
    forall e. LuaError e => a -> LuaE e ()
    forall a e. (Pushable a, LuaError e) => a -> LuaE e ()
    push Pusher e b
    forall e. LuaError e => b -> LuaE e ()
    forall a e. (Pushable a, LuaError e) => a -> LuaE e ()
    push

    instance Pushable a => Pushable (Set a) where
      push :: forall e. LuaError e => Set a -> LuaE e ()
    push = Pusher e a -> Pusher e (Set a)
    forall e a. LuaError e => Pusher e a -> Pusher e (Set a)
    pushSet Pusher e a
    forall e. LuaError e => a -> LuaE e ()
    forall a e. (Pushable a, LuaError e) => a -> LuaE e ()
    push

    -- | Push list as numerically indexed table.
    pushList :: (LuaError e, Pushable a) => [a] -> LuaE e ()
    pushList :: forall e a. (LuaError e, Pushable a) => [a] -> LuaE e ()
    pushList = Pusher e a -> [a] -> LuaE e ()
    forall e a. LuaError e => Pusher e a -> [a] -> LuaE e ()
    Push.pushList Pusher e a
    forall e. LuaError e => a -> LuaE e ()
    forall a e. (Pushable a, LuaError e) => a -> LuaE e ()
    push

    --
    -- Tuples
    --
    instance {-# OVERLAPPABLE #-}
      (Pushable a, Pushable b) =>
      Pushable (a, b)
     where
      push :: forall e. LuaError e => (a, b) -> LuaE e ()
    push (a
    a, b
    b) = do
        LuaE e ()
    forall e. LuaE e ()
    newtable
        Integer -> a -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    1 a
    a
        Integer -> b -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    2 b
    b

    instance {-# OVERLAPPABLE #-}
      (Pushable a, Pushable b, Pushable c) =>
      Pushable (a, b, c)
     where
      push :: forall e. LuaError e => (a, b, c) -> LuaE e ()
    push (a
    a, b
    b, c
    c) = do
        LuaE e ()
    forall e. LuaE e ()
    newtable
        Integer -> a -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    1 a
    a
        Integer -> b -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    2 b
    b
        Integer -> c -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    3 c
    c

    instance {-# OVERLAPPABLE #-}
      (Pushable a, Pushable b, Pushable c, Pushable d) =>
      Pushable (a, b, c, d)
     where
      push :: forall e. LuaError e => (a, b, c, d) -> LuaE e ()
    push (a
    a, b
    b, c
    c, d
    d) = do
        LuaE e ()
    forall e. LuaE e ()
    newtable
        Integer -> a -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    1 a
    a
        Integer -> b -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    2 b
    b
        Integer -> c -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    3 c
    c
        Integer -> d -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    4 d
    d

    instance {-# OVERLAPPABLE #-}
      (Pushable a, Pushable b, Pushable c, Pushable d, Pushable e) =>
      Pushable (a, b, c, d, e)
     where
      push :: forall e. LuaError e => (a, b, c, d, e) -> LuaE e ()
    push (a
    a, b
    b, c
    c, d
    d, e
    e) = do
        LuaE e ()
    forall e. LuaE e ()
    newtable
        Integer -> a -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    1 a
    a
        Integer -> b -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    2 b
    b
        Integer -> c -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    3 c
    c
        Integer -> d -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    4 d
    d
        Integer -> e -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    5 e
    e

    instance  {-# OVERLAPPABLE #-}
      (Pushable a, Pushable b, Pushable c,
        Pushable d, Pushable e, Pushable f) =>
      Pushable (a, b, c, d, e, f)
     where
      push :: forall e. LuaError e => (a, b, c, d, e, f) -> LuaE e ()
    push (a
    a, b
    b, c
    c, d
    d, e
    e, f
    f) = do
        LuaE e ()
    forall e. LuaE e ()
    newtable
        Integer -> a -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    1 a
    a
        Integer -> b -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    2 b
    b
        Integer -> c -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    3 c
    c
        Integer -> d -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    4 d
    d
        Integer -> e -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    5 e
    e
        Integer -> f -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    6 f
    f

    instance {-# OVERLAPPABLE #-}
      (Pushable a, Pushable b, Pushable c, Pushable d,
        Pushable e, Pushable f, Pushable g) =>
      Pushable (a, b, c, d, e, f, g)
     where
      push :: forall e. LuaError e => (a, b, c, d, e, f, g) -> LuaE e ()
    push (a
    a, b
    b, c
    c, d
    d, e
    e, f
    f, g
    g) = do
        LuaE e ()
    forall e. LuaE e ()
    newtable
        Integer -> a -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    1 a
    a
        Integer -> b -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    2 b
    b
        Integer -> c -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    3 c
    c
        Integer -> d -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    4 d
    d
        Integer -> e -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    5 e
    e
        Integer -> f -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    6 f
    f
        Integer -> g -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    7 g
    g

    instance {-# OVERLAPPABLE #-}
      (Pushable a, Pushable b, Pushable c, Pushable d,
        Pushable e, Pushable f, Pushable g, Pushable h) =>
      Pushable (a, b, c, d, e, f, g, h)
     where
      push :: forall e. LuaError e => (a, b, c, d, e, f, g, h) -> LuaE e ()
    push (a
    a, b
    b, c
    c, d
    d, e
    e, f
    f, g
    g, h
    h) = do
        LuaE e ()
    forall e. LuaE e ()
    newtable
        Integer -> a -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    1 a
    a
        Integer -> b -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    2 b
    b
        Integer -> c -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    3 c
    c
        Integer -> d -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    4 d
    d
        Integer -> e -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    5 e
    e
        Integer -> f -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    6 f
    f
        Integer -> g -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    7 g
    g
        Integer -> h -> LuaE e ()
    forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    8 h
    h

    -- | Set numeric key/value in table at the top of the stack.
    addRawInt :: (LuaError e, Pushable a) => Lua.Integer -> a -> LuaE e ()
    addRawInt :: forall e a. (LuaError e, Pushable a) => Integer -> a -> LuaE e ()
    addRawInt Integer
    idx a
    val = do
      a -> LuaE e ()
    forall e. LuaError e => a -> LuaE e ()
    forall a e. (Pushable a, LuaError e) => a -> LuaE e ()
    push a
    val
      StackIndex -> Integer -> LuaE e ()
    forall e. LuaError e => StackIndex -> Integer -> LuaE e ()
    rawseti (-StackIndex
    2) Integer
    idx