{-# LANGUAGE DeriveGeneric, DeriveDataTypeable #-} module Data.Bond.Internal.Bonded where import Data.Bond.Marshal import Data.Bond.Proto import Data.Bond.Internal.MarshalUtils import {-# SOURCE #-} Data.Bond.Internal.Protocol import GHC.Generics (Generic) import Control.DeepSeq import Control.Exception import Data.Typeable import qualified Data.ByteString.Lazy as Lazy -- | BondedException is thrown when attempt to deserialize bonded field for comparison fails. -- To handle such cases in the pure code explicitly decode all bonded fields before comparing structures. data BondedException = BondedException String deriving (Show, Typeable) instance Exception BondedException -- | bonded\ value data Bonded a = BondedStream Lazy.ByteString -- ^ Marshalled stream | BondedObject a -- ^ Deserialized value deriving (Generic, Typeable) instance Show a => Show (Bonded a) where show BondedStream{} = "BondedStream" show (BondedObject v) = show v instance (BondStruct a, Eq a) => Eq (Bonded a) where a == b = let aobj = case getValue a of Left msg -> throw (BondedException msg) Right v -> v bobj = case getValue b of Left msg -> throw (BondedException msg) Right v -> v in aobj == bobj instance NFData a => NFData (Bonded a) -- | Extract value from 'Bonded' using compile-type schema getValue :: BondStruct a => Bonded a -> Either String a getValue (BondedObject a) = Right a getValue (BondedStream s) = bondUnmarshal s -- | Extract value from 'Bonded' using compile-type schema for other type. -- This may be useful for casting values to child structs. -- User is responsible for schema compatibility. castValue :: BondStruct b => Bonded a -> Either String b castValue (BondedObject _) = error "can't cast deserialized struct" castValue (BondedStream s) = bondUnmarshal s -- | Put struct to the bonded\ field. putValue :: a -> Bonded a putValue = BondedObject -- | Marshal struct to the bonded\ field. -- There is no checks for schema compatibility, caveat emptor. marshalValue :: (BondProto t, BondStruct a) => t -> a -> Either String (Bonded b) marshalValue t = fmap BondedStream . bondMarshal' t