{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}

-- | Example of a private struct, defined as a global memory area, with a public
-- access function.

module PublicPrivate where

import Ivory.Language
import Ivory.Compile.C.CmdlineFrontend

[ivory|
struct Foo { foo_i   :: Stored Sint32
           ; foo_cnt :: Stored Uint32
           }
|]

privateFoo :: MemArea (Struct "Foo")
privateFoo  = area "private_foo" $
  Just (istruct [foo_i .= ival 0, foo_cnt .= ival 0])

privUpdate :: Def ('[Sint32] :-> ())
privUpdate = proc "privUpdate" $ \v -> body $ do
  let foo = addrOf privateFoo
  curr <- deref (foo ~> foo_cnt)
  store (foo ~> foo_i) v
  store (foo~> foo_cnt) (curr+1)

pubUpdate :: Def ('[Sint32] :-> ())
pubUpdate = proc "pubUpdate" $ \v -> body $ do
  call_ privUpdate v

cmodule :: Module
cmodule = package "PublicPrivate" $ do
  private $ do
    defStruct (Proxy :: Proxy "Foo")
    defMemArea privateFoo
    incl privUpdate
  public $ do
    incl pubUpdate

runPublicPrivate :: IO ()
runPublicPrivate  = runCompiler [cmodule] []
  initialOpts { outDir = Nothing, constFold = True }
