{-|
Module: Capnp.Basics
Description: Handling of "basic" capnp datatypes.

In particular

* 'Text' and 'Data' (which are primitive types in the schema language,
  but are both the same as @List(UInt8)@ on the wire).
* Lists of types other than those in "Capnp.Untyped".
  Whereas 'U.ListOf' only deals with low-level encodings of lists,
  this module's 'List' type can represent typed lists.
-}
{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies          #-}
module Capnp.Basics
    ( Text
    , Data(..)
    , ListElem(..)
    , MutListElem(..)
    , getData
    , getText
    , newData
    , newText
    , dataBytes
    , textBuffer
    , textBytes
    ) where

import Data.Word

import Control.Monad       (when, (>=>))
import Control.Monad.Catch (MonadThrow(throwM))

import qualified Data.ByteString as BS

import Capnp.Classes
    (FromPtr (..), ListElem (..), MutListElem (..), ToPtr (..))
import Capnp.Message          (Mutability (..))
import Data.Mutable           (Thaw (..))
import Internal.Gen.Instances ()

import qualified Capnp.Errors  as E
import qualified Capnp.Message as M
import qualified Capnp.Untyped as U


-- | A textual string (@Text@ in capnproto's schema language). On the wire,
-- this is NUL-terminated. The encoding should be UTF-8, but the library
-- /does not/ verify this; users of the library must do validation themselves, if
-- they care about this.
--
-- Rationale: validation would require doing an up-front pass over the data,
-- which runs counter to the overall design of capnproto.
newtype Text mut = Text (U.ListOf mut Word8)
-- The argument to the data constructor is the slice of the original message
-- containing the text, including the NUL terminator.

instance Thaw (Text 'Const) where
    type Mutable s (Text 'Const) = Text ('Mut s)
    thaw :: Text 'Const -> m (Mutable s (Text 'Const))
thaw (Text ListOf 'Const Word8
l) = ListOf ('Mut s) Word8 -> Text ('Mut s)
forall (mut :: Mutability). ListOf mut Word8 -> Text mut
Text (ListOf ('Mut s) Word8 -> Text ('Mut s))
-> m (ListOf ('Mut s) Word8) -> m (Text ('Mut s))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ListOf 'Const Word8 -> m (Mutable s (ListOf 'Const Word8))
forall a (m :: * -> *) s.
(Thaw a, PrimMonad m, PrimState m ~ s) =>
a -> m (Mutable s a)
thaw ListOf 'Const Word8
l
    unsafeThaw :: Text 'Const -> m (Mutable s (Text 'Const))
unsafeThaw (Text ListOf 'Const Word8
l) = ListOf ('Mut s) Word8 -> Text ('Mut s)
forall (mut :: Mutability). ListOf mut Word8 -> Text mut
Text (ListOf ('Mut s) Word8 -> Text ('Mut s))
-> m (ListOf ('Mut s) Word8) -> m (Text ('Mut s))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ListOf 'Const Word8 -> m (Mutable s (ListOf 'Const Word8))
forall a (m :: * -> *) s.
(Thaw a, PrimMonad m, PrimState m ~ s) =>
a -> m (Mutable s a)
unsafeThaw ListOf 'Const Word8
l
    freeze :: Mutable s (Text 'Const) -> m (Text 'Const)
