mischief-assets-0.1.0.0: src/Mischief/Assets/Internal/Kdl.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
module Mischief.Assets.Internal.Kdl where
import Data.Data
import Data.Map qualified as Map
import Data.Text (Text)
import Data.Text qualified as T
import GHC.Base
import GHC.Generics
import GHC.TypeLits
import KDL qualified
import Linear (V2)
import Mischief.Assets.Internal.Asset
import Mischief.Assets.Internal.Kdl.Collection
import Mischief.Assets.Orphans
import Mischief.ECS.Components.Bundle (Bundle)
import Mischief.ECS.Utils (mapLeft)
class (Typeable a) => KdlAsset a where
decodeKdl :: RelativePath -> KDL.NodeDecoder a
default decodeKdl :: (Generic a, GKdlAsset (Rep a)) => RelativePath -> KDL.NodeDecoder a
decodeKdl x = KDL.children (to <$> decodeKdl' @(Rep a) x)
class GKdlAsset f where
decodeKdl' :: RelativePath -> KDL.NodeListDecoder (f p)
data KdlRef a = KdlRef Text | KdlValue a deriving (Show)
instance GKdlAsset V1 where
decodeKdl' _ = undefined
instance GKdlAsset U1 where
decodeKdl' _ = pure U1
instance (GKdlAsset f, GKdlAsset g) => GKdlAsset (f :*: g) where
decodeKdl' x = do
a <- decodeKdl' @f x
b <- decodeKdl' @g x
pure $ a :*: b
instance (KdlAsset a, KnownSymbol name) => GKdlAsset (M1 S (MetaSel (Just name) x y z) (K1 i a)) where
decodeKdl' x = do
let t = T.pack $ symbolVal (Proxy @name)
M1 . K1 <$> KDL.nodeWith t (decodeKdl x)
instance (GKdlAsset a) => GKdlAsset (D1 i a) where
decodeKdl' x = M1 <$> decodeKdl' x
instance {-# OVERLAPPABLE #-} (GKdlAsset a) => GKdlAsset (M1 C i a) where
decodeKdl' x = M1 <$> decodeKdl' x
instance (Asset a, Bundle a) => KdlAsset (AssetRef a) where
decodeKdl = KDL.argWith . decodeRef
instance (KdlAsset a) => KdlAsset [a] where
decodeKdl n = KDL.children $ do
x <- KDL.remainingNodesWith $ decodeKdl @a n
pure $ concatMap snd $ Map.toList x
instance (KdlAsset a) => KdlAsset (KdlRef a) where
decodeKdl n = f1 <|> f2
where
f1 = KDL.propWith "link" $ decodeKdlRef n
f2 = KdlValue <$> decodeKdl n
instance (KdlAsset a) => KdlAsset (KdlCollection a) where
decodeKdl n = KDL.children $ colDecodeWith $ decodeKdl @a n
instance {-# OVERLAPPABLE #-} (Typeable a, KDL.DecodeNode a) => KdlAsset a where
decodeKdl _ = KDL.nodeDecoder
loadKdl :: forall a. (KdlAsset a) => Text -> FilePath -> RelativePath -> IO (Either Text a)
loadKdl t p r = mapLeft T.show <$> KDL.decodeFileWith (KDL.document $ KDL.nodeWith t $ decodeKdl @a r) p
decodeKdlRef :: RelativePath -> KDL.ValueDecoder (KdlRef a)
decodeKdlRef path = do
t <- KDL.valueDecoder @Text
pure $ KdlRef $ path <> "/" <> t
kdlToAssetRef :: (Asset a, Bundle a) => KdlRef a -> AssetRef a
kdlToAssetRef (KdlRef p) = Ref p
kdlToAssetRef (KdlValue v) = PureRef v
instance ToAssetRef KdlRef where
toRef = kdlToAssetRef