ganeti-htoolsSource codeContentsIndex
Ganeti.THH
Contents
Exported types
Common field declarations
Helper functions
Template code for simple raw type-equivalent ADTs
Template code for opcodes
Template code for luxi
Objects functionality
Inheritable parameter tables implementation
Description

TemplateHaskell helper for HTools.

As TemplateHaskell require that splices be defined in a separate module, we combine all the TemplateHaskell functionality that HTools needs in this module (except the one for unittests).

Synopsis
type Container = Map String
data Field = Field {
fieldName :: String
fieldType :: Q Type
fieldRead :: Maybe (Q Exp)
fieldShow :: Maybe (Q Exp)
fieldDefault :: Maybe (Q Exp)
fieldConstr :: Maybe String
fieldIsContainer :: Bool
fieldIsOptional :: Bool
}
simpleField :: String -> Q Type -> Field
renameField :: String -> Field -> Field
defaultField :: Q Exp -> Field -> Field
optionalField :: Field -> Field
containerField :: Field -> Field
customField :: Name -> Name -> Field -> Field
fieldRecordName :: Field -> String
fieldVariable :: Field -> String
actualFieldType :: Field -> Q Type
checkNonOptDef :: Monad m => Field -> m ()
loadFn :: Field -> Q Exp -> Q Exp -> Q Exp
timeStampFields :: [Field]
serialFields :: [Field]
uuidFields :: [Field]
ensureLower :: String -> String
ensureUpper :: String -> String
varNameE :: String -> Q Exp
showJSONE :: Q Exp
toRawName :: String -> Name
fromRawName :: String -> Name
reprE :: Either String Name -> Q Exp
appFn :: Exp -> Exp -> Exp
readContainer :: (Monad m, JSON a) => JSObject JSValue -> m (Container a)
showContainer :: JSON a => Container a -> JSValue
strADTDecl :: Name -> [String] -> Dec
genToRaw :: Name -> Name -> Name -> [(String, Either String Name)] -> Q [Dec]
genFromRaw :: Name -> Name -> Name -> [(String, Name)] -> Q [Dec]
declareADT :: Name -> String -> [(String, Name)] -> Q [Dec]
declareIADT :: String -> [(String, Name)] -> Q [Dec]
declareSADT :: String -> [(String, Name)] -> Q [Dec]
genShowJSON :: String -> Q Dec
genReadJSON :: String -> Q Dec
makeJSONInstance :: Name -> Q [Dec]
deCamelCase :: String -> String
camelCase :: String -> String
constructorName :: Con -> Q Name
genConstrToStr :: (String -> String) -> Name -> String -> Q [Dec]
genOpID :: Name -> String -> Q [Dec]
type OpParam = (String, Q Type, Q Exp)
genOpCode :: String -> [(String, [Field])] -> Q [Dec]
isOptional :: Type -> Bool
saveConstructor :: String -> [Field] -> Q Clause
genSaveOpCode :: [(String, [Field])] -> Q (Dec, Dec)
loadConstructor :: String -> [Field] -> Q Exp
genLoadOpCode :: [(String, [Field])] -> Q (Dec, Dec)
genStrOfOp :: Name -> String -> Q [Dec]
genStrOfKey :: Name -> String -> Q [Dec]
type LuxiParam = (String, Q Type, Q Exp)
genLuxiOp :: String -> [(String, [LuxiParam])] -> Q [Dec]
saveLuxiField :: Name -> LuxiParam -> Q Exp
saveLuxiConstructor :: (String, [LuxiParam]) -> Q Clause
genSaveLuxiOp :: [(String, [LuxiParam])] -> Q (Dec, Dec)
fieldTypeInfo :: String -> Field -> Q (Name, Strict, Type)
buildObject :: String -> String -> [Field] -> Q [Dec]
buildObjectSerialisation :: String -> [Field] -> Q [Dec]
genSaveObject :: (Name -> Field -> Q Exp) -> String -> [Field] -> Q [Dec]
saveObjectField :: Name -> Field -> Q Exp
objectShowJSON :: String -> Q Dec
genLoadObject :: (Field -> Q (Name, Stmt)) -> String -> [Field] -> Q (Dec, Dec)
loadObjectField :: Field -> Q (Name, Stmt)
objectReadJSON :: String -> Q Dec
paramTypeNames :: String -> (String, String)
paramFieldTypeInfo :: String -> Field -> Q (Name, Strict, Type)
buildParam :: String -> String -> [Field] -> Q [Dec]
buildPParamSerialisation :: String -> [Field] -> Q [Dec]
savePParamField :: Name -> Field -> Q Exp
loadPParamField :: Field -> Q (Name, Stmt)
buildFromMaybe :: String -> Q Dec
fillParam :: String -> String -> [Field] -> Q [Dec]
Exported types
type Container = Map StringSource
data Field Source
Serialised field data type.
Constructors
Field
fieldName :: String
fieldType :: Q Type
fieldRead :: Maybe (Q Exp)
fieldShow :: Maybe (Q Exp)
fieldDefault :: Maybe (Q Exp)
fieldConstr :: Maybe String
fieldIsContainer :: Bool
fieldIsOptional :: Bool
simpleField :: String -> Q Type -> FieldSource
Generates a simple field.
renameField :: String -> Field -> FieldSource
Sets the renamed constructor field.
defaultField :: Q Exp -> Field -> FieldSource
Sets the default value on a field (makes it optional with a default value).
optionalField :: Field -> FieldSource
Marks a field optional (turning its base type into a Maybe).
containerField :: Field -> FieldSource
Marks a field as a container.
customFieldSource
:: NameThe name of the read function
-> NameThe name of the show function
-> FieldThe original field
-> FieldUpdated field
Sets custom functions on a field.
fieldRecordName :: Field -> StringSource
fieldVariable :: Field -> StringSource
Computes the preferred variable name to use for the value of this field. If the field has a specific constructor name, then we use a first-letter-lowercased version of that; otherwise, we simply use the field name. See also fieldRecordName.
actualFieldType :: Field -> Q TypeSource
checkNonOptDef :: Monad m => Field -> m ()Source
loadFnSource
:: FieldThe field definition
-> Q ExpThe value of the field as existing in the JSON message
-> Q ExpThe entire object in JSON object format
-> Q ExpResulting expression
Produces the expression that will de-serialise a given field. Since some custom parsing functions might need to use the entire object, we do take and pass the object to any custom read functions.
Common field declarations
timeStampFields :: [Field]Source
serialFields :: [Field]Source
uuidFields :: [Field]Source
Helper functions
ensureLower :: String -> StringSource

