module Data.Name ( Name (..) , Name_ -- * Parsers , readNameLFM , readNameFML -- * Writers , renderNameLFM , renderNameFML ) where import Prolog import Data.Char (isSpace) import Data.List qualified as L import Data.Text qualified as T data Name a = Name { lastName :: !a , firstName :: !a , middleName :: !(Maybe a) } deriving (Eq, Functor, Foldable, Generic, Generic1, Ord, Show, Traversable) type Name_ = Name StrictText instance Binary a => Binary (Name a) instance Applicative Name where pure a = Name a a (pure a) Name l f m <*> Name l' f' m' = Name (l l') (f f') (m <*> m') readNameLFM :: Alternative m => StrictText -> m Name_ readNameLFM t = T.map (\c -> if c == '~' then ' ' else c) <<$>> case T.break (== ',') t of (l, fm) | T.null l -> empty | otherwise -> case T.dropWhile ((||) <$> isSpace <*> (== ',')) fm of fm' | T.null fm' -> empty | otherwise -> case T.break isSpace fm' of (f, m) -> pure $ Name l f $ case T.dropWhile isSpace m of x | T.null x -> Nothing | otherwise -> Just x readNameFML :: Alternative m => StrictText -> m Name_ readNameFML t = T.map (\c -> if c == '~' then ' ' else c) <<$>> case T.words t of [] -> empty (f:xs) -> case unsnoc xs of Nothing -> empty Just (m, l) -> pure $ Name f l $ case m of [] -> Nothing _ -> Just $ T.unwords m showNameLFM :: Name_ -> StrictText showNameLFM (Name l f m) = stt l <> ", " <> stt f <> maybe "" (\x -> " " <> stt x) m showNameFML :: Name_ -> StrictText showNameFML (Name l f m) = stt f <> maybe " " (\x -> " " <> stt x <> " ") m <> stt l renderNameLFM :: (Semigroup a, IsString a) => Name a -> a renderNameLFM (Name l f m) = l <> ", " <> f <> maybe "" (\x -> " " <> x) m renderNameFML :: (Semigroup a, IsString a) => Name a -> a renderNameFML (Name l f m) = f <> maybe " " (\x -> " " <> x <> " ") m <> l -- Helpers unsnoc :: [a] -> Maybe ([a],a) unsnoc = foldr (\x -> Just . maybe ([], x) (\(~(a, b)) -> (x : a, b))) Nothing {-# INLINABLE unsnoc #-} stt :: StrictText -> StrictText stt = T.map $ \c -> if isSpace c then '~' else c {-# INLINABLE stt #-}