[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v1 3/9] qapi: golang: Generate qapi's struct types in Go
From: |
Victor Toso |
Subject: |
Re: [PATCH v1 3/9] qapi: golang: Generate qapi's struct types in Go |
Date: |
Fri, 29 Sep 2023 15:29:34 +0200 |
Hi,
On Thu, Sep 28, 2023 at 03:06:23PM +0100, Daniel P. Berrangé wrote:
> On Wed, Sep 27, 2023 at 01:25:38PM +0200, Victor Toso wrote:
> > This patch handles QAPI struct types and generates the equivalent
> > types in Go. The following patch adds extra logic when a member of the
> > struct has a Type that can take JSON Null value (e.g: StrOrNull in
> > QEMU)
> >
> > The highlights of this implementation are:
> >
> > 1. Generating an Go struct that requires a @base type, the @base type
> > fields are copied over to the Go struct. The advantage of this
> > approach is to not have embed structs in any of the QAPI types.
> > Note that embedding a @base type is recursive, that is, if the
> > @base type has a @base, all of those fields will be copied over.
> >
> > 2. About the Go struct's fields:
> >
> > i) They can be either by Value or Reference.
> >
> > ii) Every field that is marked as optional in the QAPI specification
> > are translated to Reference fields in its Go structure. This
> > design decision is the most straightforward way to check if a
> > given field was set or not. Exception only for types that can
> > take JSON Null value.
> >
> > iii) Mandatory fields are always by Value with the exception of QAPI
> > arrays, which are handled by Reference (to a block of memory) by
> > Go.
> >
> > iv) All the fields are named with Uppercase due Golang's export
> > convention.
> >
> > v) In order to avoid any kind of issues when encoding or decoding,
> > to or from JSON, we mark all fields with its @name and, when it is
> > optional, member, with @omitempty
> >
> > Example:
> >
> > qapi:
> > | { 'struct': 'BlockdevCreateOptionsFile',
> > | 'data': { 'filename': 'str',
> > | 'size': 'size',
> > | '*preallocation': 'PreallocMode',
> > | '*nocow': 'bool',
> > | '*extent-size-hint': 'size'} }
> >
> > go:
> > | type BlockdevCreateOptionsFile struct {
> > | Filename string `json:"filename"`
> > | Size uint64 `json:"size"`
> > | Preallocation *PreallocMode `json:"preallocation,omitempty"`
> > | Nocow *bool `json:"nocow,omitempty"`
> > | ExtentSizeHint *uint64 `json:"extent-size-hint,omitempty"`
> > | }
>
> Note, 'omitempty' shouldn't be used on pointer fields, only
> scalar fields. The pointer fields are always omitted when nil.
'omitempty' should be used with pointer fields unless you want to
Marshal JSON Null, which is not the expected output.
'omitempty' is used when QAPI member is said to be optional. This
is true for all optional members with the exception of two
Alternates: StrOrNull and BlockdevRefOrNull, as we _do_ want to
express JSON Null with them.
```Go
package main
import (
"encoding/json"
"fmt"
)
type Test1 struct {
Foo *bool `json:"foo"`
Bar *bool `json:"bar,omitempty"`
Esc bool `json:"esc"`
Lar bool `json:"lar,omitempty"`
}
type Test2 struct {
Foo *uint64 `json:"foo"`
Bar *uint64 `json:"bar,omitempty"`
Esc uint64 `json:"esc"`
Lar uint64 `json:"lar,omitempty"`
}
func printIt(s any) {
if b, err := json.Marshal(s); err != nil {
panic(err)
} else {
fmt.Println(string(b))
}
}
func main() {
printIt(Test1{})
printIt(Test2{})
}
```
```console
toso@tapioca /tmp> go run main.go
{"foo":null,"esc":false}
{"foo":null,"esc":0}
```
Cheers,
Victor
signature.asc
Description: PGP signature
[PATCH v1 4/9] qapi: golang: structs: Address 'null' members, Victor Toso, 2023/09/27
[PATCH v1 7/9] qapi: golang: Generate qapi's command types in Go, Victor Toso, 2023/09/27
[PATCH v1 8/9] qapi: golang: Add CommandResult type to Go, Victor Toso, 2023/09/27
[PATCH v1 9/9] docs: add notes on Golang code generator, Victor Toso, 2023/09/27