registry-0.1.0.3: src/Data/Registry/Internal/Types.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{- |
List of types used inside the Registry
-}
module Data.Registry.Internal.Types where
import Data.Dynamic
import Data.Registry.Internal.Reflection
import Data.Text as T
import Prelude (show)
import Protolude hiding (show)
import Type.Reflection
-- | A 'Function' is the 'Dynamic' representation of a Haskell value + its description
-- It is either provided by the user of the Registry or created as part of the
-- resolution algorithm
data Value =
CreatedValue Dynamic ValueDescription
| ProvidedValue Dynamic ValueDescription
deriving (Show)
-- | Description of a value. It might just have
-- a description for its type when it is a value
-- created by the resolution algorithm
data ValueDescription = ValueDescription {
_valueType :: Text
, _valueValue :: Maybe Text
} deriving (Eq, Show)
-- | Describe a value with its type and actual content
describeValue :: (Typeable a, Show a) => a -> ValueDescription
describeValue a = ValueDescription (showFullValueType a) (Just . toS $ show a)
-- | Describe a value with only its type
describeTypeableValue :: (Typeable a) => a -> ValueDescription
describeTypeableValue a = ValueDescription (showFullValueType a) Nothing
-- | Show a Value from the 'Registry'
showValue :: Value -> Text
showValue = valDescriptionToText . valDescription
-- | Create a Value from a Haskell value, with its 'Show' description
createValue :: (Show a, Typeable a) => a -> Value
createValue a = ProvidedValue (toDyn a) (describeValue a)
-- | Create a Value from a Haskell value, with only its 'Typeable' description
createTypeableValue :: Typeable a => a -> Value
createTypeableValue a = ProvidedValue (toDyn a) (describeTypeableValue a)
-- | Create a Value from a 'Dynamic' value and some description
createDynValue :: Dynamic -> Text -> Value
createDynValue dyn desc = ProvidedValue dyn (ValueDescription desc Nothing)
-- | Type representation of a 'Value'
valueDynTypeRep :: Value -> SomeTypeRep
valueDynTypeRep (CreatedValue d _) = dynTypeRep d
valueDynTypeRep (ProvidedValue d _) = dynTypeRep d
-- | Dynamic representation of a 'Value'
valueDyn :: Value -> Dynamic
valueDyn (CreatedValue d _) = d
valueDyn (ProvidedValue d _) = d
-- | The description for a 'Value'
valDescription :: Value -> ValueDescription
valDescription (CreatedValue _ d) = d
valDescription (ProvidedValue _ d) = d
-- | A ValueDescription as 'Text'. If the actual content of the 'Value'
-- is provided display the type first then the content
valDescriptionToText :: ValueDescription -> Text
valDescriptionToText (ValueDescription t Nothing) = t
valDescriptionToText (ValueDescription t (Just v)) = t <> ": " <> v
-- | A Function is the 'Dynamic' representation of a Haskell function + its description
data Function = Function Dynamic FunctionDescription deriving (Show)
-- | Create a 'Function' value from a Haskell function
createFunction :: (Typeable a) => a -> Function
createFunction a =
let dynType = toDyn a
in Function dynType (describeFunction a)
-- | Description of a 'Function' with input types and output type
data FunctionDescription = FunctionDescription {
_inputTypes :: [Text]
, _outputType :: Text
} deriving (Eq, Show)
-- | Describe a 'Function' (which doesn't have a 'Show' instance)
-- that can be put in the 'Registry'
describeFunction :: Typeable a => a -> FunctionDescription
describeFunction = uncurry FunctionDescription . showFullFunctionType
-- | Show a Function as 'Text' using its Description
showFunction :: Function -> Text
showFunction = funDescriptionToText . funDescription
-- | The Description of a 'Function'
funDescription :: Function -> FunctionDescription
funDescription (Function _ t) = t
-- | Dynamic representation of a 'Function'
funDyn :: Function -> Dynamic
funDyn (Function d _) = d
-- | Type representation of a 'Function'
funDynTypeRep :: Function -> SomeTypeRep
funDynTypeRep = dynTypeRep . funDyn
-- | A 'FunctionDescription' as 'Text'
funDescriptionToText :: FunctionDescription -> Text
funDescriptionToText (FunctionDescription ins out) = T.intercalate " -> " (ins <> [out])
-- | Return True if a 'Function' has some input values
hasParameters :: Function -> Bool
hasParameters = isFunction . funDynTypeRep
-- | A Typed value can be added to a 'Registry'
-- It is either a value, having both 'Show' and 'Typeable' information
-- or a function having just 'Typeable' information
data Typed a =
TypedValue Value
| TypedFunction Function
-- | The list of functions available for constructing other values
newtype Functions = Functions [Function] deriving (Show, Semigroup, Monoid)
-- | Add one more Function to the list of Functions
addFunction :: Function -> Functions -> Functions
addFunction f (Functions fs) = Functions (f : fs)
-- | List of values available for constructing other values
newtype Values = Values [Value] deriving (Show, Semigroup, Monoid)
-- | Add one more Value to the list of Values
addValue :: Value -> Values -> Values
addValue v (Values vs) = Values (v : vs)
-- | The types of values being currently built
newtype Context = Context { _context :: [SomeTypeRep] } deriving (Show, Semigroup, Monoid)
-- | Specification of values which become available for
-- construction when a corresponding type comes in context
newtype Specializations = Specializations [(SomeTypeRep, Value)] deriving (Show, Semigroup, Monoid)
-- | List of functions modifying some values right after they have been
-- built. This enables "tweaking" the creation process with slightly
-- different results. Here SomeTypeRep is the target value type 'a' and
newtype Modifiers = Modifiers [(SomeTypeRep, Function)] deriving (Show, Semigroup, Monoid)