{-# LANGUAGE GADTs #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Siphon.Types where import Data.Vector (Vector) import Control.Exception (Exception) import Data.Typeable (Typeable) import qualified Data.Vector as Vector import qualified Data.Attoparsec.Types as Atto newtype Escaped c = Escaped { getEscaped :: c } data Siphon c = Siphon { siphonEscape :: !(c -> Escaped c) , siphonIntercalate :: !(Vector (Escaped c) -> c) , siphonParseRow :: c -> Atto.IResult c (Vector c) , siphonNull :: c -> Bool } data DecolonnadeCellError f content = DecolonnadeCellError { decodingCellErrorContent :: !content , decodingCellErrorHeader :: !(Indexed f content) , decodingCellErrorMessage :: !String } deriving (Show,Read,Eq) -- instance (Show (f content), Typeable content) => Exception (DecolonnadeError f content) data Indexed f a = Indexed { indexedIndex :: !Int , indexedHeading :: !(f a) } deriving (Eq,Ord,Functor,Show,Read) newtype DecolonnadeCellErrors f content = DecolonnadeCellErrors { getDecolonnadeCellErrors :: Vector (DecolonnadeCellError f content) } deriving (Monoid,Show,Read,Eq) -- newtype ParseRowError = ParseRowError String -- TODO: rewrite the instances for this by hand. They -- currently use FlexibleContexts. data DecolonnadeRowError f content = DecolonnadeRowError { decodingRowErrorRow :: !Int , decodingRowErrorError :: !(RowError f content) } deriving (Show,Read,Eq) -- TODO: rewrite the instances for this by hand. They -- currently use FlexibleContexts. data RowError f content = RowErrorParse !String -- ^ Error occurred parsing the document into cells | RowErrorDecode !(DecolonnadeCellErrors f content) -- ^ Error decoding the content | RowErrorSize !Int !Int -- ^ Wrong number of cells in the row | RowErrorHeading !(HeadingErrors content) | RowErrorMinSize !Int !Int | RowErrorMalformed !String -- ^ Error decoding unicode content deriving (Show,Read,Eq) data HeadingErrors content = HeadingErrors { headingErrorsMissing :: Vector content -- ^ headers that were missing , headingErrorsDuplicate :: Vector (content,Int) -- ^ headers that occurred more than once } deriving (Show,Read,Eq) instance (Show content, Typeable content) => Exception (HeadingErrors content) instance Monoid (HeadingErrors content) where mempty = HeadingErrors Vector.empty Vector.empty mappend (HeadingErrors a1 b1) (HeadingErrors a2 b2) = HeadingErrors (a1 Vector.++ a2) (b1 Vector.++ b2) -- | This just actually a specialization of the free applicative. -- Check out @Control.Applicative.Free@ in the @free@ library to -- learn more about this. The meanings of the fields are documented -- slightly more in the source code. Unfortunately, haddock does not -- play nicely with GADTs. data Decolonnade f content a where DecolonnadePure :: !a -- function -> Decolonnade f content a DecolonnadeAp :: !(f content) -- header -> !(content -> Either String a) -- decoding function -> !(Decolonnade f content (a -> b)) -- next decoding -> Decolonnade f content b instance Functor (Decolonnade f content) where fmap f (DecolonnadePure a) = DecolonnadePure (f a) fmap f (DecolonnadeAp h c apNext) = DecolonnadeAp h c ((f .) <$> apNext) instance Applicative (Decolonnade f content) where pure = DecolonnadePure DecolonnadePure f <*> y = fmap f y DecolonnadeAp h c y <*> z = DecolonnadeAp h c (flip <$> y <*> z) -- -- | This type is provided for convenience with @pipes-text@ -- data CsvResult f c -- = CsvResultSuccess -- | CsvResultTextDecodeError -- | CsvResultDecodeError (DecodingRowError f c) -- deriving (Show,Read,Eq) -- | Consider changing out the use of 'Vector' here -- with the humble list instead. It might fuse away -- better. Not sure though. -- data SiphonX c1 c2 = SiphonX -- { siphonXEscape :: !(c1 -> Escaped c2) -- , siphonXIntercalate :: !(Vector (Escaped c2) -> c2) -- } -- -- data SiphonDecoding c1 c2 = SiphonDecoding -- { siphonDecodingParse :: c1 -> Atto.IResult c1 (Vector c2) -- , siphonDecodingNull :: c1 -> Bool -- } -- data WithEnd c = WithEnd -- { withEndEnded :: !Bool -- , withEndContent :: !c -- } -- data SiphonDecodingError -- { clarify -- }