module Text.ProtocolBuffers.Unknown
( UnknownField(..),UnknownMessage(..),UnknownFieldValue(..)
, wireSizeUnknownField,wirePutUnknownField,catch'Unknown
) where
import qualified Data.ByteString.Lazy as L
import qualified Data.Foldable as F
import Data.Generics
import Data.Monoid(mempty,mappend)
import Data.Sequence((|>))
import Data.Typeable()
import Control.Monad.Error.Class(catchError)
import Text.ProtocolBuffers.Basic
import Text.ProtocolBuffers.WireMessage
class UnknownMessage msg where
getUnknownField :: msg -> UnknownField
putUnknownField :: UnknownField -> msg -> msg
newtype UnknownField = UnknownField (Seq UnknownFieldValue)
deriving (Eq,Ord,Show,Read,Data,Typeable)
data UnknownFieldValue = UFV !WireTag !ByteString
deriving (Eq,Ord,Show,Read,Data,Typeable)
instance Mergeable UnknownField where
mergeAppend (UnknownField m1) (UnknownField m2) = UnknownField (mappend m1 m2)
instance Default UnknownField where
defaultValue = UnknownField mempty
wireSizeUnknownField :: UnknownField -> WireSize
wireSizeUnknownField (UnknownField m) = F.foldl' aSize 0 m where
aSize old (UFV tag bs) = old + size'WireTag tag + L.length bs
wirePutUnknownField :: UnknownField -> Put
wirePutUnknownField (UnknownField m) = F.mapM_ aPut m where
aPut (UFV tag bs) = putVarUInt (getWireTag tag) >> putLazyByteString bs
catch'Unknown :: (Typeable a, UnknownMessage a) => (WireTag -> a -> Get a) -> (WireTag -> a -> Get a)
catch'Unknown update'Self = \wire'Tag old'Self -> catchError (update'Self wire'Tag old'Self) (\_ -> loadUnknown wire'Tag old'Self)
where loadUnknown :: (Typeable a, UnknownMessage a) => WireTag -> a -> Get a
loadUnknown tag msg = do
let (fieldId,wireType) = splitWireTag tag
(UnknownField uf) = getUnknownField msg
bs <- wireGetFromWire fieldId wireType
let v' = seq bs $ UFV tag bs
uf' = seq v' $ uf |> v'
seq uf' $ return $ putUnknownField (UnknownField uf') msg