{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}

module Data.Packed.Packable (Packable (..), pack) where

import ByteString.StrictBuilder
import Data.Packed.Needs (
    Needs (..),
    NeedsWriter,
    finish,
    mkNeedsBuilder,
    withEmptyNeeds,
 )
import Data.Packed.Packed (Packed)
import Foreign
import Prelude hiding (length)

class Packable a where
    write :: a -> NeedsWriter a r t

instance (Storable a) => Packable a where
    write :: forall (r :: [*]) (t :: [*]). a -> NeedsWriter a r t
write a
v = (Needs (a : r) t -> Needs r t) -> NeedsBuilder (a : r) t r t
forall (ps :: [*]) (ts :: [*]) (pd :: [*]) (td :: [*]).
(Needs ps ts -> Needs pd td) -> NeedsBuilder ps ts pd td
mkNeedsBuilder (\(Needs Builder
b) -> Builder -> Needs r t
forall (p :: [*]) (t :: [*]). Builder -> Needs p t
Needs (Builder
b Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> a -> Builder
forall a. Storable a => a -> Builder
storable a
v))

pack :: (Packable a) => a -> Packed '[a]
pack :: forall a. Packable a => a -> Packed '[a]
pack a
a = Needs '[] '[a] -> Packed '[a]
forall (t :: [*]). Needs '[] t -> Packed t
finish (NeedsBuilder '[a] '[a] '[] '[a] -> Needs '[] '[a]
forall (a :: [*]) (b :: [*]) (x :: [*]) (y :: [*]).
NeedsBuilder a b x y -> Needs x y
withEmptyNeeds (a -> NeedsBuilder '[a] '[a] '[] '[a]
forall (r :: [*]) (t :: [*]). a -> NeedsWriter a r t
forall a (r :: [*]) (t :: [*]).
Packable a =>
a -> NeedsWriter a r t
write a
a))