hedn-0.1.5.2: src/Data/EDN/Types.hs
{-# LANGUAGE FlexibleInstances #-}
module Data.EDN.Types (
-- * Types
Value(..), Tagged(..), TaggedValue,
-- ** Internal containers
EDNList, EDNVec, EDNSet, EDNMap, Pair,
-- * Tag manipulation
setTag, getTag, stripTag,
-- * Constructors
tag, notag,
-- ** Trivial values
nil,
bool, true, false,
char, string,
symbol, symbolNS, keyword,
integer, floating,
-- ** Containers
makeList, makeVec, makeSet, makeMap, (.=)
) where
import Data.String (IsString(..))
import Data.Text (Text)
import qualified Data.Text as T
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as BS
import qualified Data.Vector as V
import qualified Data.Map as M
import qualified Data.Set as S
-- | Abstract namespaced tag.
data Tagged a = NoTag !a
| Tagged !a !ByteString !ByteString
deriving (Eq, Ord, Show)
instance Functor Tagged where
fmap f (NoTag v) = NoTag (f v)
fmap f (Tagged v ns t) = Tagged (f v) ns t
type TaggedValue = Tagged Value
type EDNList = [TaggedValue]
type EDNVec = V.Vector TaggedValue
type EDNMap = M.Map Value TaggedValue
type EDNSet = S.Set TaggedValue
-- | A \"raw\" EDN value represented as a Haskell value.
data Value = Nil
| Boolean !Bool
| String !Text
| Character !Char
| Symbol !ByteString !ByteString
| Keyword !ByteString
| Integer !Integer
| Floating !Double
| List EDNList
| Vec !EDNVec
| Map !EDNMap
| Set !EDNSet
deriving (Eq, Ord, Show)
-- | Strings starting with \":\" will become keywords.
instance IsString Value where
fromString (':':s) = Keyword . BS.pack $ s
fromString s = String . T.pack $ s
{-# INLINE fromString #-}
-- | Strings will become an tagless EDN strings.
instance IsString (Tagged Value) where
fromString = string . T.pack
{-# INLINE fromString #-}
-- | Basic EDN nil.
nil :: TaggedValue
nil = NoTag Nil
{-# INLINE nil #-}
-- | Basic EDN boolean.
bool :: Bool -> TaggedValue
bool = NoTag . Boolean
{-# INLINE bool #-}
-- | Const EDN True.
true :: TaggedValue
true = bool True
{-# INLINE true #-}
-- | Const EDN False.
false :: TaggedValue
false = bool False
{-# INLINE false #-}
-- | Basic EDN character.
char :: Char -> TaggedValue
char = NoTag . Character
{-# INLINE char #-}
-- | Basic EDN string.
string :: Text -> TaggedValue
string = NoTag . String
{-# INLINE string #-}
-- | A namespaced symbol.
symbolNS :: ByteString -> ByteString -> TaggedValue
symbolNS ns value = NoTag $ Symbol ns value
{-# INLINE symbolNS #-}
-- | \"Bare\" symbol.
symbol :: ByteString -> TaggedValue
symbol = symbolNS BS.empty
{-# INLINE symbol #-}
-- | Basic EDN keyword.
keyword :: ByteString -> TaggedValue
keyword = NoTag . Keyword
{-# INLINE keyword #-}
-- | Basic EDN integer.
integer :: Integer -> TaggedValue
integer = NoTag . Integer
{-# INLINE integer #-}
-- | Basic EDN fp number.
floating :: Double -> TaggedValue
floating = NoTag . Floating
{-# INLINE floating #-}
-- | Attach a namespaced tag to a value.
tag :: ByteString -> ByteString -> a -> Tagged a
tag ns t value = Tagged value ns t
{-# INLINE tag #-}
-- | Wrap a value into tagless container.
notag :: a -> Tagged a
notag = NoTag
{-# INLINE notag #-}
-- | Replace a tag on a 'Tagged' value.
setTag :: ByteString -> ByteString -> Tagged a -> Tagged a
setTag ns t (NoTag v) = tag ns t v
setTag ns t (Tagged v _ _) = tag ns t v
{-# INLINE setTag #-}
-- | Extract namespace and tag from a tagged container. Will be a pair of 'BS.empty' for tagless containers.
getTag :: TaggedValue -> (ByteString, ByteString)
getTag (NoTag _) = (BS.empty, BS.empty)
getTag (Tagged _ ns t) = (ns, t)
-- | Extract bare value from a tagged or tagless container.
stripTag :: Tagged a -> a
stripTag (NoTag v) = v
stripTag (Tagged v _ _) = v
{-# INLINE stripTag #-}
-- | Create an EDN 'List' from a 'Value' list wrapping them into empty tags.
makeList :: [TaggedValue] -> Value
makeList = List
{-# INLINE makeList #-}
-- | Create an EDN 'Vector' from a 'TaggedValue' list.
makeVec :: [TaggedValue] -> Value
makeVec = Vec . V.fromList
{-# INLINE makeVec #-}
-- | Create an EDN 'Set' from a 'TaggedValue' list.
makeSet :: [TaggedValue] -> Value
makeSet = Set . S.fromList
{-# INLINE makeSet #-}
-- | A key\/value pair for a EDN Map
type Pair = (Value, TaggedValue)
-- | Create an EDN 'Map' from a assoc list with untagged keys and tagged values.
makeMap :: [Pair] -> Value
makeMap = Map . M.fromList
{-# INLINE makeMap #-}
-- | Construct a 'Pair' from a key (as EDN keyword) and a value.
(.=) :: ByteString -> TaggedValue -> Pair
name .= value = (Keyword name, value)
{-# INLINE (.=) #-}