Blame Network/BufferType.hs

Packit acf257
{-# LANGUAGE TypeSynonymInstances #-}
Packit acf257
-----------------------------------------------------------------------------
Packit acf257
-- |
Packit acf257
-- Module      :  Network.BufferType
Packit acf257
-- Description :  Abstract representation of request and response buffer types.
Packit acf257
-- Copyright   :  See LICENSE file
Packit acf257
-- License     :  BSD
Packit acf257
--
Packit acf257
-- Maintainer  :  Ganesh Sittampalam <ganesh@earth.li>
Packit acf257
-- Stability   :  experimental
Packit acf257
-- Portability :  non-portable (not tested)
Packit acf257
--
Packit acf257
-- In order to give the user freedom in how request and response content
Packit acf257
-- is represented, a sufficiently abstract representation is needed of
Packit acf257
-- these internally. The "Network.BufferType" module provides this, defining
Packit acf257
-- the 'BufferType' class and its ad-hoc representation of buffer operations
Packit acf257
-- via the 'BufferOp' record.
Packit acf257
--
Packit acf257
-- This module provides definitions for the standard buffer types that the
Packit acf257
-- package supports, i.e., for @String@ and @ByteString@ (strict and lazy.)
Packit acf257
-- 
Packit acf257
-----------------------------------------------------------------------------
Packit acf257
module Network.BufferType
Packit acf257
       ( 
Packit acf257
         BufferType(..)
Packit acf257
Packit acf257
       , BufferOp(..)
Packit acf257
       , strictBufferOp
Packit acf257
       , lazyBufferOp
Packit acf257
       , stringBufferOp
Packit acf257
       ) where
Packit acf257
Packit acf257
Packit acf257
import qualified Data.ByteString       as Strict hiding ( unpack, pack, span )
Packit acf257
import qualified Data.ByteString.Char8 as Strict ( unpack, pack, span )
Packit acf257
import qualified Data.ByteString.Lazy as Lazy hiding ( pack, unpack,span )
Packit acf257
import qualified Data.ByteString.Lazy.Char8 as Lazy ( pack, unpack, span )
Packit acf257
import System.IO ( Handle )
Packit acf257
import Data.Word ( Word8 )
Packit acf257
Packit acf257
import Network.HTTP.Utils ( crlf, lf )
Packit acf257
Packit acf257
-- | The @BufferType@ class encodes, in a mixed-mode way, the interface
Packit acf257
-- that the library requires to operate over data embedded in HTTP
Packit acf257
-- requests and responses. That is, we use explicit dictionaries
Packit acf257
-- for the operations, but overload the name of the dicts themselves.
Packit acf257
-- 
Packit acf257
class BufferType bufType where
Packit acf257
   bufferOps :: BufferOp bufType
Packit acf257
Packit acf257
instance BufferType Lazy.ByteString where
Packit acf257
   bufferOps = lazyBufferOp
Packit acf257
Packit acf257
instance BufferType Strict.ByteString where
Packit acf257
   bufferOps = strictBufferOp
Packit acf257
Packit acf257
instance BufferType String where
Packit acf257
   bufferOps = stringBufferOp
Packit acf257
Packit acf257
-- | @BufferOp@ encodes the I/O operations of the underlying buffer over 
Packit acf257
-- a Handle in an (explicit) dictionary type. May not be needed, but gives
Packit acf257
-- us flexibility in explicit overriding and wrapping up of these methods.
Packit acf257
--
Packit acf257
-- Along with IO operations is an ad-hoc collection of functions for working
Packit acf257
-- with these abstract buffers, as needed by the internals of the code
Packit acf257
-- that processes requests and responses.
Packit acf257
--
Packit acf257
-- We supply three default @BufferOp@ values, for @String@ along with the
Packit acf257
-- strict and lazy versions of @ByteString@. To add others, provide @BufferOp@
Packit acf257
-- definitions for 
Packit acf257
data BufferOp a
Packit acf257
 = BufferOp
Packit acf257
     { buf_hGet         :: Handle -> Int -> IO a
Packit acf257
     , buf_hGetContents :: Handle -> IO a
Packit acf257
     , buf_hPut         :: Handle -> a   -> IO ()
Packit acf257
     , buf_hGetLine     :: Handle -> IO a
Packit acf257
     , buf_empty        :: a
Packit acf257
     , buf_append       :: a -> a -> a
Packit acf257
     , buf_concat       :: [a] -> a
Packit acf257
     , buf_fromStr      :: String -> a
Packit acf257
     , buf_toStr        :: a -> String
Packit acf257
     , buf_snoc         :: a -> Word8 -> a
Packit acf257
     , buf_splitAt      :: Int -> a -> (a,a)
Packit acf257
     , buf_span         :: (Char  -> Bool) -> a -> (a,a)
Packit acf257
     , buf_isLineTerm   :: a -> Bool
Packit acf257
     , buf_isEmpty      :: a -> Bool
Packit acf257
     }
Packit acf257
Packit acf257
instance Eq (BufferOp a) where
Packit acf257
  _ == _ = False
Packit acf257
Packit acf257
-- | @strictBufferOp@ is the 'BufferOp' definition over @ByteString@s,
Packit acf257
-- the non-lazy kind.
Packit acf257
strictBufferOp :: BufferOp Strict.ByteString
Packit acf257
strictBufferOp = 
Packit acf257
    BufferOp 
Packit acf257
      { buf_hGet         = Strict.hGet
Packit acf257
      , buf_hGetContents = Strict.hGetContents
Packit acf257
      , buf_hPut         = Strict.hPut
Packit acf257
      , buf_hGetLine     = Strict.hGetLine
Packit acf257
      , buf_append       = Strict.append
Packit acf257
      , buf_concat       = Strict.concat
Packit acf257
      , buf_fromStr      = Strict.pack
Packit acf257
      , buf_toStr        = Strict.unpack
Packit acf257
      , buf_snoc         = Strict.snoc
Packit acf257
      , buf_splitAt      = Strict.splitAt
Packit acf257
      , buf_span         = Strict.span
Packit acf257
      , buf_empty        = Strict.empty
Packit acf257
      , buf_isLineTerm   = \ b -> Strict.length b == 2 && p_crlf == b ||
Packit acf257
                                  Strict.length b == 1 && p_lf   == b
Packit acf257
      , buf_isEmpty      = Strict.null 
Packit acf257
      }
Packit acf257
   where
Packit acf257
    p_crlf = Strict.pack crlf
Packit acf257
    p_lf   = Strict.pack lf
Packit acf257
Packit acf257
-- | @lazyBufferOp@ is the 'BufferOp' definition over @ByteString@s,
Packit acf257
-- the non-strict kind.
Packit acf257
lazyBufferOp :: BufferOp Lazy.ByteString
Packit acf257
lazyBufferOp = 
Packit acf257
    BufferOp 
Packit acf257
      { buf_hGet         = Lazy.hGet
Packit acf257
      , buf_hGetContents = Lazy.hGetContents
Packit acf257
      , buf_hPut         = Lazy.hPut
Packit acf257
      , buf_hGetLine     = \ h -> Strict.hGetLine h >>= \ l -> return (Lazy.fromChunks [l])
Packit acf257
      , buf_append       = Lazy.append
Packit acf257
      , buf_concat       = Lazy.concat
Packit acf257
      , buf_fromStr      = Lazy.pack
Packit acf257
      , buf_toStr        = Lazy.unpack
Packit acf257
      , buf_snoc         = Lazy.snoc
Packit acf257
      , buf_splitAt      = \ i x -> Lazy.splitAt (fromIntegral i) x
Packit acf257
      , buf_span         = Lazy.span
Packit acf257
      , buf_empty        = Lazy.empty
Packit acf257
      , buf_isLineTerm   = \ b -> Lazy.length b == 2 && p_crlf == b ||
Packit acf257
                                  Lazy.length b == 1 && p_lf   == b
Packit acf257
      , buf_isEmpty      = Lazy.null 
Packit acf257
      }
Packit acf257
   where
Packit acf257
    p_crlf = Lazy.pack crlf
Packit acf257
    p_lf   = Lazy.pack lf
Packit acf257
Packit acf257
-- | @stringBufferOp@ is the 'BufferOp' definition over @String@s.
Packit acf257
-- It is defined in terms of @strictBufferOp@ operations,
Packit acf257
-- unpacking/converting to @String@ when needed.
Packit acf257
stringBufferOp :: BufferOp String
Packit acf257
stringBufferOp =BufferOp 
Packit acf257
      { buf_hGet         = \ h n -> buf_hGet strictBufferOp h n >>= return . Strict.unpack
Packit acf257
      , buf_hGetContents = \ h -> buf_hGetContents strictBufferOp h >>= return . Strict.unpack
Packit acf257
      , buf_hPut         = \ h s -> buf_hPut strictBufferOp h (Strict.pack s)
Packit acf257
      , buf_hGetLine     = \ h   -> buf_hGetLine strictBufferOp h >>= return . Strict.unpack
Packit acf257
      , buf_append       = (++)
Packit acf257
      , buf_concat       = concat
Packit acf257
      , buf_fromStr      = id
Packit acf257
      , buf_toStr        = id
Packit acf257
      , buf_snoc         = \ a x -> a ++ [toEnum (fromIntegral x)]
Packit acf257
      , buf_splitAt      = splitAt
Packit acf257
      , buf_span         = \ p a -> 
Packit acf257
                             case Strict.span p (Strict.pack a) of
Packit acf257
                               (x,y) -> (Strict.unpack x, Strict.unpack y)
Packit acf257
      , buf_empty        = []
Packit acf257
      , buf_isLineTerm   = \ b -> b == crlf || b == lf
Packit acf257
      , buf_isEmpty      = null 
Packit acf257
      }
Packit acf257