[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 10/11] qapi: golang: Add CommandResult type to Go
From: |
Victor Toso |
Subject: |
[PATCH v2 10/11] qapi: golang: Add CommandResult type to Go |
Date: |
Mon, 16 Oct 2023 17:27:03 +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 {
| MessageId 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 | 104 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 92 insertions(+), 12 deletions(-)
diff --git a/scripts/qapi/golang.py b/scripts/qapi/golang.py
index 624bc2af4d..6471ddeb52 100644
--- a/scripts/qapi/golang.py
+++ b/scripts/qapi/golang.py
@@ -39,6 +39,15 @@
"""
TEMPLATE_HELPER = """
+type QAPIError struct {
+\tClass string `json:"class"`
+\tDescription string `json:"desc"`
+}
+
+func (err *QAPIError) Error() string {
+\treturn err.Description
+}
+
// Creates a decoder that errors on unknown Fields
// Returns nil if successfully decoded @from payload to @into type
// Returns error if failed to decode @from payload to @into type
@@ -271,12 +280,17 @@
func (s *{type_name}) GetId() string {{
\treturn s.MessageId
}}
+
+func (s *{type_name}) GetReturnType() CommandReturn {{
+\treturn &{cmd_ret_name}{{}}
+}}
"""
TEMPLATE_COMMAND = """
type Command interface {{
\tGetId() string
\tGetName() string
+\tGetReturnType() CommandReturn
}}
func MarshalCommand(c Command) ([]byte, error) {{
@@ -308,6 +322,37 @@
}}
"""
+TEMPLATE_COMMAND_RETURN = """
+type CommandReturn interface {
+\tGetId() string
+\tGetCommandName() string
+\tGetError() error
+}
+"""
+
+TEMPLATE_COMMAND_RETURN_METHODS = """
+func (r *{cmd_ret_name}) GetCommandName() string {{
+\treturn "{name}"
+}}
+
+func (r *{cmd_ret_name}) GetId() string {{
+\treturn r.MessageId
+}}
+
+func (r *{cmd_ret_name}) GetError() error {{
+\treturn r.Error
+}}{marshal_empty}
+"""
+
+TEMPLATE_COMMAND_RETURN_MARSHAL_EMPTY = """
+func (r {cmd_ret_name}) MarshalJSON() ([]byte, error) {{
+\tif r.Error != nil {{
+\t\ttype Alias {cmd_ret_name}
+\t\treturn json.Marshal(Alias(r))
+\t}}
+\treturn []byte(`{{"return":{{}}}}`), nil
+}}"""
+
def gen_golang(schema: QAPISchema, output_dir: str, prefix: str) -> None:
vis = QAPISchemaGenGolangVisitor(prefix)
@@ -346,7 +391,7 @@ def qapi_to_go_type_name(name: str, meta: Optional[str] =
None) -> str:
name += "".join(word.title() for word in words[1:])
- types = ["event", "command"]
+ types = ["event", "command", "command return"]
if meta in types:
name = name[:-3] if name.endswith("Arg") else name
name += meta.title().replace(" ", "")
@@ -943,18 +988,19 @@ def generate_template_command(commands: dict[str,
Tuple[str, str]]) -> str:
case_type, gocode = commands[name]
content += gocode
cases += f"""
-case "{name}":
- command := struct {{
- Args {case_type} `json:"arguments"`
- }}{{}}
-
- if err := json.Unmarshal(data, &command); err != nil {{
- return nil, fmt.Errorf("Failed to unmarshal: %s", string(data))
- }}
- command.Args.MessageId = base.MessageId
- return &command.Args, nil
+\tcase "{name}":
+\t\tcommand := struct {{
+\t\t\tArgs {case_type} `json:"arguments"`
+\t\t}}{{}}
+
+\t\tif err := json.Unmarshal(data, &command); err != nil {{
+\t\t\treturn nil, fmt.Errorf("Failed to unmarshal: %s", string(data))
+\t\t}}
+\t\tcommand.Args.MessageId = base.MessageId
+\t\treturn &command.Args, nil
"""
content += TEMPLATE_COMMAND.format(cases=cases)
+ content += TEMPLATE_COMMAND_RETURN
return content
@@ -1182,6 +1228,34 @@ def visit_command(
type_name = qapi_to_go_type_name(name, info.defn_meta)
+ cmd_ret_name = qapi_to_go_type_name(name, "command return")
+ marshal_empty = TEMPLATE_COMMAND_RETURN_MARSHAL_EMPTY.format(
+ cmd_ret_name=cmd_ret_name
+ )
+ retargs: List[dict[str:str]] = [
+ {
+ "name": "MessageId",
+ "type": "string",
+ "tag": """`json:"id,omitempty"`""",
+ },
+ {
+ "name": "Error",
+ "type": "*QAPIError",
+ "tag": """`json:"error,omitempty"`""",
+ },
+ ]
+ if ret_type:
+ marshal_empty = ""
+ ret_type_name = qapi_schema_type_to_go_type(ret_type.name)
+ isptr = "*" if ret_type_name[0] not in "*[" else ""
+ retargs.append(
+ {
+ "name": "Result",
+ "type": f"{isptr}{ret_type_name}",
+ "tag": """`json:"return"`""",
+ }
+ )
+
content = ""
if boxed or not arg_type or not qapi_name_is_object(arg_type.name):
args: List[dict[str:str]] = []
@@ -1213,7 +1287,13 @@ def visit_command(
)
content += TEMPLATE_COMMAND_METHODS.format(
- name=name, type_name=type_name
+ name=name, type_name=type_name, cmd_ret_name=cmd_ret_name
+ )
+ content += generate_struct_type(cmd_ret_name, retargs)
+ content += TEMPLATE_COMMAND_RETURN_METHODS.format(
+ name=name,
+ cmd_ret_name=cmd_ret_name,
+ marshal_empty=marshal_empty,
)
self.commands[name] = (type_name, content)
--
2.41.0
- [PATCH v2 05/11] qapi: golang: Generate qapi's struct types in Go, (continued)
[PATCH v2 08/11] qapi: golang: Generate qapi's event types in Go, Victor Toso, 2023/10/16
[PATCH v2 07/11] qapi: golang: Generate qapi's union types in Go, Victor Toso, 2023/10/16
[PATCH v2 09/11] qapi: golang: Generate qapi's command types in Go, Victor Toso, 2023/10/16
[PATCH v2 10/11] qapi: golang: Add CommandResult type to Go,
Victor Toso <=
[PATCH v2 11/11] docs: add notes on Golang code generator, Victor Toso, 2023/10/16
[PATCH v2 06/11] qapi: golang: structs: Address 'null' members, Victor Toso, 2023/10/16
Re: [PATCH v2 00/11] qapi-go: add generator for Golang interface, Victor Toso, 2023/10/27