module Data.Sv.Syntax.Sv (
Sv (Sv, _separatorSv, _maybeHeader, _records, _finalNewlines)
, HasSv (sv, maybeHeader, traverseHeader, finalNewlines)
, HasRecords (records, traverseNewlines, traverseRecords)
, mkSv
, emptySv
, recordList
, Header (Header, _headerRecord)
, HasHeader (header, headerRecord, headerNewline)
, noHeader
, mkHeader
, Headedness (Unheaded, Headed)
, HasHeadedness (headedness)
, getHeadedness
, Separator
, HasSeparator (separator)
, comma
, pipe
, tab
) where
import Control.DeepSeq (NFData)
import Control.Lens (Lens, Lens', Traversal')
import Data.Foldable (Foldable (foldMap))
import Data.Functor (Functor (fmap), (<$>))
import Data.Monoid ((<>))
import Data.Traversable (Traversable (traverse))
import GHC.Generics (Generic)
import Data.Sv.Syntax.Field (HasFields (fields))
import Data.Sv.Syntax.Record (Record, Records (EmptyRecords), HasRecord (record), HasRecords (records, traverseNewlines, traverseRecords), recordList)
import Text.Newline (Newline)
data Sv s =
Sv {
_separatorSv :: Separator
, _maybeHeader :: Maybe (Header s)
, _records :: Records s
, _finalNewlines :: [Newline]
}
deriving (Eq, Ord, Show, Generic)
instance NFData s => NFData (Sv s)
class (HasRecords c s, HasSeparator c) => HasSv c s | c -> s where
sv :: Lens' c (Sv s)
maybeHeader :: Lens' c (Maybe (Header s))
traverseHeader :: Traversal' c (Header s)
finalNewlines :: Lens' c [Newline]
maybeHeader = sv . maybeHeader
traverseHeader = maybeHeader . traverse
finalNewlines = sv . finalNewlines
instance HasRecords (Sv s) s where
records f (Sv x1 x2 x3 x4) =
fmap (\y -> Sv x1 x2 y x4) (f x3)
instance HasSv (Sv s) s where
sv = id
maybeHeader f (Sv x1 x2 x3 x4) =
fmap (\y -> Sv x1 y x3 x4) (f x2)
finalNewlines f (Sv x1 x2 x3 x4) =
fmap (Sv x1 x2 x3) (f x4)
mkSv :: Separator -> Maybe (Header s) -> [Newline] -> Records s -> Sv s
mkSv c h ns rs = Sv c h rs ns
emptySv :: Separator -> Sv s
emptySv c = Sv c Nothing EmptyRecords []
instance Functor Sv where
fmap f (Sv s h rs e) = Sv s (fmap (fmap f) h) (fmap f rs) e
instance Foldable Sv where
foldMap f (Sv _ h rs _) = foldMap (foldMap f) h <> foldMap f rs
instance Traversable Sv where
traverse f (Sv s h rs e) = Sv s <$> traverse (traverse f) h <*> traverse f rs <*> pure e
getHeadedness :: Sv s -> Headedness
getHeadedness = maybe Unheaded (const Headed) . _maybeHeader
data Header s =
Header {
_headerRecord :: Record s
, _headerNewline :: Newline
}
deriving (Eq, Ord, Show, Functor, Foldable, Traversable, Generic)
instance NFData s => NFData (Header s)
class HasHeader s t a b | s -> a, t -> b, s b -> t, t a -> s where
header :: Lens s t (Header a) (Header b)
headerNewline :: (s ~ t) => Lens s t Newline Newline
headerRecord :: Lens s t (Record a) (Record b)
default headerNewline :: (a ~ b) => Lens s t Newline Newline
headerNewline = header . headerNewline
headerRecord = header . headerRecord
instance HasHeader (Header a) (Header b) a b where
header = id
headerNewline f (Header x1 x2)
= fmap (Header x1) (f x2)
headerRecord f (Header x1 x2)
= fmap (\y -> Header y x2) (f x1)
instance HasRecord (Header a) (Header b) a b where
record = headerRecord
instance HasFields (Header a) (Header b) a b where
fields = headerRecord . fields
noHeader :: Maybe (Header s)
noHeader = Nothing
mkHeader :: Record s -> Newline -> Maybe (Header s)
mkHeader r n = Just (Header r n)
data Headedness =
Unheaded | Headed
deriving (Eq, Ord, Show)
class HasHeadedness c where
headedness :: Lens' c Headedness
instance HasHeadedness Headedness where
headedness = id
type Separator = Char
class HasSeparator c where
separator :: Lens' c Separator
instance HasSeparator Char where
separator = id
instance HasSeparator (Sv s) where
separator f (Sv x1 x2 x3 x4) =
fmap (\y -> Sv y x2 x3 x4) (f x1)
comma :: Separator
comma = ','
pipe :: Separator
pipe = '|'
tab :: Separator
tab = '\t'