Revision 9b156883 htools/Ganeti/THH.hs
b/htools/Ganeti/THH.hs | ||
---|---|---|
42 | 42 |
, simpleField |
43 | 43 |
, defaultField |
44 | 44 |
, optionalField |
45 |
, optionalNullSerField |
|
45 | 46 |
, renameField |
46 | 47 |
, customField |
47 | 48 |
, timeStampFields |
... | ... | |
74 | 75 |
class DictObject a where |
75 | 76 |
toDict :: a -> [(String, JSON.JSValue)] |
76 | 77 |
|
78 |
-- | Optional field information. |
|
79 |
data OptionalType |
|
80 |
= NotOptional -- ^ Field is not optional |
|
81 |
| OptionalOmitNull -- ^ Field is optional, null is not serialised |
|
82 |
| OptionalSerializeNull -- ^ Field is optional, null is serialised |
|
83 |
deriving (Show, Eq) |
|
84 |
|
|
77 | 85 |
-- | Serialised field data type. |
78 | 86 |
data Field = Field { fieldName :: String |
79 | 87 |
, fieldType :: Q Type |
... | ... | |
81 | 89 |
, fieldShow :: Maybe (Q Exp) |
82 | 90 |
, fieldDefault :: Maybe (Q Exp) |
83 | 91 |
, fieldConstr :: Maybe String |
84 |
, fieldIsOptional :: Bool
|
|
92 |
, fieldIsOptional :: OptionalType
|
|
85 | 93 |
} |
86 | 94 |
|
87 | 95 |
-- | Generates a simple field. |
... | ... | |
93 | 101 |
, fieldShow = Nothing |
94 | 102 |
, fieldDefault = Nothing |
95 | 103 |
, fieldConstr = Nothing |
96 |
, fieldIsOptional = False
|
|
104 |
, fieldIsOptional = NotOptional
|
|
97 | 105 |
} |
98 | 106 |
|
99 | 107 |
-- | Sets the renamed constructor field. |
... | ... | |
107 | 115 |
|
108 | 116 |
-- | Marks a field optional (turning its base type into a Maybe). |
109 | 117 |
optionalField :: Field -> Field |
110 |
optionalField field = field { fieldIsOptional = True } |
|
118 |
optionalField field = field { fieldIsOptional = OptionalOmitNull } |
|
119 |
|
|
120 |
-- | Marks a field optional (turning its base type into a Maybe), but |
|
121 |
-- with 'Nothing' serialised explicitly as /null/. |
|
122 |
optionalNullSerField :: Field -> Field |
|
123 |
optionalNullSerField field = field { fieldIsOptional = OptionalSerializeNull } |
|
111 | 124 |
|
112 | 125 |
-- | Sets custom functions on a field. |
113 | 126 |
customField :: Name -- ^ The name of the read function |
... | ... | |
134 | 147 |
Just name -> ensureLower name |
135 | 148 |
_ -> map (\c -> if c == '-' then '_' else c) $ fieldName f |
136 | 149 |
|
150 |
-- | Compute the actual field type (taking into account possible |
|
151 |
-- optional status). |
|
137 | 152 |
actualFieldType :: Field -> Q Type |
138 |
actualFieldType f | fieldIsOptional f = [t| Maybe $t |]
|
|
153 |
actualFieldType f | fieldIsOptional f /= NotOptional = [t| Maybe $t |]
|
|
139 | 154 |
| otherwise = t |
140 | 155 |
where t = fieldType f |
141 | 156 |
|
157 |
-- | Checks that a given field is not optional (for object types or |
|
158 |
-- fields which should not allow this case). |
|
142 | 159 |
checkNonOptDef :: (Monad m) => Field -> m () |
143 |
checkNonOptDef (Field { fieldIsOptional = True, fieldName = name }) = |
|
160 |
checkNonOptDef (Field { fieldIsOptional = OptionalOmitNull |
|
161 |
, fieldName = name }) = |
|
162 |
fail $ "Optional field " ++ name ++ " used in parameter declaration" |
|
163 |
checkNonOptDef (Field { fieldIsOptional = OptionalSerializeNull |
|
164 |
, fieldName = name }) = |
|
144 | 165 |
fail $ "Optional field " ++ name ++ " used in parameter declaration" |
145 | 166 |
checkNonOptDef (Field { fieldDefault = (Just _), fieldName = name }) = |
146 | 167 |
fail $ "Default field " ++ name ++ " used in parameter declaration" |
... | ... | |
681 | 702 |
-- | Generates the code for saving an object's field, handling the |
682 | 703 |
-- various types of fields that we have. |
683 | 704 |
saveObjectField :: Name -> Field -> Q Exp |
684 |
saveObjectField fvar field |
|
685 |
| fisOptional = [| case $(varE fvar) of |
|
686 |
Nothing -> [] |
|
687 |
Just v -> [( $nameE, JSON.showJSON v)] |
|
688 |
|] |
|
689 |
| otherwise = case fieldShow field of |
|
690 |
Nothing -> [| [( $nameE, JSON.showJSON $fvarE)] |] |
|
691 |
Just fn -> [| let (actual, extra) = $fn $fvarE |
|
692 |
in extra ++ [( $nameE, JSON.showJSON actual)] |
|
693 |
|] |
|
694 |
where fisOptional = fieldIsOptional field |
|
695 |
nameE = stringE (fieldName field) |
|
705 |
saveObjectField fvar field = |
|
706 |
case fieldIsOptional field of |
|
707 |
OptionalOmitNull -> [| case $(varE fvar) of |
|
708 |
Nothing -> [] |
|
709 |
Just v -> [( $nameE, JSON.showJSON v )] |
|
710 |
|] |
|
711 |
OptionalSerializeNull -> [| case $(varE fvar) of |
|
712 |
Nothing -> [( $nameE, JSON.JSNull )] |
|
713 |
Just v -> [( $nameE, JSON.showJSON v )] |
|
714 |
|] |
|
715 |
NotOptional -> |
|
716 |
case fieldShow field of |
|
717 |
Nothing -> [| [( $nameE, JSON.showJSON $fvarE)] |] |
|
718 |
Just fn -> [| let (actual, extra) = $fn $fvarE |
|
719 |
in extra ++ [( $nameE, JSON.showJSON actual)] |
|
720 |
|] |
|
721 |
where nameE = stringE (fieldName field) |
|
696 | 722 |
fvarE = varE fvar |
697 | 723 |
|
698 | 724 |
-- | Generates the showJSON clause for a given object name. |
... | ... | |
729 | 755 |
let objvar = varNameE "o" |
730 | 756 |
objfield = stringE (fieldName field) |
731 | 757 |
loadexp = |
732 |
if fieldIsOptional field |
|
758 |
if fieldIsOptional field /= NotOptional |
|
759 |
-- we treat both optional types the same, since |
|
760 |
-- 'maybeFromObj' can deal with both missing and null values |
|
761 |
-- appropriately (the same) |
|
733 | 762 |
then [| $(varNameE "maybeFromObj") $objvar $objfield |] |
734 | 763 |
else case fieldDefault field of |
735 | 764 |
Just defv -> |
Also available in: Unified diff