packages feed

ppad-lmdb-0.1.0: lib/Database/LMDB/Internal.hs

{-# OPTIONS_HADDOCK not-home #-}
{-# LANGUAGE CApiFFI #-}

-- |
-- Module: Database.LMDB.Internal
-- Copyright: (c) 2026 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- Raw FFI declarations and constants for the LMDB C API. This module
-- is exposed for power users; prefer "Database.LMDB" for the safe,
-- bracketed interface.

module Database.LMDB.Internal (
  -- * Opaque handles
    MDB_env
  , MDB_txn
  , MDB_dbi
  , MDB_cursor

  -- * Value pair
  , MDB_val(..)

  -- * Environment flags
  , _MDB_NOSUBDIR
  , _MDB_NOSYNC
  , _MDB_RDONLY
  , _MDB_NOMETASYNC
  , _MDB_NOTLS

  -- * Database open flags
  , _MDB_CREATE

  -- * Put flags
  , _MDB_NOOVERWRITE
  , _MDB_APPEND

  -- * Cursor operations
  , _MDB_FIRST
  , _MDB_LAST
  , _MDB_NEXT
  , _MDB_PREV
  , _MDB_SET
  , _MDB_SET_RANGE
  , _MDB_GET_CURRENT

  -- * Error codes
  , _MDB_SUCCESS
  , _MDB_KEYEXIST
  , _MDB_NOTFOUND
  , _MDB_MAP_FULL
  , _MDB_CORRUPTED
  , _MDB_PANIC
  , _MDB_VERSION_MISMATCH
  , _MDB_INVALID
  , _MDB_BAD_TXN
  , _MDB_BAD_VALSIZE
  , _MDB_BAD_DBI

  -- * Environment lifecycle
  , mdb_env_create
  , mdb_env_open
  , mdb_env_close
  , mdb_env_set_mapsize
  , mdb_env_set_maxdbs
  , mdb_env_sync

  -- * Transactions
  , mdb_txn_begin
  , mdb_txn_commit
  , mdb_txn_abort

  -- * Databases
  , mdb_dbi_open
  , mdb_dbi_close

  -- * Key-value operations
  , mdb_get
  , mdb_put
  , mdb_del

  -- * Cursors
  , mdb_cursor_open
  , mdb_cursor_close
  , mdb_cursor_get

  -- * Diagnostics
  , mdb_strerror
  ) where

import Foreign.C.String (CString)
import Foreign.C.Types
  (CInt(..), CUInt(..), CSize(..), CChar(..))
import Foreign.Ptr (Ptr)
import Foreign.Storable (Storable(..))
import System.Posix.Types (CMode(..))

-- opaque handles -------------------------------------------------------------

data MDB_env
data MDB_txn
data MDB_cursor

-- | LMDB's database identifier is a plain @unsigned int@ value type,
--   not a pointer.
type MDB_dbi = CUInt

-- value pair -----------------------------------------------------------------

-- | The key-or-value pair LMDB passes across the FFI boundary.
data MDB_val = MDB_val
  { mvSize :: !CSize
  , mvData :: !(Ptr CChar)
  }

instance Storable MDB_val where
  sizeOf    _ = 2 * sizeOf (undefined :: Ptr ())
  {-# INLINE sizeOf #-}
  alignment _ = alignment   (undefined :: Ptr ())
  {-# INLINE alignment #-}
  peek p = do
    sz <- peekByteOff p 0
    pd <- peekByteOff p (sizeOf (undefined :: Ptr ()))
    pure (MDB_val sz pd)
  {-# INLINE peek #-}
  poke p (MDB_val sz pd) = do
    pokeByteOff p 0 sz
    pokeByteOff p (sizeOf (undefined :: Ptr ())) pd
  {-# INLINE poke #-}

-- environment flags ----------------------------------------------------------

_MDB_NOSUBDIR, _MDB_NOSYNC, _MDB_RDONLY, _MDB_NOMETASYNC, _MDB_NOTLS
  :: CUInt
_MDB_NOSUBDIR    = 0x4000
_MDB_NOSYNC      = 0x10000
_MDB_RDONLY      = 0x20000
_MDB_NOMETASYNC  = 0x40000
_MDB_NOTLS       = 0x200000

-- database open flags --------------------------------------------------------

_MDB_CREATE :: CUInt
_MDB_CREATE = 0x40000

-- put flags ------------------------------------------------------------------

_MDB_NOOVERWRITE, _MDB_APPEND :: CUInt
_MDB_NOOVERWRITE = 0x10
_MDB_APPEND      = 0x20000

-- cursor ops -----------------------------------------------------------------

-- These mirror the enum MDB_cursor_op declared in lmdb.h. We only
-- bind the operations the safe wrapper currently uses; add more as
-- needed.

_MDB_FIRST, _MDB_LAST, _MDB_NEXT, _MDB_PREV
  , _MDB_SET, _MDB_SET_RANGE, _MDB_GET_CURRENT :: CInt
_MDB_FIRST       = 0
_MDB_LAST        = 6
_MDB_NEXT        = 8
_MDB_PREV        = 12
_MDB_SET         = 15
_MDB_SET_RANGE   = 17  -- index per MDB_cursor_op enum (post-DUP entries)
_MDB_GET_CURRENT = 4

-- error codes ----------------------------------------------------------------

_MDB_SUCCESS, _MDB_KEYEXIST, _MDB_NOTFOUND, _MDB_MAP_FULL
  , _MDB_CORRUPTED, _MDB_PANIC, _MDB_VERSION_MISMATCH, _MDB_INVALID
  , _MDB_BAD_TXN, _MDB_BAD_VALSIZE, _MDB_BAD_DBI :: CInt
_MDB_SUCCESS          = 0
_MDB_KEYEXIST         = -30799
_MDB_NOTFOUND         = -30798
_MDB_CORRUPTED        = -30796
_MDB_PANIC            = -30795
_MDB_VERSION_MISMATCH = -30794
_MDB_INVALID          = -30793
_MDB_MAP_FULL         = -30792
_MDB_BAD_TXN          = -30782
_MDB_BAD_VALSIZE      = -30781
_MDB_BAD_DBI          = -30780

-- foreign imports ------------------------------------------------------------

-- environment lifecycle

foreign import capi "lmdb.h mdb_env_create"
  mdb_env_create :: Ptr (Ptr MDB_env) -> IO CInt

foreign import capi "lmdb.h mdb_env_open"
  mdb_env_open
    :: Ptr MDB_env -> CString -> CUInt -> CMode -> IO CInt

foreign import capi "lmdb.h mdb_env_close"
  mdb_env_close :: Ptr MDB_env -> IO ()

foreign import capi "lmdb.h mdb_env_set_mapsize"
  mdb_env_set_mapsize :: Ptr MDB_env -> CSize -> IO CInt

foreign import capi "lmdb.h mdb_env_set_maxdbs"
  mdb_env_set_maxdbs :: Ptr MDB_env -> MDB_dbi -> IO CInt

foreign import capi "lmdb.h mdb_env_sync"
  mdb_env_sync :: Ptr MDB_env -> CInt -> IO CInt

-- transactions

foreign import capi "lmdb.h mdb_txn_begin"
  mdb_txn_begin
    :: Ptr MDB_env
    -> Ptr MDB_txn      -- parent (NULL for top-level)
    -> CUInt            -- flags
    -> Ptr (Ptr MDB_txn)
    -> IO CInt

foreign import capi "lmdb.h mdb_txn_commit"
  mdb_txn_commit :: Ptr MDB_txn -> IO CInt

foreign import capi "lmdb.h mdb_txn_abort"
  mdb_txn_abort :: Ptr MDB_txn -> IO ()

-- databases

foreign import capi "lmdb.h mdb_dbi_open"
  mdb_dbi_open
    :: Ptr MDB_txn
    -> CString          -- name; NULL for the default unnamed db
    -> CUInt            -- flags
    -> Ptr MDB_dbi
    -> IO CInt

foreign import capi "lmdb.h mdb_dbi_close"
  mdb_dbi_close :: Ptr MDB_env -> MDB_dbi -> IO ()

-- key-value ops

foreign import capi "lmdb.h mdb_get"
  mdb_get
    :: Ptr MDB_txn -> MDB_dbi -> Ptr MDB_val -> Ptr MDB_val -> IO CInt

foreign import capi "lmdb.h mdb_put"
  mdb_put
    :: Ptr MDB_txn
    -> MDB_dbi
    -> Ptr MDB_val      -- key
    -> Ptr MDB_val      -- data
    -> CUInt            -- flags
    -> IO CInt

foreign import capi "lmdb.h mdb_del"
  mdb_del
    :: Ptr MDB_txn
    -> MDB_dbi
    -> Ptr MDB_val      -- key
    -> Ptr MDB_val      -- data; NULL except for MDB_DUPSORT
    -> IO CInt

-- cursors

foreign import capi "lmdb.h mdb_cursor_open"
  mdb_cursor_open
    :: Ptr MDB_txn -> MDB_dbi -> Ptr (Ptr MDB_cursor) -> IO CInt

foreign import capi "lmdb.h mdb_cursor_close"
  mdb_cursor_close :: Ptr MDB_cursor -> IO ()

foreign import capi "lmdb.h mdb_cursor_get"
  mdb_cursor_get
    :: Ptr MDB_cursor
    -> Ptr MDB_val      -- key (in/out)
    -> Ptr MDB_val      -- data (out)
    -> CInt             -- MDB_cursor_op
    -> IO CInt

-- diagnostics

foreign import capi "lmdb.h mdb_strerror"
  mdb_strerror :: CInt -> IO CString