Ensure first letter is lowercase.

Used to convert type name to function prefix, e.g. in data Aa -> aaToRaw.

ensureUpper :: String -> StringSource

Ensure first letter is uppercase.

Used to convert constructor name to component

varNameE :: String -> Q ExpSource
Helper for quoted expressions.
showJSONE :: Q ExpSource
showJSON as an expression, for reuse.
toRawName :: String -> NameSource
ToRaw function name.
fromRawName :: String -> NameSource
FromRaw function name.
reprE :: Either String Name -> Q ExpSource
Converts a name to it's varE/litE representations.
appFn :: Exp -> Exp -> ExpSource

Smarter function application.

This does simply f x, except that if is id, it will skip it, in order to generate more readable code when using -ddump-splices.

readContainer :: (Monad m, JSON a) => JSObject JSValue -> m (Container a)Source
Container loader
showContainer :: JSON a => Container a -> JSValueSource
Container dumper
Template code for simple raw type-equivalent ADTs
strADTDecl :: Name -> [String] -> DecSource

Generates a data type declaration.

The type will have a fixed list of instances.

genToRaw :: Name -> Name -> Name -> [(String, Either String Name)] -> Q [Dec]Source

Generates a toRaw function.

This generates a simple function of the form:

 nameToRaw :: Name -> traw
 nameToRaw Cons1 = var1
 nameToRaw Cons2 = "value2"
genFromRaw :: Name -> Name -> Name -> [(String, Name)] -> Q [Dec]Source

Generates a fromRaw function.

The function generated is monadic and can fail parsing the raw value. It is of the form:

 nameFromRaw :: (Monad m) => traw -> m Name
 nameFromRaw s | s == var1       = Cons1
               | s == "value2" = Cons2
               | otherwise = fail ...
declareADT :: Name -> String -> [(String, Name)] -> Q [Dec]Source

Generates a data type from a given raw format.

The format is expected to multiline. The first line contains the type name, and the rest of the lines must contain two words: the constructor name and then the string representation of the respective constructor.

The function will generate the data type declaration, and then two functions:

  • nameToRaw, which converts the type to a raw type
  • nameFromRaw, which (monadically) converts from a raw type to the type

Note that this is basically just a custom show/read instance, nothing else.

declareIADT :: String -> [(String, Name)] -> Q [Dec]Source
declareSADT :: String -> [(String, Name)] -> Q [Dec]Source
genShowJSON :: String -> Q DecSource

Creates the showJSON member of a JSON instance declaration.

This will create what is the equivalent of:

 showJSON = showJSON . nameToRaw

in an instance JSON name declaration

genReadJSON :: String -> Q DecSource

Creates the readJSON member of a JSON instance declaration.

This will create what is the equivalent of:

 readJSON s = case readJSON s of
                Ok s' -> nameFromRaw s'
                Error e -> Error description

in an instance JSON name declaration

makeJSONInstance :: Name -> Q [Dec]Source

Generates a JSON instance for a given type.

This assumes that the nameToRaw and nameFromRaw functions have been defined as by the declareSADT function.

