[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH v2 7/8] qapi: golang: Add CommandResult type to Go
From: |
Victor Toso |
Subject: |
[RFC PATCH v2 7/8] qapi: golang: Add CommandResult type to Go |
Date: |
Fri, 17 Jun 2022 14:19:31 +0200 |
This patch adds a struct type in Go that will handle return values for
QAPI's command types.
The return value of a Command is, encouraged to be, QAPI's complex
types or an Array of those.
Every Command has a underlying CommandResult. The EmptyCommandReturn
is for those that don't expect any data e.g: `{ "return": {} }`.
All CommandReturn types implement the CommandResult interface.
Example:
qapi:
| { 'command': 'query-sev', 'returns': 'SevInfo',
| 'if': 'TARGET_I386' }
go:
| type QuerySevCommandReturn struct {
| CommandId string `json:"id,omitempty"`
| Result *SevInfo `json:"return"`
| Error *QapiError `json:"error,omitempty"`
| }
usage:
| // One can use QuerySevCommandReturn directly or
| // command's interface GetReturnType() instead.
|
| input := `{ "return": { "enabled": true, "api-major" : 0,` +
| `"api-minor" : 0, "build-id" : 0,` +
| `"policy" : 0, "state" : "running",` +
| `"handle" : 1 } } `
| ret := QuerySevCommandReturn{}
| err := json.Unmarshal([]byte(input), &ret)
| if ret.Error != nil {
| // Handle command failure {"error": { ...}}
| } else if ret.Result != nil {
| // ret.Result.Enable == true
| }
Signed-off-by: Victor Toso <victortoso@redhat.com>
---
scripts/qapi/golang.py | 73 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 70 insertions(+), 3 deletions(-)
diff --git a/scripts/qapi/golang.py b/scripts/qapi/golang.py
index 123179cced..ab91cf124f 100644
--- a/scripts/qapi/golang.py
+++ b/scripts/qapi/golang.py
@@ -89,7 +89,8 @@
}}
'''
-# Only variable is @unm_cases to handle all command's names and associated
types.
+# Only variable is @unm_cases to handle
+# all command's names and associated types.
TEMPLATE_COMMAND = '''
type Command interface {{
GetId() string
@@ -145,10 +146,49 @@
}}
'''
+TEMPLATE_COMMAND_RETURN = '''
+type CommandReturn interface {
+ GetId() string
+ GetCommandName() string
+ GetError() error
+}
+
+type EmptyCommandReturn struct {
+ CommandId string `json:"id,omitempty"`
+ Error *QapiError `json:"error,omitempty"`
+ Name string `json:"-"`
+}
+
+func (r EmptyCommandReturn) MarshalJSON() ([]byte, error) {
+ return []byte(`{"return":{}}`), nil
+}
+
+func (r *EmptyCommandReturn) GetId() string {
+ return r.CommandId
+}
+
+func (r *EmptyCommandReturn) GetCommandName() string {
+ return r.Name
+}
+
+func (r *EmptyCommandReturn) GetError() error {
+ return r.Error
+}
+'''
+
TEMPLATE_HELPER = '''
// Alias for go version lower than 1.18
type Any = interface{}
+type QapiError struct {
+ Class string `json:"class"`
+ Description string `json:"desc"`
+}
+
+func (err *QapiError) Error() string {
+ return fmt.Sprintf("%s: %s", err.Class, err.Description)
+}
+
// Creates a decoder that errors on unknown Fields
// Returns true if successfully decoded @from string @into type
// Returns false without error is failed with "unknown field"
@@ -176,6 +216,7 @@ def __init__(self, prefix: str):
self.schema = None
self.events = {}
self.commands = {}
+ self.command_results = {}
self.golang_package_name = "qapi"
def visit_begin(self, schema):
@@ -224,6 +265,7 @@ def visit_end(self):
'''
self.target["command"] += TEMPLATE_COMMAND.format(unm_cases=unm_cases)
+ self.target["command"] += TEMPLATE_COMMAND_RETURN
def visit_object_type(self: QAPISchemaGenGolangVisitor,
name: str,
@@ -390,6 +432,31 @@ def visit_command(self,
self.commands[name] = type_name
command_ret = ""
init_ret_type_name = f'''EmptyCommandReturn {{ Name: "{name}" }}'''
+ if ret_type:
+ cmd_ret_name = qapi_to_go_type_name(name, "command return")
+ ret_type_name = qapi_schema_type_to_go_type(ret_type.name)
+ init_ret_type_name = f'''{cmd_ret_name}{{}}'''
+ isptr = "*" if ret_type_name[0] not in "*[" else ""
+ self.command_results[name] = ret_type_name
+ command_ret = f'''
+type {cmd_ret_name} struct {{
+ CommandId string `json:"id,omitempty"`
+ Result {isptr}{ret_type_name} `json:"return"`
+ Error *QapiError `json:"error,omitempty"`
+}}
+
+func (r *{cmd_ret_name}) GetCommandName() string {{
+ return "{name}"
+}}
+
+func (r *{cmd_ret_name}) GetId() string {{
+ return r.CommandId
+}}
+
+func (r *{cmd_ret_name}) GetError() error {{
+ return r.Error
+}}
+'''
self_contained = True
if arg_type and arg_type.name.startswith("q_obj"):
@@ -423,7 +490,7 @@ def visit_command(self,
return &{init_ret_type_name}
}}
'''
- self.target["command"] += content + methods
+ self.target["command"] += content + methods + command_ret
def visit_event(self, name, info, ifcond, features, arg_type, boxed):
assert name == info.defn_name
@@ -686,7 +753,7 @@ def qapi_to_go_type_name(name: str, meta: str) -> str:
name += ''.join(word.title() for word in words[1:])
- if meta in ["event", "command"]:
+ if meta in ["event", "command", "command return"]:
name = name[:-3] if name.endswith("Arg") else name
name += meta.title().replace(" ", "")
--
2.36.1
- [RFC PATCH v2 0/8] qapi: add generator for Golang interface, Victor Toso, 2022/06/17
- [RFC PATCH v2 2/8] qapi: golang: Generate qapi's alternate types in Go, Victor Toso, 2022/06/17
- [RFC PATCH v2 3/8] qapi: golang: Generate qapi's struct types in Go, Victor Toso, 2022/06/17
- [RFC PATCH v2 4/8] qapi: golang: Generate qapi's union types in Go, Victor Toso, 2022/06/17
- [RFC PATCH v2 5/8] qapi: golang: Generate qapi's event types in Go, Victor Toso, 2022/06/17
- [RFC PATCH v2 6/8] qapi: golang: Generate qapi's command types in Go, Victor Toso, 2022/06/17
- [RFC PATCH v2 8/8] qapi: golang: document skip function visit_array_types, Victor Toso, 2022/06/17
- [RFC PATCH v2 7/8] qapi: golang: Add CommandResult type to Go,
Victor Toso <=
- [RFC PATCH v2 1/8] qapi: golang: Generate qapi's enum types in Go, Victor Toso, 2022/06/17
- Re: [RFC PATCH v2 0/8] qapi: add generator for Golang interface, Markus Armbruster, 2022/06/27