{-# LANGUAGE FlexibleInstances #-} -- | Use 'X.Text' to send and receive messages. -- For this module, a message is a single line; -- the newline character acts as the end-of-message flag. module Network.NetSpec.Text ( -- * Receiving receive -- * Sending , (!) , send , broadcast -- * Re-exports , module I , module X , module IO ) where import System.IO as I (Handle) import Data.Text as X (Text, pack) import Control.Monad.IO.Class as IO (MonadIO, liftIO) import Data.Text.IO as T import Data.Foldable as F import System.IO (hFlush) infix 2 ! class CanSend h where -- | The staple for sending a message. -- @!@ is typeclassed so that you can -- 'send' or 'broadcast' using the same simple syntax. -- The @CanSend@ typeclass is not exposed. -- Instances of CanSend include 'I.Handle' -- and @Traversable t => t Handle@. -- -- @!@ produces an @IO@ action lifted into any 'IO.MonadIO', -- so can be used without the extra cruft of 'IO.liftIO' -- for most monad stacks. @!@ is declared as @infix 2@. -- -- Usage: -- -- > destination ! someText (!) :: MonadIO io => h -> Text -> io () instance CanSend Handle where (!) = send instance (Foldable f) => CanSend (f Handle) where (!) = broadcast -- | Send a 'X.Text' message to exactly one 'I.Handle'. send :: MonadIO io => Handle -> Text -> io () send h str = liftIO $ T.hPutStrLn h str >> hFlush h -- | Broadcast a 'X.Text' message to multiple 'I.Handle's. broadcast :: MonadIO io => Foldable f => f Handle -> Text -> io () broadcast hs str = F.mapM_ (! str) hs -- | Receive a 'X.Text' message from a 'I.Handle'. receive :: MonadIO io => Handle -> io Text receive = liftIO . T.hGetLine