From 88609f00af9f9169677d7c897040bf06908cc4b7 Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Thu, 8 Nov 2012 13:26:40 +0100
Subject: [PATCH] Switch Luxi TH code from simple to custom fields

This is needed so that we have more flexibility in generating Luxi
serialisation code (deserialisation is still custom). Also, only
exceptions are now using the 'simple' field types, so we might be able
later to convert and remove that TH code as well.

Since we will use custom serialisation fields in the future, we change
the order of serialisation for custom-save fields; Luxi uses
positional as opposed to name-based ordering, so we need to keep this
stable.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Helga Velroyen <helgav@google.com>
---
 htools/Ganeti/Luxi.hs | 68 +++++++++++++++++++++----------------------
 htools/Ganeti/THH.hs  | 33 +++++++++++++--------
 2 files changed, 55 insertions(+), 46 deletions(-)

diff --git a/htools/Ganeti/Luxi.hs b/htools/Ganeti/Luxi.hs
index b933eb5c3..622eceb6c 100644
--- a/htools/Ganeti/Luxi.hs
+++ b/htools/Ganeti/Luxi.hs
@@ -101,73 +101,73 @@ type JobId = Int
 -- | Currently supported Luxi operations and JSON serialization.
 $(genLuxiOp "LuxiOp"
   [ (luxiReqQuery,
-    [ ("what",    [t| Qlang.ItemType |])
-    , ("fields",  [t| [String]  |])
-    , ("qfilter", [t| Qlang.Filter Qlang.FilterField |])
+    [ simpleField "what"    [t| Qlang.ItemType |]
+    , simpleField "fields"  [t| [String]  |]
+    , simpleField "qfilter" [t| Qlang.Filter Qlang.FilterField |]
     ])
   , (luxiReqQueryFields,
-    [ ("what",    [t| Qlang.ItemType |])
-    , ("fields",  [t| [String]  |])
+    [ simpleField "what"    [t| Qlang.ItemType |]
+    , simpleField "fields"  [t| [String]  |]
     ])
   , (luxiReqQueryNodes,
-     [ ("names",  [t| [String] |])
-     , ("fields", [t| [String] |])
-     , ("lock",   [t| Bool     |])
+     [ simpleField "names"  [t| [String] |]
+     , simpleField "fields" [t| [String] |]
+     , simpleField "lock"   [t| Bool     |]
      ])
   , (luxiReqQueryGroups,
-     [ ("names",  [t| [String] |])
-     , ("fields", [t| [String] |])
-     , ("lock",   [t| Bool     |])
+     [ simpleField "names"  [t| [String] |]
+     , simpleField "fields" [t| [String] |]
+     , simpleField "lock"   [t| Bool     |]
      ])
   , (luxiReqQueryInstances,
-     [ ("names",  [t| [String] |])
-     , ("fields", [t| [String] |])
-     , ("lock",   [t| Bool     |])
+     [ simpleField "names"  [t| [String] |]
+     , simpleField "fields" [t| [String] |]
+     , simpleField "lock"   [t| Bool     |]
      ])
   , (luxiReqQueryJobs,
-     [ ("ids",    [t| [Int]    |])
-     , ("fields", [t| [String] |])
+     [ simpleField "ids"    [t| [Int]    |]
+     , simpleField "fields" [t| [String] |]
      ])
   , (luxiReqQueryExports,
-     [ ("nodes", [t| [String] |])
-     , ("lock",  [t| Bool     |])
+     [ simpleField "nodes" [t| [String] |]
+     , simpleField "lock"  [t| Bool     |]
      ])
   , (luxiReqQueryConfigValues,
-     [ ("fields", [t| [String] |]) ]
+     [ simpleField "fields" [t| [String] |] ]
     )
   , (luxiReqQueryClusterInfo, [])
   , (luxiReqQueryTags,
-     [ ("kind", [t| TagObject |])
-     , ("name", [t| String |])
+     [ simpleField "kind" [t| TagObject |]
+     , simpleField "name" [t| String |]
      ])
   , (luxiReqSubmitJob,
-     [ ("job", [t| [OpCode] |]) ]
+     [ simpleField "job" [t| [OpCode] |] ]
     )
   , (luxiReqSubmitManyJobs,
-     [ ("ops", [t| [[OpCode]] |]) ]
+     [ simpleField "ops" [t| [[OpCode]] |] ]
     )
   , (luxiReqWaitForJobChange,
-     [ ("job",      [t| Int     |])
-     , ("fields",   [t| [String]|])
-     , ("prev_job", [t| JSValue |])
-     , ("prev_log", [t| JSValue |])
-     , ("tmout",    [t| Int     |])
+     [ simpleField "job"      [t| Int     |]
+     , simpleField "fields"   [t| [String]|]
+     , simpleField "prev_job" [t| JSValue |]
+     , simpleField "prev_log" [t| JSValue |]
+     , simpleField "tmout"    [t| Int     |]
      ])
   , (luxiReqArchiveJob,
-     [ ("job", [t| Int |]) ]
+     [ simpleField "job" [t| Int |] ]
     )
   , (luxiReqAutoArchiveJobs,
-     [ ("age",   [t| Int |])
-     , ("tmout", [t| Int |])
+     [ simpleField "age"   [t| Int |]
+     , simpleField "tmout" [t| Int |]
      ])
   , (luxiReqCancelJob,
-     [ ("job", [t| Int |]) ]
+     [ simpleField "job" [t| Int |] ]
     )
   , (luxiReqSetDrainFlag,
-     [ ("flag", [t| Bool |]) ]
+     [ simpleField "flag" [t| Bool |] ]
     )
   , (luxiReqSetWatcherPause,
-     [ ("duration", [t| Double |]) ]
+     [ simpleField "duration" [t| Double |] ]
     )
   ])
 
diff --git a/htools/Ganeti/THH.hs b/htools/Ganeti/THH.hs
index 584c71223..489413d78 100644
--- a/htools/Ganeti/THH.hs
+++ b/htools/Ganeti/THH.hs
@@ -621,11 +621,17 @@ genStrOfKey = genConstrToStr ensureLower
 --
 -- * type
 --
-genLuxiOp :: String -> SimpleObject -> Q [Dec]
+genLuxiOp :: String -> [(String, [Field])] -> Q [Dec]
 genLuxiOp name cons = do
   let tname = mkName name
-  declD <- buildSimpleCons tname cons
-  (savesig, savefn) <- genSaveSimpleObj tname "opToArgs"
+  decl_d <- mapM (\(cname, fields) -> do
+                    -- we only need the type of the field, without Q
+                    fields' <- mapM actualFieldType fields
+                    let fields'' = zip (repeat NotStrict) fields'
+                    return $ NormalC (mkName cname) fields'')
+            cons
+  let declD = DataD [] (mkName name) [] decl_d [''Show, ''Read, ''Eq]
+  (savesig, savefn) <- genSaveOpCode tname "opToArgs"
                          cons saveLuxiConstructor
   req_defs <- declareSADT "LuxiReq" .
               map (\(str, _) -> ("Req" ++ str, mkName ("luxiReq" ++ str))) $
@@ -638,16 +644,16 @@ saveLuxiField fvar (_, qt) =
     [| JSON.showJSON $(varE fvar) |]
 
 -- | Generates the \"save\" clause for entire LuxiOp constructor.
-saveLuxiConstructor :: SimpleConstructor -> Q Clause
+saveLuxiConstructor :: (String, [Field]) -> Q Clause
 saveLuxiConstructor (sname, fields) = do
   let cname = mkName sname
-      fnames = map (mkName . fst) fields
-      pat = conP cname (map varP fnames)
-      flist = map (uncurry saveLuxiField) (zip fnames fields)
-      finval = if null flist
-               then [| JSON.showJSON ()    |]
-               else [| JSON.showJSON $(listE flist) |]
-  clause [pat] (normalB finval) []
+  fnames <- mapM (newName . fieldVariable) fields
+  let pat = conP cname (map varP fnames)
+  let felems = map (uncurry saveObjectField) (zip fnames fields)
+      flist = if null felems
+                then [| JSON.showJSON () |]
+                else [| JSON.showJSON (map snd $ concat $(listE felems)) |]
+  clause [pat] (normalB flist) []
 
 -- * "Objects" functionality
 
@@ -721,9 +727,12 @@ saveObjectField fvar field =
                               |]
     NotOptional ->
       case fieldShow field of
+        -- Note: the order of actual:extra is important, since for
+        -- some serialisation types (e.g. Luxi), we use tuples
+        -- (positional info) rather than object (name info)
         Nothing -> [| [( $nameE, JSON.showJSON $fvarE)] |]
         Just fn -> [| let (actual, extra) = $fn $fvarE
-                      in extra ++ [( $nameE, JSON.showJSON actual)]
+                      in ($nameE, JSON.showJSON actual):extra
                     |]
   where nameE = stringE (fieldName field)
         fvarE = varE fvar
-- 
GitLab