cm: Implement json Marshal/Unmarshal for List type#266
cm: Implement json Marshal/Unmarshal for List type#266lxfontes wants to merge 3 commits intobytecodealliance:mainfrom
Conversation
Signed-off-by: Lucas Fontes <lucas@cosmonic.com>
Signed-off-by: Lucas Fontes <lucas@cosmonic.com>
cm/list.go
Outdated
| // We override that behavior so all int types have the same serialization format. | ||
| // []uint8{1,2,3} -> [1,2,3] | ||
| // []uint32{1,2,3} -> [1,2,3] | ||
| if byteArray, ok := any(s).([]byte); ok { |
There was a problem hiding this comment.
This will miss List[T] where T is a named uint8 type.
Try something like this and convert the underlying slice: https://go.dev/play/p/MSlhH5LesNN
Update: updated link.
package main
import (
"encoding/json"
"fmt"
"unsafe"
)
func main() {
j, _ := json.Marshal([]uint8{0, 1, 2, 3})
fmt.Println(string(j))
j, _ = json.Marshal(sliceOf([]uint8{0, 1, 2, 3}))
fmt.Println(string(j))
}
type slice[T any] []entry[T]
func sliceOf[S ~[]E, E any](s S) slice[E] {
return *(*slice[E])(unsafe.Pointer(&s))
}
type entry[T any] [1]T
func (v entry[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(v[0])
}There was a problem hiding this comment.
makes sense! was avoiding the unsafe.Pointer route but totally forgot about type aliases.
| } | ||
| } | ||
|
|
||
| type listTestItem struct { |
There was a problem hiding this comment.
Is all this machinery necessary?
If List[T] implements json.Marshaler and json.Unmarshaler, then the test cases can have these lists inline.
There was a problem hiding this comment.
listTestItem is to test structs.
The machinery is necessary to generalize the Slice() method & carry the type information to reflect.DeepEqual. It's either this or unrolling into many smaller test functions per type.
While List implements Marshaler/Unmarshaler, accessing the underlying slice is thru typed Slice() []T ( not a common interface ). So the options are:
- make a generic wrapper ( what I did )
- cast it ( which requires knowing which type to cast to )
Unmarshal is where it is needed, and I used it in Marshal as well for consistency/less typing.
Signed-off-by: Lucas Fontes <lucas@cosmonic.com>
| s := l.Slice() | ||
|
|
||
| if s == nil { | ||
| return nullLiteral, nil |
There was a problem hiding this comment.
The caller can mutate the value of nullLiteral. Maybe mix this optimization for now?
|
Merged as part of #279. |
Relates to #239
This will also respect json nulls as per https://pkg.go.dev/encoding/json#Unmarshaler