Template code for opcodes
deCamelCase :: String -> StringSource
Transforms a CamelCase string into an_underscore_based_one.
camelCase :: String -> StringSource
Transform an underscore_name into a CamelCase one.
constructorName :: Con -> Q NameSource
Computes the name of a given constructor.
genConstrToStr :: (String -> String) -> Name -> String -> Q [Dec]Source

Builds the generic constructor-to-string function.

This generates a simple function of the following form:

 fname (ConStructorOne {}) = trans_fun(ConStructorOne)
 fname (ConStructorTwo {}) = trans_fun(ConStructorTwo)

This builds a custom list of name/string pairs and then uses genToRaw to actually generate the function

genOpID :: Name -> String -> Q [Dec]Source
Constructor-to-string for OpCode.
type OpParam = (String, Q Type, Q Exp)Source
OpCode parameter (field) type.
genOpCodeSource
:: StringType name to use
-> [(String, [Field])]Constructor name and parameters
-> Q [Dec]

Generates the OpCode data type.

This takes an opcode logical definition, and builds both the datatype and the JSON serialisation out of it. We can't use a generic serialisation since we need to be compatible with Ganeti's own, so we have a few quirks to work around.

isOptional :: Type -> BoolSource

Checks whether a given parameter is options.

This requires that it's a Maybe.

saveConstructorSource
:: StringThe constructor name
-> [Field]The parameter definitions for this constructor
-> Q ClauseResulting clause

Generates the "save" clause for an entire opcode constructor.

This matches the opcode with variables named the same as the constructor fields (just so that the spliced in code looks nicer), and passes those name plus the parameter definition to saveObjectField.

genSaveOpCode :: [(String, [Field])] -> Q (Dec, Dec)Source

Generates the main save opcode function.

This builds a per-constructor match clause that contains the respective constructor-serialisation code.

loadConstructor :: String -> [Field] -> Q ExpSource
genLoadOpCode :: [(String, [Field])] -> Q (Dec, Dec)Source
Template code for luxi
genStrOfOp :: Name -> String -> Q [Dec]Source
Constructor-to-string for LuxiOp.
genStrOfKey :: Name -> String -> Q [Dec]Source
Constructor-to-string for MsgKeys.
type LuxiParam = (String, Q Type, Q Exp)Source
LuxiOp parameter type.
genLuxiOp :: String -> [(String, [LuxiParam])] -> Q [Dec]Source

Generates the LuxiOp data type.

This takes a Luxi operation definition and builds both the datatype and the function trnasforming the arguments to JSON. We can't use anything less generic, because the way different operations are serialized differs on both parameter- and top-level.

There are three things to be defined for each parameter:

  • name
  • type
  • operation; this is the operation performed on the parameter before serialization
saveLuxiField :: Name -> LuxiParam -> Q ExpSource
Generates the "save" expression for a single luxi parameter.
saveLuxiConstructor :: (String, [LuxiParam]) -> Q ClauseSource
Generates the "save" clause for entire LuxiOp constructor.
genSaveLuxiOp :: [(String, [LuxiParam])] -> Q (Dec, Dec)Source
Generates the main save LuxiOp function.
Objects functionality
fieldTypeInfo :: String -> Field -> Q (Name, Strict, Type)Source
Extract the field's declaration from a Field structure.
buildObject :: String -> String -> [Field] -> Q [Dec]Source
Build an object declaration.
buildObjectSerialisation :: String -> [Field] -> Q [Dec]Source
genSaveObject :: (Name -> Field -> Q Exp) -> String -> [Field] -> Q [Dec]Source
saveObjectField :: Name -> Field -> Q ExpSource
objectShowJSON :: String -> Q DecSource
genLoadObject :: (Field -> Q (Name, Stmt)) -> String -> [Field] -> Q (Dec, Dec)Source
loadObjectField :: Field -> Q (Name, Stmt)Source
objectReadJSON :: String -> Q DecSource
Inheritable parameter tables implementation
paramTypeNames :: String -> (String, String)Source
Compute parameter type names.
paramFieldTypeInfo :: String -> Field -> Q (Name, Strict, Type)Source
Compute information about the type of a parameter field.
buildParam :: String -> String -> [Field] -> Q [Dec]Source

Build a parameter declaration.

This function builds two different data structures: a filled one, in which all fields are required, and a partial one, in which all fields are optional. Due to the current record syntax issues, the fields need to be named differrently for the two structures, so the partial ones get a P suffix.

buildPParamSerialisation :: String -> [Field] -> Q [Dec]Source
savePParamField :: Name -> Field -> Q ExpSource
loadPParamField :: Field -> Q (Name, Stmt)Source
buildFromMaybe :: String -> Q DecSource
Builds a simple declaration of type n_x = fromMaybe f_x p_x.
fillParam :: String -> String -> [Field] -> Q [Dec]Source
Produced by Haddock version 2.6.0