    {-# LANGUAGE BangPatterns, CPP, DeriveFunctor, ScopedTypeVariables #-}

    -- | This module allows for incremental decoding and encoding of CSV
    -- data. This is useful if you e.g. want to interleave I\/O with
    -- parsing or if you want finer grained control over how you deal with
    -- type conversion errors.
    --
    -- Decoding example:
    --
    -- > main :: IO ()
    -- > main = withFile "salaries.csv" ReadMode $ \ csvFile -> do
    -- >     let loop !_ (Fail _ errMsg) = putStrLn errMsg >> exitFailure
    -- >         loop acc (Many rs k)    = loop (acc + sumSalaries rs) =<< feed k
    -- >         loop acc (Done rs)      = putStrLn $ "Total salaries: " ++
    -- >                                   show (sumSalaries rs + acc)
    -- >
    -- >         feed k = do
    -- >             isEof <- hIsEOF csvFile
    -- >             if isEof
    -- >                 then return $ k B.empty
    -- >                 else k `fmap` B.hGetSome csvFile 4096
    -- >     loop 0 (decode NoHeader)
    -- >   where
    -- >     sumSalaries rs = sum [salary | Right (_ :: String, salary :: Int) <- rs]
    --
    -- Encoding example:
    --
    -- > data Person = Person { name   :: !String, salary :: !Int }
    -- >     deriving Generic
    -- >
    -- > instance FromNamedRecord Person
    -- > instance ToNamedRecord Person
    -- > instance DefaultOrdered Person
    -- >
    -- > persons :: [Person]
    -- > persons = [Person "John" 50000, Person "Jane" 60000]
    -- >
    -- > main :: IO ()
    -- > main = putStrLn $ encodeDefaultOrderedByName (go persons)
    -- >   where
    -- >     go (x:xs) = encodeNamedRecord x <> go xs
    --
    module Data.Csv.Incremental
        (
        -- * Decoding
          HeaderParser(..)
        , decodeHeader
        , decodeHeaderWith

        -- $typeconversion
        , Parser(..)

        -- ** Index-based record conversion
        -- $indexbased
        , HasHeader(..)
        , decode
        , decodeWith
        , decodeWithP

        -- ** Name-based record conversion
        -- $namebased
        , decodeByName
        , decodeByNameWith
        , decodeByNameWithP

        -- * Encoding
        -- ** Index-based record conversion
        -- $indexbased
        , encode
        , encodeWith
        , encodeRecord
        , Builder

        -- ** Name-based record conversion
        -- $namebased
        , encodeByName
        , encodeDefaultOrderedByName
        , encodeByNameWith
        , encodeDefaultOrderedByNameWith
        , encodeNamedRecord
        , NamedBuilder
        ) where

    import Control.Applicative ((<|>))
    import qualified Data.Attoparsec.ByteString as A
    import Data.Attoparsec.ByteString.Char8 (endOfInput)
    import qualified Data.ByteString as B
    import qualified Data.ByteString.Builder as Builder
    import qualified Data.ByteString.Lazy as L
    import Data.Semigroup as Semi (Semigroup, (<>))
    import qualified Data.Vector as V
    import Data.Word (Word8)

    import Data.Csv.Conversion hiding (Parser, header, namedRecord, record,
                                       toNamedRecord)
    import qualified Data.Csv.Conversion as Conversion
    import qualified Data.Csv.Encoding as Encoding
    import Data.Csv.Encoding (EncodeOptions(..), Quoting(..), recordSep)
    import Data.Csv.Parser
    import Data.Csv.Types
    import Data.Csv.Util (endOfLine)

    #if !MIN_VERSION_base(4,8,0)
    import Data.Monoid (Monoid(mappend, mempty))
    import Control.Applicative ((<*))
    #endif

    -- $feed-header
    --
    -- These functions are sometimes convenient when working with
    -- 'HeaderParser', but don't let you do anything you couldn't already
    -- do using the 'HeaderParser' constructors directly.

    -- $indexbased
    --
    -- See documentation on index-based conversion in "Data.Csv" for more
    -- information.

    -- $namebased
    --
    -- See documentation on name-based conversion in "Data.Csv" for more
    -- information.

    -- $feed-records
    --
    -- These functions are sometimes convenient when working with
    -- 'Parser', but don't let you do anything you couldn't already do
    -- using the 'Parser' constructors directly.

    ------------------------------------------------------------------------
    -- * Decoding headers

    -- | An incremental parser that when fed data eventually returns a
    -- parsed 'Header', or an error.
    data HeaderParser a =
          -- | The input data was malformed. The first field contains any
          -- unconsumed input and second field contains information about
          -- the parse error.
          FailH !B.ByteString String

          -- | The parser needs more input data before it can produce a
          -- result. Use an 'B.empty' string to indicate that no more
          -- input data is available. If fed an 'B.empty string', the
          -- continuation is guaranteed to return either 'FailH' or
          -- 'DoneH'.
        | PartialH (B.ByteString -> HeaderParser a)

          -- | The parse succeeded and produced the given 'Header'.
        | DoneH !Header a
        deriving a -> HeaderParser b -> HeaderParser a
    (a -> b) -> HeaderParser a -> HeaderParser b
    (forall a b. (a -> b) -> HeaderParser a -> HeaderParser b)
    -> (forall a b. a -> HeaderParser b -> HeaderParser a)
    -> Functor HeaderParser
    forall a b. a -> HeaderParser b -> HeaderParser a
    forall a b. (a -> b) -> HeaderParser a -> HeaderParser b
    forall (f :: * -> *).
    (forall a b. (a -> b) -> f a -> f b)
    -> (forall a b. a -> f b -> f a) -> Functor f
    <$ :: a -> HeaderParser b -> HeaderParser a
    $c<$ :: forall a b. a -> HeaderParser b -> HeaderParser a
    fmap :: (a -> b) -> HeaderParser a -> HeaderParser b
    $cfmap :: forall a b. (a -> b) -> HeaderParser a -> HeaderParser b
    Functor

    instance Show a => Show (HeaderParser a) where
        showsPrec :: Int -> HeaderParser a -> ShowS
    showsPrec d :: Int
    d (FailH rest :: ByteString
    rest msg :: String
    msg) = Bool -> ShowS -> ShowS
    showParen (Int
    d Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    appPrec) ShowS
    showStr
          where
            showStr :: ShowS
    showStr = String -> ShowS
    showString "FailH " ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> ByteString -> ShowS
    forall a. Show a => Int -> a -> ShowS
    showsPrec (Int
    appPrecInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +1) ByteString
    rest ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                      String -> ShowS
    showString " " ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> String -> ShowS
    forall a. Show a => Int -> a -> ShowS
    showsPrec (Int
    appPrecInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +1) String
    msg
        showsPrec _ (PartialH _) = String -> ShowS
    showString "PartialH <function>"
        showsPrec d :: Int
    d (DoneH hdr :: Header
    hdr x :: a
    x) = Bool -> ShowS -> ShowS
    showParen (Int
    d Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    appPrec) ShowS
    showStr
          where
            showStr :: ShowS
    showStr = String -> ShowS
    showString "DoneH " ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> Header -> ShowS
    forall a. Show a => Int -> a -> ShowS
    showsPrec (Int
    appPrecInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +1) Header
    hdr ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                      String -> ShowS
    showString " " ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> a -> ShowS
    forall a. Show a => Int -> a -> ShowS
    showsPrec (Int
    appPrecInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +1) a
    x

    -- Application has precedence one more than the most tightly-binding
    -- operator
    appPrec :: Int
    appPrec :: Int
    appPrec = 10

    -- | Parse a CSV header in an incremental fashion. When done, the
    -- 'HeaderParser' returns any unconsumed input in the second field of
    -- the 'DoneH' constructor.
    decodeHeader :: HeaderParser B.ByteString
    decodeHeader :: HeaderParser ByteString
    decodeHeader = DecodeOptions -> HeaderParser ByteString
    decodeHeaderWith DecodeOptions
    defaultDecodeOptions

    -- | Like 'decodeHeader', but lets you customize how the CSV data is
    -- parsed.
    decodeHeaderWith :: DecodeOptions -> HeaderParser B.ByteString
    decodeHeaderWith :: DecodeOptions -> HeaderParser ByteString
    decodeHeaderWith !DecodeOptions
    opts = (ByteString -> HeaderParser ByteString) -> HeaderParser ByteString
    forall a. (ByteString -> HeaderParser a) -> HeaderParser a
    PartialH (IResult ByteString Header -> HeaderParser ByteString
    go (IResult ByteString Header -> HeaderParser ByteString)
    -> (ByteString -> IResult ByteString Header)
    -> ByteString
    -> HeaderParser ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> IResult ByteString Header
    parser)
      where
        parser :: ByteString -> IResult ByteString Header
    parser = Parser Header -> ByteString -> IResult ByteString Header
    forall a. Parser a -> ByteString -> Result a
    A.parse (Word8 -> Parser Header
    header (Word8 -> Parser Header) -> Word8 -> Parser Header
    forall a b. (a -> b) -> a -> b
    $ DecodeOptions -> Word8
    decDelimiter DecodeOptions
    opts)

        go :: IResult ByteString Header -> HeaderParser ByteString
    go (A.Fail rest :: ByteString
    rest _ msg :: String
    msg) = ByteString -> String -> HeaderParser ByteString
    forall a. ByteString -> String -> HeaderParser a
    FailH ByteString
    rest String
    err
          where err :: String
    err = "parse error (" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    msg String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ")"
        -- TODO: Check empty and give attoparsec one last chance to return
        -- something:
        go (A.Partial k :: ByteString -> IResult ByteString Header
    k)       = (ByteString -> HeaderParser ByteString) -> HeaderParser ByteString
    forall a. (ByteString -> HeaderParser a) -> HeaderParser a
    PartialH ((ByteString -> HeaderParser ByteString)
     -> HeaderParser ByteString)
    -> (ByteString -> HeaderParser ByteString)
    -> HeaderParser ByteString
    forall a b. (a -> b) -> a -> b
    $ \ s :: ByteString
    s -> IResult ByteString Header -> HeaderParser ByteString
    go (ByteString -> IResult ByteString Header
    k ByteString
    s)
        go (A.Done rest :: ByteString
    rest r :: Header
    r)     = Header -> ByteString -> HeaderParser ByteString
    forall a. Header -> a -> HeaderParser a
    DoneH Header
    r ByteString
    rest

    ------------------------------------------------------------------------
    -- * Decoding records

    -- $typeconversion
    --
    -- Just like in the case of non-incremental decoding, there are two
    -- ways to convert CSV records to and from and user-defined data
    -- types: index-based conversion and name-based conversion.

    -- | An incremental parser that when fed data eventually produces some
    -- parsed records, converted to the desired type, or an error in case
    -- of malformed input data.
    data Parser a =
          -- | The input data was malformed. The first field contains any
          -- unconsumed input and second field contains information about
          -- the parse error.
          Fail !B.ByteString String

          -- | The parser parsed and converted zero or more records. Any
          -- records that failed type conversion are returned as @'Left'
          -- errMsg@ and the rest as @'Right' val@. Feed a 'B.ByteString'
          -- to the continuation to continue parsing. Use an 'B.empty'
          -- string to indicate that no more input data is available. If
          -- fed an 'B.empty' string, the continuation is guaranteed to
          -- return either 'Fail' or 'Done'.
        | Many [Either String a] (B.ByteString -> Parser a)

          -- | The parser parsed and converted some records. Any records
          -- that failed type conversion are returned as @'Left' errMsg@
          -- and the rest as @'Right' val@.
        | Done [Either String a]
        deriving a -> Parser b -> Parser a
    (a -> b) -> Parser a -> Parser b
    (forall a b. (a -> b) -> Parser a -> Parser b)
    -> (forall a b. a -> Parser b -> Parser a) -> Functor Parser
    forall a b. a -> Parser b -> Parser a
    forall a b. (a -> b) -> Parser a -> Parser b
    forall (f :: * -> *).
    (forall a b. (a -> b) -> f a -> f b)
    -> (forall a b. a -> f b -> f a) -> Functor f
    <$ :: a -> Parser b -> Parser a
    $c<$ :: forall a b. a -> Parser b -> Parser a
    fmap :: (a -> b) -> Parser a -> Parser b
    $cfmap :: forall a b. (a -> b) -> Parser a -> Parser b
    Functor

    instance Show a => Show (Parser a) where
        showsPrec :: Int -> Parser a -> ShowS
    showsPrec d :: Int
    d (Fail rest :: ByteString
    rest msg :: String
    msg) = Bool -> ShowS -> ShowS
    showParen (Int
    d Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    appPrec) ShowS
    showStr
          where
            showStr :: ShowS
    showStr = String -> ShowS
    showString "Fail " ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> ByteString -> ShowS
    forall a. Show a => Int -> a -> ShowS
    showsPrec (Int
    appPrecInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +1) ByteString
    rest ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                      String -> ShowS
    showString " " ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> String -> ShowS
    forall a. Show a => Int -> a -> ShowS
    showsPrec (Int
    appPrecInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +1) String
    msg
        showsPrec d :: Int
    d (Many rs :: [Either String a]
    rs _) = Bool -> ShowS -> ShowS
    showParen (Int
    d Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    appPrec) ShowS
    showStr
          where
            showStr :: ShowS
    showStr = String -> ShowS
    showString "Many " ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> [Either String a] -> ShowS
    forall a. Show a => Int -> a -> ShowS
    showsPrec (Int
    appPrecInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +1) [Either String a]
    rs ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
                      String -> ShowS
    showString " <function>"
        showsPrec d :: Int
    d (Done rs :: [Either String a]
    rs) = Bool -> ShowS -> ShowS
    showParen (Int
    d Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    appPrec) ShowS
    showStr
          where
            showStr :: ShowS
    showStr = String -> ShowS
    showString "Done " ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> [Either String a] -> ShowS
    forall a. Show a => Int -> a -> ShowS
    showsPrec (Int
    appPrecInt -> Int -> Int
    forall a. Num a => a -> a -> a
    +1) [Either String a]
    rs

    -- | Have we read all available input?
    data More = Incomplete | Complete
              deriving (More -> More -> Bool
    (More -> More -> Bool) -> (More -> More -> Bool) -> Eq More
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: More -> More -> Bool
    $c/= :: More -> More -> Bool
    == :: More -> More -> Bool
    $c== :: More -> More -> Bool
    Eq, Int -> More -> ShowS
    [More] -> ShowS
    More -> String
    (Int -> More -> ShowS)
    -> (More -> String) -> ([More] -> ShowS) -> Show More
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [More] -> ShowS
    $cshowList :: [More] -> ShowS
    show :: More -> String
    $cshow :: More -> String
    showsPrec :: Int -> More -> ShowS
    $cshowsPrec :: Int -> More -> ShowS
    Show)

    -- | Efficiently deserialize CSV in an incremental fashion. Equivalent
    -- to @'decodeWith' 'defaultDecodeOptions'@.
    decode :: FromRecord a
           => HasHeader     -- ^ Data contains header that should be
                            -- skipped
           -> Parser a
    decode :: HasHeader -> Parser a
    decode = DecodeOptions -> HasHeader -> Parser a
    forall a. FromRecord a => DecodeOptions -> HasHeader -> Parser a
    decodeWith DecodeOptions
    defaultDecodeOptions

    -- | Like 'decode', but lets you customize how the CSV data is parsed.
    decodeWith :: FromRecord a
               => DecodeOptions  -- ^ Decoding options
               -> HasHeader      -- ^ Data contains header that should be
                                 -- skipped
               -> Parser a
    decodeWith :: DecodeOptions -> HasHeader -> Parser a
    decodeWith !DecodeOptions
    opts hasHeader :: HasHeader
    hasHeader = (Header -> Parser a) -> DecodeOptions -> HasHeader -> Parser a
    forall a.
    (Header -> Parser a) -> DecodeOptions -> HasHeader -> Parser a
    decodeWithP Header -> Parser a
    forall a. FromRecord a => Header -> Parser a
    parseRecord DecodeOptions
    opts HasHeader
    hasHeader

    -- | Like 'decodeWith', but lets you pass an explicit parser value instead of
    -- using a typeclass
    --
    -- @since 0.5.2.0
    decodeWithP :: (Record -> Conversion.Parser a)
                -> DecodeOptions  -- ^ Decoding options
                -> HasHeader      -- ^ Data contains header that should be
                                 -- skipped
                -> Parser a
    decodeWithP :: (Header -> Parser a) -> DecodeOptions -> HasHeader -> Parser a
    decodeWithP p :: Header -> Parser a
    p !DecodeOptions
    opts hasHeader :: HasHeader
    hasHeader = case HasHeader
    hasHeader of
        HasHeader -> HeaderParser ByteString -> Parser a
    go (DecodeOptions -> HeaderParser ByteString
    decodeHeaderWith DecodeOptions
    opts)
        NoHeader  -> [Either String a] -> (ByteString -> Parser a) -> Parser a
    forall a. [Either String a] -> (ByteString -> Parser a) -> Parser a
    Many [] ((ByteString -> Parser a) -> Parser a)
    -> (ByteString -> Parser a) -> Parser a
    forall a b. (a -> b) -> a -> b
    $ \ s :: ByteString
    s -> (Header -> Parser a) -> DecodeOptions -> ByteString -> Parser a
    forall a.
    (Header -> Parser a) -> DecodeOptions -> ByteString -> Parser a
    decodeWithP' Header -> Parser a
    p DecodeOptions
    opts ByteString
    s
      where go :: HeaderParser ByteString -> Parser a
    go (FailH rest :: ByteString
    rest msg :: String
    msg) = ByteString -> String -> Parser a
    forall a. ByteString -> String -> Parser a
    Fail ByteString
    rest String
    msg
            go (PartialH k :: ByteString -> HeaderParser ByteString
    k)     = [Either String a] -> (ByteString -> Parser a) -> Parser a
    forall a. [Either String a] -> (ByteString -> Parser a) -> Parser a
    Many [] ((ByteString -> Parser a) -> Parser a)
    -> (ByteString -> Parser a) -> Parser a
    forall a b. (a -> b) -> a -> b
    $ \ s' :: ByteString
    s' -> HeaderParser ByteString -> Parser a
    go (ByteString -> HeaderParser ByteString
    k ByteString
    s')
            go (DoneH _ rest :: ByteString
    rest)   = (Header -> Parser a) -> DecodeOptions -> ByteString -> Parser a
    forall a.
    (Header -> Parser a) -> DecodeOptions -> ByteString -> Parser a
    decodeWithP' Header -> Parser a
    p DecodeOptions
    opts ByteString
    rest

    ------------------------------------------------------------------------

    -- | Efficiently deserialize CSV in an incremental fashion. The data
    -- is assumed to be preceded by a header. Returns a 'HeaderParser'
    -- that when done produces a 'Parser' for parsing the actual records.
    -- Equivalent to @'decodeByNameWith' 'defaultDecodeOptions'@.
    decodeByName :: FromNamedRecord a
                 => HeaderParser (Parser a)
    decodeByName :: HeaderParser (Parser a)
    decodeByName = DecodeOptions -> HeaderParser (Parser a)
    forall a.
    FromNamedRecord a =>
    DecodeOptions -> HeaderParser (Parser a)
    decodeByNameWith DecodeOptions
    defaultDecodeOptions

    -- | Like 'decodeByName', but lets you customize how the CSV data is
    -- parsed.
    decodeByNameWith :: FromNamedRecord a
                     => DecodeOptions  -- ^ Decoding options
                     -> HeaderParser (Parser a)
    decodeByNameWith :: DecodeOptions -> HeaderParser (Parser a)
    decodeByNameWith !DecodeOptions
    opts = (NamedRecord -> Parser a)
    -> DecodeOptions -> HeaderParser (Parser a)
    forall a.
    (NamedRecord -> Parser a)
    -> DecodeOptions -> HeaderParser (Parser a)
    decodeByNameWithP NamedRecord -> Parser a
    forall a. FromNamedRecord a => NamedRecord -> Parser a
    parseNamedRecord DecodeOptions
    opts

    -- | Like 'decodeByNameWith', but lets you pass an explicit parser value instead
    -- of using a typeclass
    --
    -- @since 0.5.2.0
    decodeByNameWithP :: (NamedRecord -> Conversion.Parser a)
                      -> DecodeOptions  -- ^ Decoding options
                      -> HeaderParser (Parser a)
    decodeByNameWithP :: (NamedRecord -> Parser a)
    -> DecodeOptions -> HeaderParser (Parser a)
    decodeByNameWithP p :: NamedRecord -> Parser a
    p !DecodeOptions
    opts = HeaderParser ByteString -> HeaderParser (Parser a)
    go (DecodeOptions -> HeaderParser ByteString
    decodeHeaderWith DecodeOptions
    opts)
      where
        go :: HeaderParser ByteString -> HeaderParser (Parser a)
    go (FailH rest :: ByteString
    rest msg :: String
    msg) = ByteString -> String -> HeaderParser (Parser a)
    forall a. ByteString -> String -> HeaderParser a
    FailH ByteString
    rest String
    msg
        go (PartialH k :: ByteString -> HeaderParser ByteString
    k)     = (ByteString -> HeaderParser (Parser a)) -> HeaderParser (Parser a)
    forall a. (ByteString -> HeaderParser a) -> HeaderParser a
    PartialH ((ByteString -> HeaderParser (Parser a))
     -> HeaderParser (Parser a))
    -> (ByteString -> HeaderParser (Parser a))
    -> HeaderParser (Parser a)
    forall a b. (a -> b) -> a -> b
    $ \ s :: ByteString
    s -> HeaderParser ByteString -> HeaderParser (Parser a)
    go (ByteString -> HeaderParser ByteString
    k ByteString
    s)
        go (DoneH hdr :: Header
    hdr rest :: ByteString
    rest) =
            Header -> Parser a -> HeaderParser (Parser a)
    forall a. Header -> a -> HeaderParser a
    DoneH Header
    hdr ((Header -> Parser a) -> DecodeOptions -> ByteString -> Parser a
    forall a.
    (Header -> Parser a) -> DecodeOptions -> ByteString -> Parser a
    decodeWithP' (NamedRecord -> Parser a
    p (NamedRecord -> Parser a)
    -> (Header -> NamedRecord) -> Header -> Parser a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Header -> Header -> NamedRecord
    toNamedRecord Header
    hdr) DecodeOptions
    opts ByteString
    rest)

    ------------------------------------------------------------------------

    -- TODO: 'decodeWithP' should probably not take an initial
    -- 'B.ByteString' input.

    -- | Like 'decode', but lets you customize how the CSV data is parsed.
    decodeWithP' :: (Record -> Conversion.Parser a) -> DecodeOptions -> B.ByteString
                -> Parser a
    decodeWithP' :: (Header -> Parser a) -> DecodeOptions -> ByteString -> Parser a
    decodeWithP' p :: Header -> Parser a
    p !DecodeOptions
    opts = More -> [Either String a] -> IResult ByteString Header -> Parser a
    go More
    Incomplete [] (IResult ByteString Header -> Parser a)
    -> (ByteString -> IResult ByteString Header)
    -> ByteString
    -> Parser a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> IResult ByteString Header
    parser
      where
        go :: More -> [Either String a] -> IResult ByteString Header -> Parser a
    go !More
    _ ![Either String a]
    acc (A.Fail rest :: ByteString
    rest _ msg :: String
    msg)
            | [Either String a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [Either String a]
    acc  = ByteString -> String -> Parser a
    forall a. ByteString -> String -> Parser a
    Fail ByteString
    rest String
    err
            | Bool
    otherwise = [Either String a] -> (ByteString -> Parser a) -> Parser a
    forall a. [Either String a] -> (ByteString -> Parser a) -> Parser a
    Many ([Either String a] -> [Either String a]
    forall a. [a] -> [a]
    reverse [Either String a]
    acc) (\ s :: ByteString
    s -> ByteString -> String -> Parser a
    forall a. ByteString -> String -> Parser a
    Fail (ByteString
    rest ByteString -> ByteString -> ByteString
    `B.append` ByteString
    s) String
    err)
          where err :: String
    err = "parse error (" String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    msg String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ")"
        go Incomplete acc :: [Either String a]
    acc (A.Partial k :: ByteString -> IResult ByteString Header
    k) = [Either String a] -> (ByteString -> Parser a) -> Parser a
    forall a. [Either String a] -> (ByteString -> Parser a) -> Parser a
    Many ([Either String a] -> [Either String a]
    forall a. [a] -> [a]
    reverse [Either String a]
    acc) ByteString -> Parser a
    cont
          where cont :: ByteString -> Parser a
    cont s :: ByteString
    s = More -> [Either String a] -> IResult ByteString Header -> Parser a
    go More
    m [] (ByteString -> IResult ByteString Header
    k ByteString
    s)
                  where m :: More
    m | ByteString -> Bool
    B.null ByteString
    s  = More
    Complete
                          | Bool
    otherwise = More
    Incomplete
        go Complete _ (A.Partial _) = String -> String -> Parser a
    forall a. String -> String -> a
    moduleError "decodeWithP'" String
    msg
            where msg :: String
    msg = "attoparsec should never return Partial in this case"
        go m :: More
    m acc :: [Either String a]
    acc (A.Done rest :: ByteString
    rest r :: Header
    r)
            | ByteString -> Bool
    B.null ByteString
    rest = case More
    m of
                Complete   -> [Either String a] -> Parser a
    forall a. [Either String a] -> Parser a
    Done ([Either String a] -> [Either String a]
    forall a. [a] -> [a]
    reverse [Either String a]
    acc')
                Incomplete -> [Either String a] -> (ByteString -> Parser a) -> Parser a
    forall a. [Either String a] -> (ByteString -> Parser a) -> Parser a
    Many ([Either String a] -> [Either String a]
    forall a. [a] -> [a]
    reverse [Either String a]
    acc') ([Either String a] -> ByteString -> Parser a
    cont [])
            | Bool
    otherwise   = More -> [Either String a] -> IResult ByteString Header -> Parser a
    go More
    m [Either String a]
    acc' (ByteString -> IResult ByteString Header
    parser ByteString
    rest)
          where cont :: [Either String a] -> ByteString -> Parser a
    cont acc'' :: [Either String a]
    acc'' s :: ByteString
    s
                    | ByteString -> Bool
    B.null ByteString
    s  = [Either String a] -> Parser a
    forall a. [Either String a] -> Parser a
    Done ([Either String a] -> [Either String a]
    forall a. [a] -> [a]
    reverse [Either String a]
    acc'')
                    | Bool
    otherwise = More -> [Either String a] -> IResult ByteString Header -> Parser a
    go More
    Incomplete [Either String a]
    acc'' (ByteString -> IResult ByteString Header
    parser ByteString
    s)
                acc' :: [Either String a]
    acc' | Header -> Bool
    blankLine Header
    r = [Either String a]
    acc
                     | Bool
    otherwise   = let !r' :: Either String a
    r' = Header -> Either String a
    convert Header
    r in Either String a
    r' Either String a -> [Either String a] -> [Either String a]
    forall a. a -> [a] -> [a]
    : [Either String a]
    acc

        parser :: ByteString -> IResult ByteString Header
    parser = Parser Header -> ByteString -> IResult ByteString Header
    forall a. Parser a -> ByteString -> Result a
    A.parse (Word8 -> Parser Header
    record (DecodeOptions -> Word8
    decDelimiter DecodeOptions
    opts) Parser Header -> Parser ByteString () -> Parser Header
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
    <* (Parser ByteString ()
    endOfLine Parser ByteString ()
    -> Parser ByteString () -> Parser ByteString ()
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> Parser ByteString ()
    forall t. Chunk t => Parser t ()
    endOfInput))
        convert :: Header -> Either String a
    convert = Parser a -> Either String a
    forall a. Parser a -> Either String a
    runParser (Parser a -> Either String a)
    -> (Header -> Parser a) -> Header -> Either String a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Header -> Parser a
    p
    {-# INLINE decodeWithP' #-}

    blankLine :: V.Vector B.ByteString -> Bool
    blankLine :: Header -> Bool
    blankLine v :: Header
    v = Header -> Int
    forall a. Vector a -> Int
    V.length Header
    v Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == 1 Bool -> Bool -> Bool
    && (ByteString -> Bool
    B.null (Header -> ByteString
    forall a. Vector a -> a
    V.head Header
    v))

    ------------------------------------------------------------------------
    -- * Encoding

    -- | Efficiently serialize records in an incremental
    -- fashion. Equivalent to @'encodeWith' 'defaultEncodeOptions'@.
    encode :: ToRecord a => Builder a -> L.ByteString
    encode :: Builder a -> ByteString
    encode = EncodeOptions -> Builder a -> ByteString
    forall a. ToRecord a => EncodeOptions -> Builder a -> ByteString
    encodeWith EncodeOptions
    Encoding.defaultEncodeOptions

    -- | Like 'encode', but lets you customize how the CSV data is
    -- encoded.
    encodeWith :: ToRecord a => EncodeOptions -> Builder a
                     -> L.ByteString
    encodeWith :: EncodeOptions -> Builder a -> ByteString
    encodeWith opts :: EncodeOptions
    opts b :: Builder a
    b =
        Builder -> ByteString
    Builder.toLazyByteString (Builder -> ByteString) -> Builder -> ByteString
    forall a b. (a -> b) -> a -> b
    $
        Builder a -> Quoting -> Word8 -> Bool -> Builder
    forall a. Builder a -> Quoting -> Word8 -> Bool -> Builder
    runBuilder Builder a
    b (EncodeOptions -> Quoting
    encQuoting EncodeOptions
    opts) (EncodeOptions -> Word8
    encDelimiter EncodeOptions
    opts) (EncodeOptions -> Bool
    encUseCrLf EncodeOptions
    opts)

    -- | Encode a single record.
    encodeRecord :: ToRecord a => a -> Builder a
    encodeRecord :: a -> Builder a
    encodeRecord r :: a
    r = (Quoting -> Word8 -> Bool -> Builder) -> Builder a
    forall a. (Quoting -> Word8 -> Bool -> Builder) -> Builder a
    Builder ((Quoting -> Word8 -> Bool -> Builder) -> Builder a)
    -> (Quoting -> Word8 -> Bool -> Builder) -> Builder a
    forall a b. (a -> b) -> a -> b
    $ \ qtng :: Quoting
    qtng delim :: Word8
    delim useCrLf :: Bool
    useCrLf ->
        Quoting -> Word8 -> Header -> Builder
    Encoding.encodeRecord Quoting
    qtng Word8
    delim (a -> Header
    forall a. ToRecord a => a -> Header
    toRecord a
    r) Builder -> Builder -> Builder
    forall a. Semigroup a => a -> a -> a
    <> Bool -> Builder
    recordSep Bool
    useCrLf

    -- | A builder for building the CSV data incrementally. Just like the
    -- @ByteString@ builder, this builder should be used in a
    -- right-associative, 'foldr' style. Using '<>' to compose builders in
    -- a left-associative, `foldl'` style makes the building not be
    -- incremental.
    newtype Builder a = Builder {
          Builder a -> Quoting -> Word8 -> Bool -> Builder
    runBuilder :: Quoting -> Word8 -> Bool -> Builder.Builder
        }

    -- | @since 0.5.0.0
    instance Semi.Semigroup (Builder a) where
        Builder f :: Quoting -> Word8 -> Bool -> Builder
    f <> :: Builder a -> Builder a -> Builder a
    <> Builder g :: Quoting -> Word8 -> Bool -> Builder
    g =
            (Quoting -> Word8 -> Bool -> Builder) -> Builder a
    forall a. (Quoting -> Word8 -> Bool -> Builder) -> Builder a
    Builder ((Quoting -> Word8 -> Bool -> Builder) -> Builder a)
    -> (Quoting -> Word8 -> Bool -> Builder) -> Builder a
    forall a b. (a -> b) -> a -> b
    $ \ qtng :: Quoting
    qtng delim :: Word8
    delim useCrlf :: Bool
    useCrlf ->
            Quoting -> Word8 -> Bool -> Builder
    f Quoting
    qtng Word8
    delim Bool
    useCrlf Builder -> Builder -> Builder
    forall a. Semigroup a => a -> a -> a
    <> Quoting -> Word8 -> Bool -> Builder
    g Quoting
    qtng Word8
    delim Bool
    useCrlf

    instance Monoid (Builder a) where
        mempty :: Builder a
    mempty  = (Quoting -> Word8 -> Bool -> Builder) -> Builder a
    forall a. (Quoting -> Word8 -> Bool -> Builder) -> Builder a
    Builder (\ _ _ _ -> Builder
    forall a. Monoid a => a
    mempty)
        mappend :: Builder a -> Builder a -> Builder a
    mappend = Builder a -> Builder a -> Builder a
    forall a. Semigroup a => a -> a -> a
    (Semi.<>)

    ------------------------------------------------------------------------
    -- ** Index-based record conversion

    -- | Efficiently serialize named records in an incremental fashion,
    -- including the leading header. Equivalent to @'encodeWith'
    -- 'defaultEncodeOptions'@. The header is written before any records
    -- and dictates the field order.
    encodeByName :: ToNamedRecord a => Header -> NamedBuilder a -> L.ByteString
    encodeByName :: Header -> NamedBuilder a -> ByteString
    encodeByName = EncodeOptions -> Header -> NamedBuilder a -> ByteString
    forall a.
    ToNamedRecord a =>
    EncodeOptions -> Header -> NamedBuilder a -> ByteString
    encodeByNameWith EncodeOptions
    Encoding.defaultEncodeOptions

    -- | Like 'encodeByName', but header and field order is dictated by
    -- the 'Conversion.headerOrder' method.
    encodeDefaultOrderedByName :: (DefaultOrdered a, ToNamedRecord a) =>
                                  NamedBuilder a -> L.ByteString
    encodeDefaultOrderedByName :: NamedBuilder a -> ByteString
    encodeDefaultOrderedByName =
        EncodeOptions -> NamedBuilder a -> ByteString
    forall a.
    (DefaultOrdered a, ToNamedRecord a) =>
    EncodeOptions -> NamedBuilder a -> ByteString
    encodeDefaultOrderedByNameWith EncodeOptions
    Encoding.defaultEncodeOptions

    -- | Like 'encodeByName', but lets you customize how the CSV data is
    -- encoded.
    encodeByNameWith :: ToNamedRecord a => EncodeOptions -> Header -> NamedBuilder a
                     -> L.ByteString
    encodeByNameWith :: EncodeOptions -> Header -> NamedBuilder a -> ByteString
    encodeByNameWith opts :: EncodeOptions
    opts hdr :: Header
    hdr b :: NamedBuilder a
    b =
        Builder -> ByteString
    Builder.toLazyByteString (Builder -> ByteString) -> Builder -> ByteString
    forall a b. (a -> b) -> a -> b
    $
        Builder
    encHdr Builder -> Builder -> Builder
    forall a. Semigroup a => a -> a -> a
    <>
        NamedBuilder a -> Header -> Quoting -> Word8 -> Bool -> Builder
    forall a.
    NamedBuilder a -> Header -> Quoting -> Word8 -> Bool -> Builder
    runNamedBuilder NamedBuilder a
    b Header
    hdr (EncodeOptions -> Quoting
    encQuoting EncodeOptions
    opts) (EncodeOptions -> Word8
    encDelimiter EncodeOptions
    opts)
        (EncodeOptions -> Bool
    encUseCrLf EncodeOptions
    opts)
      where
        encHdr :: Builder
    encHdr
          | EncodeOptions -> Bool
    encIncludeHeader EncodeOptions
    opts =
              Quoting -> Word8 -> Header -> Builder
    Encoding.encodeRecord (EncodeOptions -> Quoting
    encQuoting EncodeOptions
    opts) (EncodeOptions -> Word8
    encDelimiter EncodeOptions
    opts) Header
    hdr
              Builder -> Builder -> Builder
    forall a. Semigroup a => a -> a -> a
    <> Bool -> Builder
    recordSep (EncodeOptions -> Bool
    encUseCrLf EncodeOptions
    opts)
          | Bool
    otherwise = Builder
    forall a. Monoid a => a
    mempty

    -- | Like 'encodeDefaultOrderedByName', but lets you customize how the
    -- CSV data is encoded.
    encodeDefaultOrderedByNameWith ::
        forall a. (DefaultOrdered a, ToNamedRecord a) =>
        EncodeOptions -> NamedBuilder a -> L.ByteString
    encodeDefaultOrderedByNameWith :: EncodeOptions -> NamedBuilder a -> ByteString
    encodeDefaultOrderedByNameWith opts :: EncodeOptions
    opts b :: NamedBuilder a
    b =
        Builder -> ByteString
    Builder.toLazyByteString (Builder -> ByteString) -> Builder -> ByteString
    forall a b. (a -> b) -> a -> b
    $
        Builder
    encHdr Builder -> Builder -> Builder
    forall a. Semigroup a => a -> a -> a
    <>
        NamedBuilder a -> Header -> Quoting -> Word8 -> Bool -> Builder
    forall a.
    NamedBuilder a -> Header -> Quoting -> Word8 -> Bool -> Builder
    runNamedBuilder NamedBuilder a
    b Header
    hdr (EncodeOptions -> Quoting
    encQuoting EncodeOptions
    opts)
        (EncodeOptions -> Word8
    encDelimiter EncodeOptions
    opts) (EncodeOptions -> Bool
    encUseCrLf EncodeOptions
    opts)
      where
        hdr :: Header
    hdr = a -> Header
    forall a. DefaultOrdered a => a -> Header
    Conversion.headerOrder (a
    forall a. HasCallStack => a
    undefined :: a)

        encHdr :: Builder
    encHdr
          | EncodeOptions -> Bool
    encIncludeHeader EncodeOptions
    opts =
              Quoting -> Word8 -> Header -> Builder
    Encoding.encodeRecord (EncodeOptions -> Quoting
    encQuoting EncodeOptions
    opts) (EncodeOptions -> Word8
    encDelimiter EncodeOptions
    opts) Header
    hdr
              Builder -> Builder -> Builder
    forall a. Semigroup a => a -> a -> a
    <> Bool -> Builder
    recordSep (EncodeOptions -> Bool
    encUseCrLf EncodeOptions
    opts)
          | Bool
    otherwise = Builder
    forall a. Monoid a => a
    mempty

    -- | Encode a single named record.
    encodeNamedRecord :: ToNamedRecord a => a -> NamedBuilder a
    encodeNamedRecord :: a -> NamedBuilder a
    encodeNamedRecord nr :: a
    nr = (Header -> Quoting -> Word8 -> Bool -> Builder) -> NamedBuilder a
    forall a.
    (Header -> Quoting -> Word8 -> Bool -> Builder) -> NamedBuilder a
    NamedBuilder ((Header -> Quoting -> Word8 -> Bool -> Builder) -> NamedBuilder a)
    -> (Header -> Quoting -> Word8 -> Bool -> Builder)
    -> NamedBuilder a
    forall a b. (a -> b) -> a -> b
    $ \ hdr :: Header
    hdr qtng :: Quoting
    qtng delim :: Word8
    delim useCrLf :: Bool
    useCrLf ->
        Header -> Quoting -> Word8 -> NamedRecord -> Builder
    Encoding.encodeNamedRecord Header
    hdr Quoting
    qtng Word8
    delim
        (a -> NamedRecord
    forall a. ToNamedRecord a => a -> NamedRecord
    Conversion.toNamedRecord a
    nr) Builder -> Builder -> Builder
    forall a. Semigroup a => a -> a -> a
    <> Bool -> Builder
    recordSep Bool
    useCrLf

    -- | A builder for building the CSV data incrementally. Just like the
    -- @ByteString@ builder, this builder should be used in a
    -- right-associative, 'foldr' style. Using '<>' to compose builders in
    -- a left-associative, `foldl'` style makes the building not be
    -- incremental.
    newtype NamedBuilder a = NamedBuilder {
          NamedBuilder a -> Header -> Quoting -> Word8 -> Bool -> Builder
    runNamedBuilder :: Header -> Quoting -> Word8 -> Bool -> Builder.Builder
        }

    -- | @since 0.5.0.0
    instance Semigroup (NamedBuilder a) where
        NamedBuilder f :: Header -> Quoting -> Word8 -> Bool -> Builder
    f <> :: NamedBuilder a -> NamedBuilder a -> NamedBuilder a
    <> NamedBuilder g :: Header -> Quoting -> Word8 -> Bool -> Builder
    g =
            (Header -> Quoting -> Word8 -> Bool -> Builder) -> NamedBuilder a
    forall a.
    (Header -> Quoting -> Word8 -> Bool -> Builder) -> NamedBuilder a
    NamedBuilder ((Header -> Quoting -> Word8 -> Bool -> Builder) -> NamedBuilder a)
    -> (Header -> Quoting -> Word8 -> Bool -> Builder)
    -> NamedBuilder a
    forall a b. (a -> b) -> a -> b
    $ \ hdr :: Header
    hdr qtng :: Quoting
    qtng delim :: Word8
    delim useCrlf :: Bool
    useCrlf ->
            Header -> Quoting -> Word8 -> Bool -> Builder
    f Header
    hdr Quoting
    qtng Word8
    delim Bool
    useCrlf Builder -> Builder -> Builder
    forall a. Semigroup a => a -> a -> a
    <> Header -> Quoting -> Word8 -> Bool -> Builder
    g Header
    hdr Quoting
    qtng Word8
    delim Bool
    useCrlf

    instance Monoid (NamedBuilder a) where
        mempty :: NamedBuilder a
    mempty = (Header -> Quoting -> Word8 -> Bool -> Builder) -> NamedBuilder a
    forall a.
    (Header -> Quoting -> Word8 -> Bool -> Builder) -> NamedBuilder a
    NamedBuilder (\ _ _ _ _ -> Builder
    forall a. Monoid a => a
    mempty)
        mappend :: NamedBuilder a -> NamedBuilder a -> NamedBuilder a
    mappend = NamedBuilder a -> NamedBuilder a -> NamedBuilder a
    forall a. Semigroup a => a -> a -> a
    (Semi.<>)

    ------------------------------------------------------------------------

    moduleError :: String -> String -> a
    moduleError :: String -> String -> a
    moduleError func :: String
    func msg :: String
    msg = String -> a
    forall a. HasCallStack => String -> a
    error (String -> a) -> String -> a
    forall a b. (a -> b) -> a -> b
    $ "Data.Csv.Incremental." String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    func String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ ": " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    msg
    {-# NOINLINE moduleError #-}