Hi,

On Thu, Nov 09, 2023 at 09:59:50AM -0800, Andrea Bolognani wrote:
> On Mon, Oct 16, 2023 at 05:27:01PM +0200, Victor Toso wrote:
> > This patch handles QAPI event types and generates data structures in
> > Go that handles it.
> >
> > We also define a Event interface and two helper functions MarshalEvent
> > and UnmarshalEvent.
> >
> > Example:
> > qapi:
> >  | { 'event': 'MEMORY_DEVICE_SIZE_CHANGE',
> >  |   'data': { '*id': 'str', 'size': 'size', 'qom-path' : 'str'} }
> >
> > go:
> >  | type MemoryDeviceSizeChangeEvent struct {
> >  |         MessageTimestamp Timestamp `json:"-"`
> >  |         Id               *string   `json:"id,omitempty"`
> >  |         Size             uint64    `json:"size"`
> >  |         QomPath          string    `json:"qom-path"`
> >  | }
> >
> > usage:
> >  | input := `{"event":"MEMORY_DEVICE_SIZE_CHANGE",` +
> >  | `"timestamp":{"seconds":1588168529,"microseconds":201316},` +
> >  | 
> > `"data":{"id":"vm0","size":1073741824,"qom-path":"/machine/unattached/device[2]"}}`
> >  | e, err := UnmarshalEvent([]byte(input)
> >  | if err != nil {
> >  |     panic(err)
> >  | }
> >  | if e.GetName() == `MEMORY_DEVICE_SIZE_CHANGE` {
> >  |     m := e.(*MemoryDeviceSizeChangeEvent)
> >  |     // m.QomPath == "/machine/unattached/device[2]"
> >  | }
> 
> I don't think we should encourage people to perform string
> comparisons, as it completely sidesteps Go's type system and is
> thus error-prone. Safer version:
> 
>   switch m := e.(type) {
>   case *MemoryDeviceSizeChangeEvent:
>     // m.QomPath == "/machine/unattached/device[2]"
>   }

I agree.

> Now, I'm not sure I would go as far as suggesting that the
> GetName() function should be completely removed, but maybe we
> can try leaving it out from the initial version and see if
> people start screaming?

It might be useful for debugging too. I would rather log
e.GetName() than the string version of the type but if that's the
only reason we needed, I agree on removing for now.
 
> API-wise, I'm not a fan of the fact that we're forcing users to call
> (Un)MarshalEvent instead of the standard (Un)MarshalJSON. If we add
> something like
> 
>   func GetEventType(data []byte) (Event, error) {
>     type event struct {
>       Name string `json:"event"`
>     }
> 
>     tmp := event{}
>     if err := json.Unmarshal(data, &tmp); err != nil {
>       return nil, err
>     }
> 
>     switch tmp.Name {
>     case "MEMORY_DEVICE_SIZE_CHANGE":
>             return &MemoryDeviceSizeChangeEvent{}, nil
>     ...
>     }
> 
>     return nil, fmt.Errorf("unrecognized event '%s'", tmp.Name)
>   }
> 
> it becomes feasible to stick with standard functions. We can of
> course keep the (Un)MarshalEvent functions around for convenience,
> but I don't think they should be the only available API.

I agree. I'll change it. Perhaps we shouldn't use
(Un)MarshalEvent at this layer at all. Probably the same for
(Un)MarshalCommand.

Cheers,
Victor

Attachment: signature.asc
Description: PGP signature

Reply via email to