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