capnp-0.1.0.0: lib/Data/Capnp/Pointer.hs
{- |
Module: Data.Capnp.Pointer
Description: Support for parsing/serializing capnproto pointers
This module provides support for parsing and serializing capnproto pointers.
-}
module Data.Capnp.Pointer
( Ptr(..)
, ElementSize(..)
, EltSpec(..)
, parsePtr
, serializePtr
, parseEltSpec
, serializeEltSpec
)
where
import Data.Bits
import Data.Int
import Data.Word
import Data.Capnp.Bits
-- | A 'Ptr' represents the information in a capnproto pointer.
data Ptr
= StructPtr !Int32 !Word16 !Word16
-- ^ @'StructPtr' off dataSz ptrSz@ is a pointer to a struct
-- at offset @off@ in words from the end of the pointer, with
-- a data section of size @dataSz@ words, and a pointer section
-- of size @ptrSz@ words.
--
-- Note that the value @'StructPtr' 0 0 0@ is illegal, since
-- its encoding is reserved for the "null" pointer.
| ListPtr !Int32 !EltSpec
-- ^ @'ListPtr' off eltSpec@ is a pointer to a list starting at
-- offset @off@ in words from the end of the pointer. @eltSpec@
-- encodes the C and D fields in the encoding spec; see 'EltSpec'
-- for details
| FarPtr !Bool !Word32 !Word32
-- ^ @'FarPtr' twoWords off segment@ is a far pointer, whose landing
-- pad is:
--
-- * two words iff @twoWords@,
-- * @off@ words from the start of the target segment, and
-- * in segment id @segment@.
| CapPtr !Word32
-- ^ @'CapPtr' id@ is a pointer to the capability with the id @id@.
deriving(Show, Eq)
-- | The element size field in a list pointer.
data ElementSize
= Sz0
| Sz1
| Sz8
| Sz16
| Sz32
| Sz64
| SzPtr
deriving(Show, Eq, Enum)
-- | A combination of the C and D fields in a list pointer, i.e. the element
-- size, and either the number of elements in the list, or the total number
-- of /words/ in the list (if size is composite).
data EltSpec
= EltNormal !ElementSize !Word32
-- ^ @'EltNormal' size len@ is a normal (non-composite) element type
-- (C /= 7). @size@ is the size of the elements, and @len@ is the
-- number of elements in the list.
| EltComposite !Int32
-- ^ @EltComposite len@ is a composite element (C == 7). @len@ is the
-- length of the list in words.
deriving(Show, Eq)
-- | @'parsePtr' word@ parses word as a capnproto pointer. A null pointer is
-- parsed as 'Nothing'.
parsePtr :: Word64 -> Maybe Ptr
parsePtr 0 = Nothing
parsePtr word = Just $
case bitRange word 0 2 of
0 -> StructPtr
(i30 (lo word))
(bitRange word 32 48)
(bitRange word 48 64)
1 -> ListPtr
(i30 (lo word))
(parseEltSpec word)
2 -> FarPtr
(toEnum (bitRange word 2 3))
(bitRange word 3 32)
(bitRange word 32 64)
3 -> CapPtr (bitRange word 32 64)
_ -> error "unreachable"
-- | @'serializePtr' ptr@ serializes the pointer as a 'Word64', translating
-- 'Nothing' to a null pointer.
serializePtr :: Maybe Ptr -> Word64
serializePtr Nothing = 0
serializePtr (Just p) = serializePtr' p
serializePtr' :: Ptr -> Word64
serializePtr' (StructPtr 0 0 0) =
-- We need to handle this specially, since the normal encoding
-- would be interpreted as null. We can get around this by changing
-- the offset.
serializePtr' (StructPtr (-1) 0 0)
serializePtr' (StructPtr off dataSz ptrSz) =
-- 0 .|.
fromLo (fromI30 off) .|.
(fromIntegral dataSz `shiftL` 32) .|.
(fromIntegral ptrSz `shiftL` 48)
serializePtr' (ListPtr off eltSpec) = -- eltSz numElts) =
1 .|.
fromLo (fromI30 off) .|.
serializeEltSpec eltSpec
serializePtr' (FarPtr twoWords off segId) =
2 .|.
(fromIntegral (fromEnum twoWords) `shiftL` 2) .|.
(fromIntegral off `shiftL` 3) .|.
(fromIntegral segId `shiftL` 32)
serializePtr' (CapPtr index) =
3 .|.
-- (fromIntegral 0 `shiftL` 2) .|.
(fromIntegral index `shiftL` 32)
-- | @'parseEltSpec' word@ reads the 'EltSpec' from @word@, which must be the
-- encoding of a list pointer (this is not verified).
parseEltSpec :: Word64 -> EltSpec
parseEltSpec word = case bitRange word 32 35 of
7 -> EltComposite (i29 (hi word))
sz -> EltNormal (toEnum sz) (bitRange word 35 64)
-- | @'serializeEltSpec' eltSpec@ serializes @eltSpec@ as a 'Word64'. all bits
-- which are not determined by the 'EltSpec' are zero.
serializeEltSpec :: EltSpec -> Word64
serializeEltSpec (EltNormal sz len) =
(fromIntegral (fromEnum sz) `shiftL` 32) .|.
(fromIntegral len `shiftL` 35)
serializeEltSpec (EltComposite words) =
(7 `shiftL` 32) .|.
fromHi (fromI29 words)