module System.IO.Uniform.ByteString (
ByteStringIO,
withByteStringIO, withByteStringIO'
) where
import System.IO.Uniform
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import qualified Data.ByteString.Builder as BSBuild
import System.IO.Error
import Control.Concurrent.MVar
data ByteStringIO = ByteStringIO {bsioinput :: MVar (ByteString, Bool), bsiooutput :: MVar BSBuild.Builder}
instance UniformIO ByteStringIO where
uRead s n = do
(i, eof) <- takeMVar . bsioinput $ s
if eof
then do
putMVar (bsioinput s) (i, eof)
ioError $ mkIOError eofErrorType "read past end of input" Nothing Nothing
else do
let (r, i') = BS.splitAt n i
let eof' = BS.null r && n > 0
putMVar (bsioinput s) (i', eof')
return r
uPut s t = do
o <- takeMVar . bsiooutput $ s
let o' = mappend o $ BSBuild.byteString t
putMVar (bsiooutput s) o'
uClose _ = return ()
startTls _ = return
isSecure _ = True
withByteStringIO' :: ByteString -> (ByteStringIO -> IO a) -> IO (a, LBS.ByteString)
withByteStringIO' input f = do
ivar <- newMVar (input, False)
ovar <- newMVar . BSBuild.byteString $ BS.empty
let bsio = ByteStringIO ivar ovar
a <- f bsio
out <- takeMVar . bsiooutput $ bsio
return (a, BSBuild.toLazyByteString out)
withByteStringIO :: ByteString -> (ByteStringIO -> IO a) -> IO (a, ByteString)
withByteStringIO input f = do
(a, t) <- withByteStringIO' input f
return (a, LBS.toStrict t)