freeze (Text l) = ListOf 'Const Word8 -> Text 'Const
forall (mut :: Mutability). ListOf mut Word8 -> Text mut
Text (ListOf 'Const Word8 -> Text 'Const)
-> m (ListOf 'Const Word8) -> m (Text 'Const)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Mutable s (ListOf 'Const Word8) -> m (ListOf 'Const Word8)
forall a (m :: * -> *) s.
(Thaw a, PrimMonad m, PrimState m ~ s) =>
Mutable s a -> m a
freeze Mutable s (ListOf 'Const Word8)
ListOf ('Mut s) Word8
l
    unsafeFreeze :: Mutable s (Text 'Const) -> m (Text 'Const)
unsafeFreeze (Text l) = ListOf 'Const Word8 -> Text 'Const
forall (mut :: Mutability). ListOf mut Word8 -> Text mut
Text (ListOf 'Const Word8 -> Text 'Const)
-> m (ListOf 'Const Word8) -> m (Text 'Const)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Mutable s (ListOf 'Const Word8) -> m (ListOf 'Const Word8)
forall a (m :: * -> *) s.
(Thaw a, PrimMonad m, PrimState m ~ s) =>
Mutable s a -> m a
unsafeFreeze Mutable s (ListOf 'Const Word8)
ListOf ('Mut s) Word8
l

-- | A blob of bytes (@Data@ in capnproto's schema language). The argument
-- to the data constructor is a slice into the message, containing the raw
-- bytes.
newtype Data mut = Data (U.ListOf mut Word8)

instance Thaw (Data 'Const) where
    type Mutable s (Data 'Const) = Data ('Mut s)
    thaw :: Data 'Const -> m (Mutable s (Data 'Const))
thaw (Data ListOf 'Const Word8
l) = ListOf ('Mut s) Word8 -> Data ('Mut s)
forall (mut :: Mutability). ListOf mut Word8 -> Data mut
Data (ListOf ('Mut s) Word8 -> Data ('Mut s))
-> m (ListOf ('Mut s) Word8) -> m (Data ('Mut s))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ListOf 'Const Word8 -> m (Mutable s (ListOf 'Const Word8))
forall a (m :: * -> *) s.
(Thaw a, PrimMonad m, PrimState m ~ s) =>
a -> m (Mutable s a)
thaw ListOf 'Const Word8
l
    unsafeThaw :: Data 'Const -> m (Mutable s (Data 'Const))
unsafeThaw (Data ListOf 'Const Word8
l) = ListOf ('Mut s) Word8 -> Data ('Mut s)
forall (mut :: Mutability). ListOf mut Word8 -> Data mut
Data (ListOf ('Mut s) Word8 -> Data ('Mut s))
-> m (ListOf ('Mut s) Word8) -> m (Data ('Mut s))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ListOf 'Const Word8 -> m (Mutable s (ListOf 'Const Word8))
forall a (m :: * -> *) s.
(Thaw a, PrimMonad m, PrimState m ~ s) =>
a -> m (Mutable s a)
unsafeThaw ListOf 'Const Word8
l
    freeze :: Mutable s (Data 'Const) -> m (Data 'Const)
