{-# LANGUAGE MonoLocalBinds #-}

-- | Small wrapper over the Dynamic type.
module Byg.Types.Value
  ( Value(..)
  , toValue
  , toValueRep
  , fromValue
  , fromValueRep
  ) where

import Type.Reflection (TypeRep, typeRep, eqTypeRep)
import Data.Type.Equality ((:~~:)(HRefl))
import Data.Dynamic

data Value = Value { valueDynamic :: Dynamic
                   , valueShow :: String
                   }

instance Show Value where
  show = valueShow

fromDynRep :: TypeRep a -> Dynamic -> a
fromDynRep tr (Dynamic t v)
  | Just HRefl <- t `eqTypeRep` tr = v
  | otherwise = error ("unexpected; expected " ++ show tr ++ " but has " ++ show t)

toValue :: (Show a, Typeable a) => a -> Value
toValue = toValueRep typeRep

toValueRep :: Show a => TypeRep a -> a -> Value
toValueRep tr a = Value { valueDynamic = Dynamic tr a
                        , valueShow = show a
                        }

fromValue :: Typeable a => Value -> a
fromValue = fromValueRep typeRep

fromValueRep :: TypeRep a -> Value -> a
fromValueRep tr = fromDynRep tr . valueDynamic
