module Data.Generics.Record.Reify (reify, reifyMay, reflect) where
import Data.Generics.Record
import Data.Dynamic
import Data.Typeable
import Data.Data
import qualified Data.Map as M
import Data.Map (Map)
import Data.Maybe
import Control.Monad.State
import Control.Applicative
reify :: forall a. Data a => RecordT a -> a -> Map String Dynamic
reify _ = fromJust . reifyMay
reifyMay :: forall a. Data a => a -> Maybe (Map String Dynamic)
reifyMay a = (recordT :: Maybe (RecordT a))>>= return . M.fromList . flip zip (gmapQ toDyn a) . fields
reflect :: forall a. Data a => Map String Dynamic -> Maybe a
reflect vault = result
where constrs = dataTypeConstrs . dataTypeOf $ fromJust result
fs = (recordT :: Maybe (RecordT a)) >>= mapM (flip M.lookup vault) . fields
result = flip evalStateT fs . gmapM popFields . fromConstr . head $ constrs
popFields _ = (get >>= lift . (fromDynamic . head =<<)) <* modify (fmap tail)