packages feed

protocol-buffers-0.0.5: Text/ProtocolBuffers/WireMessage.hs

module Text.ProtocolBuffers.WireMessage where

import Data.Map

{- The point of this module:

There needs to be a way to represent the bytes in a form that is
in-between the type specific messages and the single string of bytes.

Encoding and Deconding WireMessage does not respect ordering between
different FieldId but must respect ordering of repeated FieldId
values.

Converting WireData to and from the actual types (e.g. sint64) will be
done elsewhere.

Converting a WireData to a message type will require code generation
of a class instance.

-}

import Data.Bits(Bits(..))
import Data.Generics(Data(..),Typeable(..))
import Data.Word(Word32,Word64)
import Data.ByteString(ByteString)
import Data.Sequence(Seq)
import Data.Map(Map,unionWith)
import Data.Monoid(Monoid(..))

newtype FieldId = FieldId { getFieldID :: Word32 } -- really 29 bits, 0 to 2^29-1
  deriving (Eq,Ord,Show,Data,Typeable)

newtype WireId = WireId { getWireID :: Word32 } -- really 3 bits
  deriving (Eq,Ord,Show,Data,Typeable)

data WireData = Fix4 Word32 
              | Fix8 Word32 -- 4 and 8 byte fixed length types, lsb first on wire
              | VarInt ByteString -- the 128 bit variable encoding (least significant first)
              | VarString ByteString -- length of contents as a VarInt
                          ByteString -- the contents on the wire
  deriving (Eq,Ord,Show,Data,Typeable)

newtype WireMessage = WireMessage (Map FieldId (Seq WireData))

instance Monoid WireMessage where
  mempty = WireMessage mempty
  mappend (WireMessage a) (WireMessage b) = WireMessage (unionWith mappend a b)

wireId :: WireData -> WireId
wireId  (Fix4 {}) = WireId 5
wireId  (Fix8 {}) = WireId 1
wireId  (VarInt {}) = WireId 0
wireId  (VarString {}) = WireId 2

composeFieldWire :: FieldId -> WireId -> Word32
composeFieldWire (FieldId f) (WireId w) = (f `shiftL` 3) .|. w

decomposeFieldWire :: Word32 -> (FieldId,WireId)
decomposeFieldWire x = (FieldId (x `shiftR` 3), WireId (x .&. 7))

encodeWireMessage :: WireMessage -> ByteString
encodeWireMessage = undefined

decodeWireMessage :: ByteString -> WireMessage
decodeWireMessage = undefined