Revision 72375ff8 src/Ganeti/THH.hs

b/src/Ganeti/THH.hs
50 50
                  , Field (..)
51 51
                  , simpleField
52 52
                  , andRestArguments
53
                  , specialNumericalField
54
                  , timeAsDoubleField
55 53
                  , withDoc
56 54
                  , defaultField
57 55
                  , optionalField
58 56
                  , optionalNullSerField
59 57
                  , renameField
60 58
                  , customField
61
                  , timeStampFields
62
                  , uuidFields
63
                  , serialFields
64
                  , tagsFields
65
                  , TagSet
66 59
                  , buildObject
67 60
                  , buildObjectSerialisation
68 61
                  , buildParam
......
80 73
import Data.List
81 74
import Data.Maybe
82 75
import qualified Data.Map as M
83
import qualified Data.Set as Set
84 76
import Language.Haskell.TH
85 77
import Language.Haskell.TH.Syntax (lift)
86
import System.Time (ClockTime(..))
87 78

  
88 79
import qualified Text.JSON as JSON
89 80
import Text.JSON.Pretty (pp_value)
......
228 219
optionalNullSerField :: Field -> Field
229 220
optionalNullSerField field = field { fieldIsOptional = OptionalSerializeNull }
230 221

  
231
-- | Wrapper around a special parse function, suitable as field-parsing
232
-- function.
233
numericalReadFn :: JSON.JSON a => (String -> JSON.Result a)
234
                   -> [(String, JSON.JSValue)] -> JSON.JSValue -> JSON.Result a
235
numericalReadFn _ _ v@(JSON.JSRational _ _) = JSON.readJSON v
236
numericalReadFn f _ (JSON.JSString x) = f $ JSON.fromJSString x
237
numericalReadFn _ _ _ = JSON.Error "A numerical field has to be a number or\
238
                                   \ a string."
239

  
240
-- | Sets the read function to also accept string parsable by the given
241
-- function.
242
specialNumericalField :: Name -> Field -> Field
243
specialNumericalField f field =
244
     field { fieldRead = Just (appE (varE 'numericalReadFn) (varE f)) }
245

  
246
-- | Creates a new mandatory field that reads time as the (floating point)
247
-- number of seconds since the standard UNIX epoch, and represents it in
248
-- Haskell as 'ClockTime'.
249
timeAsDoubleField :: String -> Field
250
timeAsDoubleField fname =
251
  (simpleField fname [t| ClockTime |])
252
    { fieldRead = Just $ [| \_ -> liftM unTimeAsDoubleJSON . JSON.readJSON |]
253
    , fieldShow = Just $ [| \c -> (JSON.showJSON $ TimeAsDoubleJSON c, []) |]
254
    }
255

  
256 222
-- | Sets custom functions on a field.
257 223
customField :: Name      -- ^ The name of the read function
258 224
            -> Name      -- ^ The name of the show function
......
335 301
loadFnOpt field expr o
336 302
  = [| $expr >>= maybe (return Nothing) (liftM Just . $(parseFn field o)) |]
337 303

  
338
-- * Common field declarations
339

  
340
-- | Timestamp fields description.
341
timeStampFields :: [Field]
342
timeStampFields = map (defaultField [| TOD 0 0 |] . timeAsDoubleField)
343
                      ["ctime", "mtime"]
344

  
345

  
346
-- | Serial number fields description.
347
serialFields :: [Field]
348
serialFields =
349
    [ renameField  "Serial" $ simpleField "serial_no" [t| Int |] ]
350

  
351
-- | UUID fields description.
352
uuidFields :: [Field]
353
uuidFields = [ simpleField "uuid" [t| String |] ]
354

  
355
-- | Tag set type alias.
356
type TagSet = Set.Set String
357

  
358
-- | Tag field description.
359
tagsFields :: [Field]
360
tagsFields = [ defaultField [| Set.empty |] $
361
               simpleField "tags" [t| TagSet |] ]
362

  
363 304
-- * Internal types
364 305

  
365 306
-- | A simple field, in constrast to the customisable 'Field' type.

Also available in: Unified diff