freeze (Data l) = ListOf 'Const Word8 -> Data 'Const
forall (mut :: Mutability). ListOf mut Word8 -> Data mut
Data (ListOf 'Const Word8 -> Data 'Const)
-> m (ListOf 'Const Word8) -> m (Data 'Const)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Mutable s (ListOf 'Const Word8) -> m (ListOf 'Const Word8)
forall a (m :: * -> *) s.
(Thaw a, PrimMonad m, PrimState m ~ s) =>
Mutable s a -> m a
freeze Mutable s (ListOf 'Const Word8)
ListOf ('Mut s) Word8
l
    unsafeFreeze :: Mutable s (Data 'Const) -> m (Data 'Const)
unsafeFreeze (Data l) = ListOf 'Const Word8 -> Data 'Const
forall (mut :: Mutability). ListOf mut Word8 -> Data mut
Data (ListOf 'Const Word8 -> Data 'Const)
-> m (ListOf 'Const Word8) -> m (Data 'Const)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Mutable s (ListOf 'Const Word8) -> m (ListOf 'Const Word8)
forall a (m :: * -> *) s.
(Thaw a, PrimMonad m, PrimState m ~ s) =>
Mutable s a -> m a
unsafeFreeze Mutable s (ListOf 'Const Word8)
ListOf ('Mut s) Word8
l

-- | @'newData' msg len@ allocates a new data blob of length @len@ bytes
-- inside the message.
newData :: M.WriteCtx m s => M.Message ('Mut s) -> Int -> m (Data ('Mut s))
newData :: Message ('Mut s) -> Int -> m (Data ('Mut s))
newData Message ('Mut s)
msg Int
len = ListOf ('Mut s) Word8 -> Data ('Mut s)
forall (mut :: Mutability). ListOf mut Word8 -> Data mut
Data (ListOf ('Mut s) Word8 -> Data ('Mut s))
-> m (ListOf ('Mut s) Word8) -> m (Data ('Mut s))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Message ('Mut s) -> Int -> m (ListOf ('Mut s) Word8)
forall (m :: * -> *) s.
WriteCtx m s =>
Message ('Mut s) -> Int -> m (ListOf ('Mut s) Word8)
U.allocList8 Message ('Mut s)
msg Int
len

-- | Interpret a list of 'Word8' as a capnproto 'Data' value.
getData :: U.ReadCtx m mut => U.ListOf mut Word8 -> m (Data mut)
getData :: ListOf mut Word8 -> m (Data mut)
getData = Data mut -> m (Data mut)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Data mut -> m (Data mut))
-> (ListOf mut Word8 -> Data mut)
-> ListOf mut Word8
-> m (Data mut)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ListOf mut Word8 -> Data mut
forall (mut :: Mutability). ListOf mut Word8 -> Data mut
Data

-- | @'newText' msg len@ Allocates a new 'Text' inside the message. The
-- value has space for @len@ *bytes* (not characters).
newText :: M.WriteCtx m s => M.Message ('Mut s) -> Int -> m (Text ('Mut s))
newText :: Message ('Mut s) -> Int -> m (Text ('Mut s))
newText Message ('Mut s)
msg Int
len =
    ListOf ('Mut s) Word8 -> Text ('Mut s)
forall (mut :: Mutability). ListOf mut Word8 -> Text mut
Text (ListOf ('Mut s) Word8 -> Text ('Mut s))
-> m (ListOf ('Mut s) Word8) -> m (Text ('Mut s))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Message ('Mut s) -> Int -> m (ListOf ('Mut s) Word8)
forall (m :: * -> *) s.
WriteCtx m s =>
Message ('Mut s) -> Int -> m (ListOf ('Mut s) Word8)
U.allocList8 Message ('Mut s)
msg (Int
lenInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)

-- | Interpret a list of 'Word8' as a capnproto 'Text' value.
--
-- This vaildates that the list is NUL-terminated, but not that it is valid
-- UTF-8. If it is not NUL-terminaed, a 'SchemaViolationError' is thrown.
getText :: U.ReadCtx m mut => U.ListOf mut Word8 -> m (Text mut)
getText :: ListOf mut Word8 -> m (Text mut)
getText ListOf mut Word8
list = do
    let len :: Int
len = ListOf mut Word8 -> Int
forall (msg :: Mutability) a. ListOf msg a -> Int
U.length ListOf mut Word8
list
    Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Error -> m ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (Error -> m ()) -> Error -> m ()
forall a b. (a -> b) -> a -> b
$ String -> Error
E.SchemaViolationError
        String
"Text is not NUL-terminated (list of bytes has length 0)"
    Word8
lastByte <- Int -> ListOf mut Word8 -> m Word8
forall (m :: * -> *) (mut :: Mutability) a.
ReadCtx m mut =>
Int -> ListOf mut a -> m a
U.index (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) ListOf mut Word8
list
    Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Word8
lastByte Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
0) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ Error -> m ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (Error -> m ()) -> Error -> m ()
forall a b. (a -> b) -> a -> b
$ String -> Error
E.SchemaViolationError (String -> Error) -> String -> Error
forall a b. (a -> b) -> a -> b
$
        String
"Text is not NUL-terminated (last byte is " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Word8 -> String
forall a. Show a => a -> String
show Word8
lastByte String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
    Text mut -> m (Text mut)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text mut -> m (Text mut)) -> Text mut -> m (Text mut)
forall a b. (a -> b) -> a -> b
$ ListOf mut Word8 -> Text mut
forall (mut :: Mutability). ListOf mut Word8 -> Text mut
Text ListOf mut Word8
list

