Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / THH / Field.hs @ 6696f1f9

History | View | Annotate | Download (4 kB)

1
{-# LANGUAGE TemplateHaskell #-}
2

    
3
{-| Helpers for creating various kinds of 'Field's.
4

    
5
They aren't directly needed for the Template Haskell code in Ganeti.THH,
6
so better keep them in a separate module.
7

    
8
-}
9

    
10
{-
11

    
12
Copyright (C) 2014 Google Inc.
13

    
14
This program is free software; you can redistribute it and/or modify
15
it under the terms of the GNU General Public License as published by
16
the Free Software Foundation; either version 2 of the License, or
17
(at your option) any later version.
18

    
19
This program is distributed in the hope that it will be useful, but
20
WITHOUT ANY WARRANTY; without even the implied warranty of
21
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22
General Public License for more details.
23

    
24
You should have received a copy of the GNU General Public License
25
along with this program; if not, write to the Free Software
26
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27
02110-1301, USA.
28

    
29
-}
30

    
31
module Ganeti.THH.Field
32
  ( specialNumericalField
33
  , timeAsDoubleField
34
  , timeStampFields
35
  , uuidFields
36
  , serialFields
37
  , TagSet
38
  , tagsFields
39
  , fileModeAsIntField
40
  ) where
41

    
42
import Control.Monad
43
import qualified Data.Set as Set
44
import Language.Haskell.TH
45
import qualified Text.JSON as JSON
46
import System.Posix.Types (FileMode)
47
import System.Time (ClockTime(..))
48

    
49
import Ganeti.JSON
50
import Ganeti.THH
51

    
52
-- * Internal functions
53

    
54
-- | Wrapper around a special parse function, suitable as field-parsing
55
-- function.
56
numericalReadFn :: JSON.JSON a => (String -> JSON.Result a)
57
                   -> [(String, JSON.JSValue)] -> JSON.JSValue -> JSON.Result a
58
numericalReadFn _ _ v@(JSON.JSRational _ _) = JSON.readJSON v
59
numericalReadFn f _ (JSON.JSString x) = f $ JSON.fromJSString x
60
numericalReadFn _ _ _ = JSON.Error "A numerical field has to be a number or\
61
                                   \ a string."
62

    
63
-- | Sets the read function to also accept string parsable by the given
64
-- function.
65
specialNumericalField :: Name -> Field -> Field
66
specialNumericalField f field =
67
     field { fieldRead = Just (appE (varE 'numericalReadFn) (varE f)) }
68

    
69
-- | Creates a new mandatory field that reads time as the (floating point)
70
-- number of seconds since the standard UNIX epoch, and represents it in
71
-- Haskell as 'ClockTime'.
72
timeAsDoubleField :: String -> Field
73
timeAsDoubleField fname =
74
  (simpleField fname [t| ClockTime |])
75
    { fieldRead = Just $ [| \_ -> liftM unTimeAsDoubleJSON . JSON.readJSON |]
76
    , fieldShow = Just $ [| \c -> (JSON.showJSON $ TimeAsDoubleJSON c, []) |]
77
    }
78

    
79
-- | A helper function for creating fields whose Haskell representation is
80
-- 'Integral' and which are serialized as numbers.
81
integralField :: Q Type -> String -> Field
82
integralField typq fname =
83
  let (~->) = appT . appT arrowT  -- constructs an arrow type
84
      (~::) = sigE . varE         -- (f ~:: t) constructs (f :: t)
85
  in (simpleField fname typq)
86
      { fieldRead = Just $
87
        [| \_ -> liftM $('fromInteger ~:: (conT ''Integer ~-> typq))
88
                   . JSON.readJSON |]
89
      , fieldShow = Just $
90
          [| \c -> (JSON.showJSON
91
                    . $('toInteger ~:: (typq ~-> conT ''Integer))
92
                    $ c, []) |]
93
      }
94

    
95
-- * External functions and data types
96

    
97
-- | Timestamp fields description.
98
timeStampFields :: [Field]
99
timeStampFields = map (defaultField [| TOD 0 0 |] . timeAsDoubleField)
100
                      ["ctime", "mtime"]
101

    
102

    
103
-- | Serial number fields description.
104
serialFields :: [Field]
105
serialFields =
106
    [ renameField  "Serial" $ simpleField "serial_no" [t| Int |] ]
107

    
108
-- | UUID fields description.
109
uuidFields :: [Field]
110
uuidFields = [ simpleField "uuid" [t| String |] ]
111

    
112
-- | Tag set type alias.
113
type TagSet = Set.Set String
114

    
115
-- | Tag field description.
116
tagsFields :: [Field]
117
tagsFields = [ defaultField [| Set.empty |] $
118
               simpleField "tags" [t| TagSet |] ]
119

    
120
-- ** Fields related to POSIX data types
121

    
122
-- | Creates a new mandatory field that reads a file mode in the standard
123
-- POSIX file mode representation. The Haskell type of the field is 'FileMode'.
124
fileModeAsIntField :: String -> Field
125
fileModeAsIntField = integralField [t| FileMode |]