module Language.Erlang.ControlMessage ( ControlMessage(..)
, putControlMessage
, getControlMessage
)
where
import Prelude hiding (length)
import Data.Binary
import Data.Binary.Get
import Util.Binary
import Language.Erlang.Term
data ControlMessage = LINK Term Term
| SEND Term Term
| EXIT Term Term Term
| UNLINK Term Term
| NODE_LINK
| REG_SEND Term Term Term
| GROUP_LEADER Term Term
| EXIT2 Term Term Term
deriving (Eq, Show)
pass_through :: Word8
pass_through = 112
linkTag, sendTag, exitTag, unlinkTag, nodeLinkTag, regSendTag, groupLeaderTag, exit2Tag :: Term
linkTag = integer 1
sendTag = integer 2
exitTag = integer 3
unlinkTag = integer 4
nodeLinkTag = integer 5
regSendTag = integer 6
groupLeaderTag = integer 7
exit2Tag = integer 8
unused :: Term
unused = atom ""
instance Binary ControlMessage where
put (LINK fromPid toPid) = do
putTerm $ tuple [linkTag, fromPid, toPid]
put (SEND toPid message) = do
putTerm $ tuple [sendTag, toPid]
putTerm message
put (EXIT fromPid toPid reason) = do
putTerm $ tuple [exitTag, fromPid, toPid, reason]
put (UNLINK fromPid toPid) = do
putTerm $ tuple [unlinkTag, fromPid, toPid]
put NODE_LINK = do
putTerm $ tuple [nodeLinkTag]
put (REG_SEND fromPid toName message) = do
putTerm $ tuple [regSendTag, fromPid, unused, toName]
putTerm message
put (GROUP_LEADER fromPid toPid) = do
putTerm $ tuple [groupLeaderTag, fromPid, toPid]
put (EXIT2 fromPid toPid reason) = do
putTerm $ tuple [exit2Tag, fromPid, toPid, reason]
get = do
term <- getTerm
if is_tuple term
then do get' term
else do fail $ "Bad control message: " ++ show term
where
get' term
| length term == 3 && element 1 term == linkTag = do
return (LINK (element 2 term) (element 3 term))
| length term == 3 && element 1 term == sendTag = do
message <- getTerm
return (SEND (element 3 term) message)
| length term == 4 && element 1 term == exitTag = do
return (EXIT (element 2 term) (element 3 term) (element 4 term))
| length term == 3 && element 1 term == unlinkTag = do
return (UNLINK (element 2 term) (element 3 term))
| length term == 1 && element 1 term == nodeLinkTag = do
return NODE_LINK
| length term == 4 && element 1 term == regSendTag = do
message <- getTerm
return (REG_SEND (element 2 term) (element 4 term) message)
| length term == 3 && element 1 term == groupLeaderTag = do
return (GROUP_LEADER (element 2 term) (element 3 term))
| length term == 4 && element 1 term == exit2Tag = do
return (EXIT2 (element 2 term) (element 3 term) (element 4 term))
| otherwise = do fail $ "Bad control message: " ++ show term
putControlMessage :: ControlMessage -> Put
putControlMessage controlMessage = do
putWithLength32be $ do
putWord8 pass_through
put controlMessage
getControlMessage :: Get ControlMessage
getControlMessage = do
expectedLen <- getWord32be
pos0 <- bytesRead
matchWord8 pass_through
controlMessage <- get
pos1 <- bytesRead
let actualLen = pos1 pos0
if (fromIntegral expectedLen) == actualLen
then do return controlMessage
else do fail "Bad control message length"