-- | Convert a 'Data' to a 'BS.ByteString'.
dataBytes :: U.ReadCtx m 'Const => Data 'Const -> m BS.ByteString
dataBytes :: Data 'Const -> m ByteString
dataBytes (Data ListOf 'Const Word8
list) = ListOf 'Const Word8 -> m ByteString
forall (m :: * -> *).
ReadCtx m 'Const =>
ListOf 'Const Word8 -> m ByteString
U.rawBytes ListOf 'Const Word8
list

-- | Return the underlying buffer containing the text. This does not include the
-- null terminator.
textBuffer :: U.ReadCtx m mut => Text mut -> m (U.ListOf mut Word8)
textBuffer :: Text mut -> m (ListOf mut Word8)
textBuffer (Text ListOf mut Word8
list) = Int -> ListOf mut Word8 -> m (ListOf mut Word8)
forall (m :: * -> *) (msg :: Mutability) a.
MonadThrow m =>
Int -> ListOf msg a -> m (ListOf msg a)
U.take (ListOf mut Word8 -> Int
forall (msg :: Mutability) a. ListOf msg a -> Int
U.length ListOf mut Word8
list Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) ListOf mut Word8
list

-- | Convert a 'Text' to a 'BS.ByteString', comprising the raw bytes of the text
-- (not counting the NUL terminator).
textBytes :: U.ReadCtx m 'Const => Text 'Const -> m BS.ByteString
textBytes :: Text 'Const -> m ByteString
textBytes = Text 'Const -> m (ListOf 'Const Word8)
forall (m :: * -> *) (mut :: Mutability).
ReadCtx m mut =>
Text mut -> m (ListOf mut Word8)
textBuffer (Text 'Const -> m (ListOf 'Const Word8))
-> (ListOf 'Const Word8 -> m ByteString)
-> Text 'Const
-> m ByteString
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> ListOf 'Const Word8 -> m ByteString
forall (m :: * -> *).
ReadCtx m 'Const =>
ListOf 'Const Word8 -> m ByteString
U.rawBytes

------------------- (Mut)ListElem instances for text and data ------------------

instance ListElem mut (Data mut) where
    newtype List mut (Data mut) = DataList (U.ListOf mut (Maybe (U.Ptr mut)))

    listFromPtr :: Message mut -> Maybe (Ptr mut) -> m (List mut (Data mut))
listFromPtr Message mut
msg Maybe (Ptr mut)
ptr = ListOf mut (Maybe (Ptr mut)) -> List mut (Data mut)
forall (mut :: Mutability).
ListOf mut (Maybe (Ptr mut)) -> List mut (Data mut)
DataList (ListOf mut (Maybe (Ptr mut)) -> List mut (Data mut))
-> m (ListOf mut (Maybe (Ptr mut))) -> m (List mut (Data mut))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Message mut -> Maybe (Ptr mut) -> m (ListOf mut (Maybe (Ptr mut)))
forall (mut :: Mutability) a (m :: * -> *).
(FromPtr mut a, ReadCtx m mut) =>
Message mut -> Maybe (Ptr mut) -> m a
fromPtr Message mut
msg Maybe (Ptr mut)
ptr
    toUntypedList :: List mut (Data mut) -> List mut
toUntypedList (DataList l) = ListOf mut (Maybe (Ptr mut)) -> List mut
forall (mut :: Mutability).
ListOf mut (Maybe (Ptr mut)) -> List mut
U.ListPtr ListOf mut (Maybe (Ptr mut))
l

    length :: List mut (Data mut) -> Int
length (DataList l) = ListOf mut (Maybe (Ptr mut)) -> Int
forall (msg :: Mutability) a. ListOf msg a -> Int
U.length ListOf mut (Maybe (Ptr mut))
l
    index :: Int -> List mut (Data mut) -> m (Data mut)
index Int
i (DataList l) = Int -> ListOf mut (Maybe (Ptr mut)) -> m (Data mut)
forall (m :: * -> *) (mut :: Mutability) a.
(ReadCtx m mut, FromPtr mut a) =>
Int -> ListOf mut (Maybe (Ptr mut)) -> m a
ptrListIndex Int
i ListOf mut (Maybe (Ptr mut))
l

instance MutListElem s (Data ('Mut s)) where
    setIndex :: Data ('Mut s) -> Int -> List ('Mut s) (Data ('Mut s)) -> m ()
setIndex (Data ListOf ('Mut s) Word8
e) Int
i (DataList l) =
        Maybe (Ptr ('Mut s))
-> Int -> ListOf ('Mut s) (Maybe (Ptr ('Mut s))) -> m ()
forall (m :: * -> *) s a.
RWCtx m s =>
a -> Int -> ListOf ('Mut s) a -> m ()
U.setIndex (Ptr ('Mut s) -> Maybe (Ptr ('Mut s))
forall a. a -> Maybe a
Just (List ('Mut s) -> Ptr ('Mut s)
forall (mut :: Mutability). List mut -> Ptr mut
U.PtrList (ListOf ('Mut s) Word8 -> List ('Mut s)
forall (mut :: Mutability). ListOf mut Word8 -> List mut
U.List8 ListOf ('Mut s) Word8
e))) Int
i ListOf ('Mut s) (Maybe (Ptr ('Mut s)))
l
    newList :: Message ('Mut s) -> Int -> m (List ('Mut s) (Data ('Mut s)))
newList Message ('Mut s)
msg Int
len = ListOf ('Mut s) (Maybe (Ptr ('Mut s)))
-> List ('Mut s) (Data ('Mut s))
forall (mut :: Mutability).
ListOf mut (Maybe (Ptr mut)) -> List mut (Data mut)
DataList (ListOf ('Mut s) (Maybe (Ptr ('Mut s)))
 -> List ('Mut s) (Data ('Mut s)))
-> m (ListOf ('Mut s) (Maybe (Ptr ('Mut s))))
-> m (List ('Mut s) (Data ('Mut s)))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Message ('Mut s)
-> Int -> m (ListOf ('Mut s) (Maybe (Ptr ('Mut s))))
forall (m :: * -> *) s.
WriteCtx m s =>
Message ('Mut s)
-> Int -> m (ListOf ('Mut s) (Maybe (Ptr ('Mut s))))
U.allocListPtr Message ('Mut s)
msg Int
len

instance ListElem mut (Text mut) where
    newtype List mut (Text mut) = TextList (U.ListOf mut (Maybe (U.Ptr mut)))

    listFromPtr :: Message mut -> Maybe (Ptr mut) -> m (List mut (Text mut))
listFromPtr Message mut
msg Maybe (Ptr mut)
ptr = ListOf mut (Maybe (Ptr mut)) -> List mut (Text mut)
forall (mut :: Mutability).
ListOf mut (Maybe (Ptr mut)) -> List mut (Text mut)
TextList (ListOf mut (Maybe (Ptr mut)) -> List mut (Text mut))
-> m (ListOf mut (Maybe (Ptr mut))) -> m (List mut (Text mut))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Message mut -> Maybe (Ptr mut) -> m (ListOf mut (Maybe (Ptr mut)))
forall (mut :: Mutability) a (m :: * -> *).
(FromPtr mut a, ReadCtx m mut) =>
Message mut -> Maybe (Ptr mut) -> m a
fromPtr Message mut
msg Maybe (Ptr mut)
ptr
    toUntypedList :: List mut (Text mut) -> List mut
toUntypedList (TextList l) = ListOf mut (Maybe (Ptr mut)) -> List mut
forall (mut :: Mutability).
ListOf mut (Maybe (Ptr mut)) -> List mut
U.ListPtr ListOf mut (Maybe (Ptr mut))
l

    length :: List mut (Text mut) -> Int
length (TextList l) = ListOf mut (Maybe (Ptr mut)) -> Int
forall (msg :: Mutability) a. ListOf msg a -> Int
U.length ListOf mut (Maybe (Ptr mut))
l
    index :: Int -> List mut (Text mut) -> m (Text mut)
index Int
i (TextList l) = Int -> ListOf mut (Maybe (Ptr mut)) -> m (Text mut)
forall (m :: * -> *) (mut :: Mutability) a.
(ReadCtx m mut, FromPtr mut a) =>
Int -> ListOf mut (Maybe (Ptr mut)) -> m a
ptrListIndex Int
i ListOf mut (Maybe (Ptr mut))
l

instance MutListElem s (Text ('Mut s)) where
    setIndex :: Text ('Mut s) -> Int -> List ('Mut s) (Text ('Mut s)) -> m ()
setIndex (Text ListOf ('Mut s) Word8
e) Int
i (TextList l) =
        Maybe (Ptr ('Mut s))
-> Int -> ListOf ('Mut s) (Maybe (Ptr ('Mut s))) -> m ()
forall (m :: * -> *) s a.
RWCtx m s =>
a -> Int -> ListOf ('Mut s) a -> m ()
U.setIndex (Ptr ('Mut s) -> Maybe (Ptr ('Mut s))
forall a. a -> Maybe a
Just (List ('Mut s) -> Ptr ('Mut s)
forall (mut :: Mutability). List mut -> Ptr mut
U.PtrList (ListOf ('Mut s) Word8 -> List ('Mut s)
forall (mut :: Mutability). ListOf mut Word8 -> List mut
U.List8 ListOf ('Mut s) Word8
e))) Int
i ListOf ('Mut s) (Maybe (Ptr ('Mut s)))
l
    newList :: Message ('Mut s) -> Int -> m (List ('Mut s) (Text ('Mut s)))
newList Message ('Mut s)
msg Int
len = ListOf ('Mut s) (Maybe (Ptr ('Mut s)))
-> List ('Mut s) (Text ('Mut s))
forall (mut :: Mutability).
ListOf mut (Maybe (Ptr mut)) -> List mut (Text mut)
TextList (ListOf ('Mut s) (Maybe (Ptr ('Mut s)))
 -> List ('Mut s) (Text ('Mut s)))
-> m (ListOf ('Mut s) (Maybe (Ptr ('Mut s))))
-> m (List ('Mut s) (Text ('Mut s)))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Message ('Mut s)
-> Int -> m (ListOf ('Mut s) (Maybe (Ptr ('Mut s))))
forall (m :: * -> *) s.
WriteCtx m s =>
Message ('Mut s)
-> Int -> m (ListOf ('Mut s) (Maybe (Ptr ('Mut s))))
U.allocListPtr Message ('Mut s)
msg Int
len

-- helper for the above instances.
ptrListIndex
    :: (U.ReadCtx m mut, FromPtr mut a)
    => Int -> U.ListOf mut (Maybe (U.Ptr mut)) -> m a
ptrListIndex :: Int -> ListOf mut (Maybe (Ptr mut)) -> m a
ptrListIndex Int
i ListOf mut (Maybe (Ptr mut))
list = do
    Maybe (Ptr mut)
ptr <- Int -> ListOf mut (Maybe (Ptr mut)) -> m (Maybe (Ptr mut))
forall (m :: * -> *) (mut :: Mutability) a.
ReadCtx m mut =>
Int -> ListOf mut a -> m a
U.index Int
i ListOf mut (Maybe (Ptr mut))
list
    Message mut -> Maybe (Ptr mut) -> m a
forall (mut :: Mutability) a (m :: * -> *).
(FromPtr mut a, ReadCtx m mut) =>
Message mut -> Maybe (Ptr mut) -> m a
fromPtr (ListOf mut (Maybe (Ptr mut)) -> Message mut
forall a (mut :: Mutability). HasMessage a mut => a -> Message mut
U.message ListOf mut (Maybe (Ptr mut))
list) Maybe (Ptr mut)
ptr

--------- To/FromPtr instances for Text and Data. These wrap lists of bytes. --------

instance FromPtr mut (Data mut) where
    fromPtr :: Message mut -> Maybe (Ptr mut) -> m (Data mut)
fromPtr Message mut
msg Maybe (Ptr mut)
ptr = Message mut -> Maybe (Ptr mut) -> m (ListOf mut Word8)
forall (mut :: Mutability) a (m :: * -> *).
(FromPtr mut a, ReadCtx m mut) =>
Message mut -> Maybe (Ptr mut) -> m a
fromPtr Message mut
msg Maybe (Ptr mut)
ptr m (ListOf mut Word8)
-> (ListOf mut Word8 -> m (Data mut)) -> m (Data mut)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ListOf mut Word8 -> m (Data mut)
forall (m :: * -> *) (mut :: Mutability).
ReadCtx m mut =>
ListOf mut Word8 -> m (Data mut)
getData
instance ToPtr s (Data ('Mut s)) where
    toPtr :: Message ('Mut s) -> Data ('Mut s) -> m (Maybe (Ptr ('Mut s)))
toPtr Message ('Mut s)
msg (Data ListOf ('Mut s) Word8
l) = Message ('Mut s)
-> ListOf ('Mut s) Word8 -> m (Maybe (Ptr ('Mut s)))
forall s a (m :: * -> *).
(ToPtr s a, WriteCtx m s) =>
Message ('Mut s) -> a -> m (Maybe (Ptr ('Mut s)))
toPtr Message ('Mut s)
msg ListOf ('Mut s) Word8
l

instance FromPtr mut (Text mut) where
    fromPtr :: Message mut -> Maybe (Ptr mut) -> m (Text mut)
fromPtr Message mut
msg Maybe (Ptr mut)
ptr = case Maybe (Ptr mut)
ptr of
        Just Ptr mut
_ ->
            Message mut -> Maybe (Ptr mut) -> m (ListOf mut Word8)
forall (mut :: Mutability) a (m :: * -> *).
(FromPtr mut a, ReadCtx m mut) =>
Message mut -> Maybe (Ptr mut) -> m a
fromPtr Message mut
msg Maybe (Ptr mut)
ptr m (ListOf mut Word8)
-> (ListOf mut Word8 -> m (Text mut)) -> m (Text mut)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ListOf mut Word8 -> m (Text mut)
forall (m :: * -> *) (mut :: Mutability).
ReadCtx m mut =>
ListOf mut Word8 -> m (Text mut)
getText
        Maybe (Ptr mut)
Nothing -> do
            -- getText expects and strips off a NUL byte at the end of the
            -- string. In the case of a null pointer we just want to return
            -- the empty string, so we bypass it here.
            Data ListOf mut Word8
bytes <- Message mut -> Maybe (Ptr mut) -> m (Data mut)
forall (mut :: Mutability) a (m :: * -> *).
(FromPtr mut a, ReadCtx m mut) =>
Message mut -> Maybe (Ptr mut) -> m a
fromPtr Message mut
msg Maybe (Ptr mut)
ptr
            Text mut -> m (Text mut)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text mut -> m (Text mut)) -> Text mut -> m (Text mut)
forall a b. (a -> b) -> a -> b
$ ListOf mut Word8 -> Text mut
forall (mut :: Mutability). ListOf mut Word8 -> Text mut
Text ListOf mut Word8
bytes
instance ToPtr s (Text ('Mut s)) where
    toPtr :: Message ('Mut s) -> Text ('Mut s) -> m (Maybe (Ptr ('Mut s)))
toPtr Message ('Mut s)
msg (Text ListOf ('Mut s) Word8
l) = Message ('Mut s)
-> ListOf ('Mut s) Word8 -> m (Maybe (Ptr ('Mut s)))
forall s a (m :: * -> *).
(ToPtr s a, WriteCtx m s) =>
Message ('Mut s) -> a -> m (Maybe (Ptr ('Mut s)))
toPtr Message ('Mut s)
msg ListOf ('Mut s) Word8
l