module Montis.Core.State.Marshal (marshalState, demarshalState) where import Data.Map qualified as M import Data.Maybe (mapMaybe) import Montis.Core.Extensions import Montis.Core.State data MarshalledState where MarshalledState :: [(String, String)] -> MarshalledState deriving (Show, Read) -- | Marshals the serializable parts of the state to a string. This happens -- during a hot-reload where some state must be saved to persist across hot -- reloads. -- Only the extensible state is persisted; hooks and other runtime data are -- reconstructed from the config on restart. marshalState :: State m -> String marshalState ( State { extensibleState = xs } ) = show $ MarshalledState (mapMaybe (\(k, v) -> (extensionKeyValue k,) <$> doMarshalEx v) (M.toList xs)) where -- Left values are already marshalled; Right values are re-encoded here. doMarshalEx :: Either String (Extension StateExtension) -> Maybe String doMarshalEx (Left s) = Just s doMarshalEx (Right (Extension a)) = marshalExtension a -- | Demarshals the string from "marshalState" into a state. Uses the provided -- config to fill out non-persistent parts of the state. -- The extensible map is rehydrated as marshalled strings so decoding can be -- deferred until a specific extension is requested. demarshalState :: Config m -> String -> State m demarshalState Config {startingHooks = hooks} str = State hooks xs where ( MarshalledState (M.mapKeys ExtensionKey . fmap Left . M.fromList -> xs) ) = read str