rattletrap-10.0.0: src/lib/Rattletrap/Type/Dictionary.hs
module Rattletrap.Type.Dictionary where
import qualified Rattletrap.ByteGet as ByteGet
import qualified Rattletrap.BytePut as BytePut
import qualified Rattletrap.Schema as Schema
import qualified Rattletrap.Type.List as List
import qualified Rattletrap.Type.Str as Str
import qualified Rattletrap.Utility.Json as Json
import qualified Data.Bifunctor as Bifunctor
import qualified Data.Map as Map
import qualified Data.Text as Text
data Dictionary a = Dictionary
{ elements :: List.List (Str.Str, a)
, lastKey :: Str.Str
}
deriving (Eq, Show)
instance Json.FromJSON a => Json.FromJSON (Dictionary a) where
parseJSON = Json.withObject "Dictionary" $ \o -> do
keys <- Json.required o "keys"
lastKey_ <- Json.required o "last_key"
value <- Json.required o "value"
let
build
:: MonadFail m
=> Map.Map Text.Text a
-> Int
-> [(Int, (Str.Str, a))]
-> [Text.Text]
-> m (List.List (Str.Str, a))
build m i xs ks = case ks of
[] -> pure . List.fromList . reverse $ fmap snd xs
k : t -> case Map.lookup k m of
Nothing -> fail $ "missing required key " <> show k
Just v -> build m (i + 1) ((i, (Str.fromText k, v)) : xs) t
elements_ <- build value 0 [] keys
pure Dictionary { elements = elements_, lastKey = lastKey_ }
instance Json.ToJSON a => Json.ToJSON (Dictionary a) where
toJSON x = Json.object
[ Json.pair "keys" . fmap fst . List.toList $ elements x
, Json.pair "last_key" $ lastKey x
, Json.pair "value"
. Map.fromList
. fmap (Bifunctor.first Str.toText)
. List.toList
$ elements x
]
schema :: Schema.Schema -> Schema.Schema
schema s =
Schema.named ("dictionary-" <> Text.unpack (Schema.name s)) $ Schema.object
[ (Json.pair "keys" . Schema.json $ Schema.array Str.schema, True)
, (Json.pair "last_key" $ Schema.ref Str.schema, True)
, ( Json.pair "value" $ Json.object
[ Json.pair "type" "object"
, Json.pair "additionalProperties" $ Schema.ref s
]
, True
)
]
lookup :: Str.Str -> Dictionary a -> Maybe a
lookup k = Prelude.lookup k . List.toList . elements
bytePut :: (a -> BytePut.BytePut) -> Dictionary a -> BytePut.BytePut
bytePut f x =
foldMap (\(k, v) -> Str.bytePut k <> f v) (List.toList $ elements x)
<> Str.bytePut (lastKey x)
byteGet :: ByteGet.ByteGet a -> ByteGet.ByteGet (Dictionary a)
byteGet = byteGetWith 0 []
byteGetWith
:: Int
-> [(Int, (Str.Str, a))]
-> ByteGet.ByteGet a
-> ByteGet.ByteGet (Dictionary a)
byteGetWith i xs f = do
k <- Str.byteGet
if isNone k
then pure Dictionary
{ elements = List.fromList . reverse $ fmap snd xs
, lastKey = k
}
else do
v <- f
byteGetWith (i + 1) ((i, (k, v)) : xs) f
isNone :: Str.Str -> Bool
isNone = (== Text.pack "None") . Text.filter (/= '\x00') . Str.toText