Hufflepdf/src/PDF/Output.hs

77 lines
1.8 KiB
Haskell

module PDF.Output (
OBuilder(..)
, Output(..)
, byteString
, char
, join
, lift
, newLine
, nextLine
, string
, render
) where
import Data.ByteString.Builder (Builder, char8, lazyByteString, string8, toLazyByteString)
import Data.ByteString.Lazy.Char8 (ByteString)
import Data.String (IsString(..))
import Control.Monad.Reader (MonadReader(..), Reader, runReader)
import qualified PDF.EOL as EOL (Style(..))
newtype OBuilder = OBuilder (Reader EOL.Style Builder)
lift :: (a -> Builder) -> a -> OBuilder
lift f a = OBuilder $ return (f a)
instance Monoid OBuilder where
mempty = OBuilder (return mempty)
mappend (OBuilder a) (OBuilder b) = OBuilder (mappend <$> a <*> b)
instance IsString OBuilder where
fromString = string
class Output a where
output :: a -> OBuilder
instance Output OBuilder where
output = id
instance Output Bool where
output False = string "false"
output True = string "true"
instance Output Float where
output = string . show
instance Output a => Output [a] where
output = foldl mappend mempty . fmap output
join :: Output a => String -> [a] -> OBuilder
join _ [] = mempty
join _ [a] = output a
join separator (a:as) =
output a `mappend` string separator `mappend` (join separator as)
newLine :: OBuilder
newLine = OBuilder $ buildEOL <$> ask
where
buildEOL EOL.CR = char8 '\r'
buildEOL EOL.LF = char8 '\n'
buildEOL EOL.CRLF = string8 "\r\n"
nextLine :: OBuilder -> OBuilder -> OBuilder
nextLine a b = a `mappend` newLine `mappend` b
char :: Char -> OBuilder
char = lift char8
string :: String -> OBuilder
string = lift string8
byteString :: ByteString -> OBuilder
byteString = lift lazyByteString
render :: Output a => EOL.Style -> a -> ByteString
render eolStyle a =
let OBuilder r = output a in
toLazyByteString $ runReader r eolStyle