mirror of
https://github.com/diamondburned/arikawa.git
synced 2024-09-28 21:29:25 +00:00
gateway: Use PartialUnmarshal for ReadyEventExtras
This commit is contained in:
parent
60ed12f3c0
commit
87c479a2dc
|
@ -692,7 +692,7 @@ func (r *ReadyEvent) UnmarshalJSON(b []byte) error {
|
|||
|
||||
// Optionally unmarshal ReadyEventExtras.
|
||||
if !r.User.Bot {
|
||||
r.ExtrasDecodeError = json.Unmarshal(b, &r.ReadyEventExtras)
|
||||
r.ExtrasDecodeErrors = json.PartialUnmarshal(b, &r.ReadyEventExtras)
|
||||
}
|
||||
|
||||
if ReadyEventKeepRaw {
|
||||
|
@ -723,9 +723,9 @@ type (
|
|||
// RawEventBody is the raw JSON body for the Ready event. It is only
|
||||
// available if ReadyEventKeepRaw is true.
|
||||
RawEventBody json.Raw
|
||||
// ExtrasDecodeError will be non-nil if there was an error decoding the
|
||||
// ExtrasDecodeErrors will be non-nil if there were errors decoding the
|
||||
// ReadyEventExtras.
|
||||
ExtrasDecodeError error
|
||||
ExtrasDecodeErrors []error
|
||||
}
|
||||
|
||||
// ReadState is a single ReadState entry. It is undocumented.
|
||||
|
|
|
@ -5,6 +5,8 @@ package json
|
|||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Driver interface {
|
||||
|
@ -55,3 +57,48 @@ func DecodeStream(r io.Reader, v interface{}) error {
|
|||
func EncodeStream(w io.Writer, v interface{}) error {
|
||||
return Default.EncodeStream(w, v)
|
||||
}
|
||||
|
||||
// PartialUnmarshal partially unmarshals the JSON in b onto v. Fields that
|
||||
// cannot be unmarshaled will be left as their zero values. Fields that can be
|
||||
// marshaled will be unmarshaled and its name will be added to the returned
|
||||
// slice.
|
||||
//
|
||||
// Only use this for the most cursed of JSONs, such as ones coming from Discord.
|
||||
// Try not to use this as much as possible.
|
||||
func PartialUnmarshal(b []byte, v interface{}) []error {
|
||||
var errs []error
|
||||
|
||||
dstv := reflect.Indirect(reflect.ValueOf(v))
|
||||
dstt := dstv.Type()
|
||||
|
||||
// ptrVal will be used by reflect to store our temporary object. This allows
|
||||
// us to free up n heap allocations just for one pointer.
|
||||
var ptrVal struct {
|
||||
_ *struct{}
|
||||
}
|
||||
|
||||
dstfields := dstt.NumField()
|
||||
for i := 0; i < dstfields; i++ {
|
||||
dstfield := dstt.Field(i)
|
||||
|
||||
// Create us a custom struct with this one field, except its type is a
|
||||
// pointer type. We prefer to do this over parsing JSON's tags.
|
||||
fake := reflect.NewAt(reflect.StructOf([]reflect.StructField{
|
||||
{
|
||||
Name: dstfield.Name,
|
||||
Type: reflect.PtrTo(dstfield.Type),
|
||||
Tag: dstfield.Tag,
|
||||
},
|
||||
}), unsafe.Pointer(&ptrVal))
|
||||
|
||||
// We can use this pointer to set the value of the field.
|
||||
fake.Elem().Field(0).Set(dstv.Field(i).Addr())
|
||||
|
||||
// Unmarshal into this struct.
|
||||
if err := json.Unmarshal(b, fake.Interface()); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue