summaryrefslogtreecommitdiff
path: root/src/Data/Name.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Data/Name.hs')
-rw-r--r--src/Data/Name.hs76
1 files changed, 76 insertions, 0 deletions
diff --git a/src/Data/Name.hs b/src/Data/Name.hs
new file mode 100644
index 0000000..9572709
--- /dev/null
+++ b/src/Data/Name.hs
@@ -0,0 +1,76 @@
+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 #-}