diff --git a/cm/list.go b/cm/list.go index 5c896d04..c73ec97b 100644 --- a/cm/list.go +++ b/cm/list.go @@ -1,6 +1,9 @@ package cm -import "unsafe" +import ( + "encoding/json" + "unsafe" +) // List represents a Component Model list. // The binary representation of list is similar to a Go slice minus the cap field. @@ -9,6 +12,20 @@ type List[T any] struct { list[T] } +func (l List[T]) MarshalJSON() ([]byte, error) { + return json.Marshal(l.Slice()) +} + +func (l *List[T]) UnmarshalJSON(buf []byte) error { + var data []T + err := json.Unmarshal(buf, &data) + if err != nil { + return err + } + *l = ToList(data) + return nil +} + // AnyList is a type constraint for generic functions that accept any [List] type. type AnyList[T any] interface { ~struct { diff --git a/cm/option.go b/cm/option.go index cf7024aa..9cba967f 100644 --- a/cm/option.go +++ b/cm/option.go @@ -1,5 +1,9 @@ package cm +import ( + "encoding/json" +) + // Option represents a Component Model [option] type. // // [option]: https://component-model.bytecodealliance.org/design/wit.html#options @@ -8,6 +12,27 @@ type Option[T any] struct { option[T] } +// MarshalJSON implements the json.Marshaler interface for [Option]. +func (o Option[T]) MarshalJSON() ([]byte, error) { + return json.Marshal(o.Some()) +} + +// UnmarshalJSON unmarshals the Option from JSON. +func (o *Option[T]) UnmarshalJSON(buf []byte) error { + if len(buf) == 0 { + *o = None[T]() + return nil + } + + var v T + if err := json.Unmarshal(buf, &v); err != nil { + return err + } + + *o = Some(v) + return nil +} + // None returns an [Option] representing the none case, // equivalent to the zero value. func None[T any]() Option[T] { diff --git a/cm/tuple.go b/cm/tuple.go index 610a19be..a1ec0382 100644 --- a/cm/tuple.go +++ b/cm/tuple.go @@ -1,5 +1,13 @@ package cm +import ( + "encoding/json" + "errors" +) + +// ErrInvalidTuple is returned when a Tuple fails to unmarshal from JSON. +var ErrInvalidTuple = errors.New("invalid tuple") + // Tuple represents a [Component Model tuple] with 2 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -9,6 +17,30 @@ type Tuple[T0, T1 any] struct { F1 T1 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple[T0, T1]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple[T0, T1]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 2 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + return nil +} + // Tuple3 represents a [Component Model tuple] with 3 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -19,6 +51,32 @@ type Tuple3[T0, T1, T2 any] struct { F2 T2 } +func (t Tuple3[T0, T1, T2]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple3[T0, T1, T2]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 3 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + return nil +} + // Tuple4 represents a [Component Model tuple] with 4 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -30,6 +88,36 @@ type Tuple4[T0, T1, T2, T3 any] struct { F3 T3 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple4[T0, T1, T2, T3]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple4[T0, T1, T2, T3]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 4 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + return nil +} + // Tuple5 represents a [Component Model tuple] with 5 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -42,6 +130,39 @@ type Tuple5[T0, T1, T2, T3, T4 any] struct { F4 T4 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple5[T0, T1, T2, T3, T4]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple5[T0, T1, T2, T3, T4]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 5 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + return nil +} + // Tuple6 represents a [Component Model tuple] with 6 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -55,6 +176,42 @@ type Tuple6[T0, T1, T2, T3, T4, T5 any] struct { F5 T5 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple6[T0, T1, T2, T3, T4, T5]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple6[T0, T1, T2, T3, T4, T5]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 6 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + return nil +} + // Tuple7 represents a [Component Model tuple] with 7 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -69,6 +226,45 @@ type Tuple7[T0, T1, T2, T3, T4, T5, T6 any] struct { F6 T6 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple7[T0, T1, T2, T3, T4, T5, T6]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple7[T0, T1, T2, T3, T4, T5, T6]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 7 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + if err := json.Unmarshal(tmp[6], &t.F6); err != nil { + return err + } + return nil +} + // Tuple8 represents a [Component Model tuple] with 8 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -84,6 +280,48 @@ type Tuple8[T0, T1, T2, T3, T4, T5, T6, T7 any] struct { F7 T7 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple8[T0, T1, T2, T3, T4, T5, T6, T7]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple8[T0, T1, T2, T3, T4, T5, T6, T7]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 8 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + if err := json.Unmarshal(tmp[6], &t.F6); err != nil { + return err + } + if err := json.Unmarshal(tmp[7], &t.F7); err != nil { + return err + } + return nil +} + // Tuple9 represents a [Component Model tuple] with 9 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -100,6 +338,51 @@ type Tuple9[T0, T1, T2, T3, T4, T5, T6, T7, T8 any] struct { F8 T8 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple9[T0, T1, T2, T3, T4, T5, T6, T7, T8]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple9[T0, T1, T2, T3, T4, T5, T6, T7, T8]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 9 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + if err := json.Unmarshal(tmp[6], &t.F6); err != nil { + return err + } + if err := json.Unmarshal(tmp[7], &t.F7); err != nil { + return err + } + if err := json.Unmarshal(tmp[8], &t.F8); err != nil { + return err + } + return nil +} + // Tuple10 represents a [Component Model tuple] with 10 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -117,6 +400,54 @@ type Tuple10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any] struct { F9 T9 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple10[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 10 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + if err := json.Unmarshal(tmp[6], &t.F6); err != nil { + return err + } + if err := json.Unmarshal(tmp[7], &t.F7); err != nil { + return err + } + if err := json.Unmarshal(tmp[8], &t.F8); err != nil { + return err + } + if err := json.Unmarshal(tmp[9], &t.F9); err != nil { + return err + } + return nil +} + // Tuple11 represents a [Component Model tuple] with 11 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -135,6 +466,57 @@ type Tuple11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any] struct { F10 T10 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple11[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 11 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + if err := json.Unmarshal(tmp[6], &t.F6); err != nil { + return err + } + if err := json.Unmarshal(tmp[7], &t.F7); err != nil { + return err + } + if err := json.Unmarshal(tmp[8], &t.F8); err != nil { + return err + } + if err := json.Unmarshal(tmp[9], &t.F9); err != nil { + return err + } + if err := json.Unmarshal(tmp[10], &t.F10); err != nil { + return err + } + return nil +} + // Tuple12 represents a [Component Model tuple] with 12 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -154,6 +536,60 @@ type Tuple12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any] struct { F11 T11 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10, t.F11} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple12[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 12 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + if err := json.Unmarshal(tmp[6], &t.F6); err != nil { + return err + } + if err := json.Unmarshal(tmp[7], &t.F7); err != nil { + return err + } + if err := json.Unmarshal(tmp[8], &t.F8); err != nil { + return err + } + if err := json.Unmarshal(tmp[9], &t.F9); err != nil { + return err + } + if err := json.Unmarshal(tmp[10], &t.F10); err != nil { + return err + } + if err := json.Unmarshal(tmp[11], &t.F11); err != nil { + return err + } + return nil +} + // Tuple13 represents a [Component Model tuple] with 13 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -174,6 +610,63 @@ type Tuple13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any] struct { F12 T12 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10, t.F11, t.F12} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple13[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 13 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + if err := json.Unmarshal(tmp[6], &t.F6); err != nil { + return err + } + if err := json.Unmarshal(tmp[7], &t.F7); err != nil { + return err + } + if err := json.Unmarshal(tmp[8], &t.F8); err != nil { + return err + } + if err := json.Unmarshal(tmp[9], &t.F9); err != nil { + return err + } + if err := json.Unmarshal(tmp[10], &t.F10); err != nil { + return err + } + if err := json.Unmarshal(tmp[11], &t.F11); err != nil { + return err + } + if err := json.Unmarshal(tmp[12], &t.F12); err != nil { + return err + } + return nil +} + // Tuple14 represents a [Component Model tuple] with 14 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -195,6 +688,66 @@ type Tuple14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any] str F13 T13 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10, t.F11, t.F12, t.F13} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple14[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 14 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + if err := json.Unmarshal(tmp[6], &t.F6); err != nil { + return err + } + if err := json.Unmarshal(tmp[7], &t.F7); err != nil { + return err + } + if err := json.Unmarshal(tmp[8], &t.F8); err != nil { + return err + } + if err := json.Unmarshal(tmp[9], &t.F9); err != nil { + return err + } + if err := json.Unmarshal(tmp[10], &t.F10); err != nil { + return err + } + if err := json.Unmarshal(tmp[11], &t.F11); err != nil { + return err + } + if err := json.Unmarshal(tmp[12], &t.F12); err != nil { + return err + } + if err := json.Unmarshal(tmp[13], &t.F13); err != nil { + return err + } + return nil +} + // Tuple15 represents a [Component Model tuple] with 15 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -217,6 +770,69 @@ type Tuple15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any F14 T14 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10, t.F11, t.F12, t.F13, t.F14} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple15[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 15 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + if err := json.Unmarshal(tmp[6], &t.F6); err != nil { + return err + } + if err := json.Unmarshal(tmp[7], &t.F7); err != nil { + return err + } + if err := json.Unmarshal(tmp[8], &t.F8); err != nil { + return err + } + if err := json.Unmarshal(tmp[9], &t.F9); err != nil { + return err + } + if err := json.Unmarshal(tmp[10], &t.F10); err != nil { + return err + } + if err := json.Unmarshal(tmp[11], &t.F11); err != nil { + return err + } + if err := json.Unmarshal(tmp[12], &t.F12); err != nil { + return err + } + if err := json.Unmarshal(tmp[13], &t.F13); err != nil { + return err + } + if err := json.Unmarshal(tmp[14], &t.F14); err != nil { + return err + } + return nil +} + // Tuple16 represents a [Component Model tuple] with 16 fields. // // [Component Model tuple]: https://component-model.bytecodealliance.org/design/wit.html#tuples @@ -240,6 +856,72 @@ type Tuple16[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T1 F15 T15 } +// MarshalJSON marshals the Tuple into JSON. +func (t Tuple16[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T16]) MarshalJSON() ([]byte, error) { + l := []any{t.F0, t.F1, t.F2, t.F3, t.F4, t.F5, t.F6, t.F7, t.F8, t.F9, t.F10, t.F11, t.F12, t.F13, t.F14, t.F15} + return json.Marshal(l) +} + +// UnmarshalJSON unmarshals the Tuple from JSON. +func (t *Tuple16[T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]) UnmarshalJSON(buf []byte) error { + tmp := []json.RawMessage{} + if err := json.Unmarshal(buf, &tmp); err != nil { + return err + } + if len(tmp) != 16 { + return ErrInvalidTuple + } + if err := json.Unmarshal(tmp[0], &t.F0); err != nil { + return err + } + if err := json.Unmarshal(tmp[1], &t.F1); err != nil { + return err + } + if err := json.Unmarshal(tmp[2], &t.F2); err != nil { + return err + } + if err := json.Unmarshal(tmp[3], &t.F3); err != nil { + return err + } + if err := json.Unmarshal(tmp[4], &t.F4); err != nil { + return err + } + if err := json.Unmarshal(tmp[5], &t.F5); err != nil { + return err + } + if err := json.Unmarshal(tmp[6], &t.F6); err != nil { + return err + } + if err := json.Unmarshal(tmp[7], &t.F7); err != nil { + return err + } + if err := json.Unmarshal(tmp[8], &t.F8); err != nil { + return err + } + if err := json.Unmarshal(tmp[9], &t.F9); err != nil { + return err + } + if err := json.Unmarshal(tmp[10], &t.F10); err != nil { + return err + } + if err := json.Unmarshal(tmp[11], &t.F11); err != nil { + return err + } + if err := json.Unmarshal(tmp[12], &t.F12); err != nil { + return err + } + if err := json.Unmarshal(tmp[13], &t.F13); err != nil { + return err + } + if err := json.Unmarshal(tmp[14], &t.F14); err != nil { + return err + } + if err := json.Unmarshal(tmp[15], &t.F15); err != nil { + return err + } + return nil +} + // MaxTuple specifies the maximum number of fields in a Tuple* type, currently [Tuple16]. // See https://github.com/WebAssembly/component-model/issues/373 for more information. const MaxTuple = 16 diff --git a/cm/variant.go b/cm/variant.go index 24703641..3e2c8887 100644 --- a/cm/variant.go +++ b/cm/variant.go @@ -1,6 +1,8 @@ package cm -import "unsafe" +import ( + "unsafe" +) // Discriminant is the set of types that can represent the tag or discriminator of a variant. // Use bool for 2-case variant types, result, or option types, uint8 where there are 256 or diff --git a/wit/bindgen/generator.go b/wit/bindgen/generator.go index a1c6c63e..7298ca77 100644 --- a/wit/bindgen/generator.go +++ b/wit/bindgen/generator.go @@ -679,13 +679,13 @@ func (g *generator) recordRep(file *gen.File, dir wit.Direction, r *wit.Record, exported := len(goName) == 0 || token.IsExported(goName) var b strings.Builder b.WriteString("struct {\n") - stringio.Write(&b, "_ ", file.Import(g.opts.cmPackage), ".HostLayout") + stringio.Write(&b, "_ ", file.Import(g.opts.cmPackage), ".HostLayout", "`json:\"-\"`") for i, f := range r.Fields { if i == 0 || i > 0 && f.Docs.Contents != "" { b.WriteRune('\n') } b.WriteString(formatDocComments(f.Docs.Contents, false)) - stringio.Write(&b, fieldName(f.Name, exported), " ", g.typeRep(file, dir, f.Type), "\n") + stringio.Write(&b, fieldName(f.Name, exported), " ", g.typeRep(file, dir, f.Type), "`json:\"", f.Name, "\"`", "\n") } b.WriteRune('}') return b.String() @@ -823,10 +823,14 @@ func (g *generator) variantRep(file *gen.File, dir wit.Direction, t *wit.TypeDef decl, _ := g.typeDecl(dir, t) scope := decl.scope - scope.DeclareName("String") // For fmt.Stringer + scope.DeclareName("String") // For fmt.Stringer + scope.DeclareName("MarshalJSON") // For encoding/json.Marshaler + scope.DeclareName("UnmarshalJSON") // For encoding/json.Unmarshaler // Emit type var b strings.Builder + var jsonMarshalCases strings.Builder + var jsonUnmarshalCases strings.Builder cm := file.Import(g.opts.cmPackage) stringio.Write(&b, cm, ".Variant[", g.typeRep(file, dir, disc), ", ", typeShape, ", ", g.typeRep(file, dir, align), "]\n\n") @@ -867,6 +871,20 @@ func (g *generator) variantRep(file *gen.File, dir wit.Direction, t *wit.TypeDef stringio.Write(&b, "return ", cm, ".Case[", typeRep, "](self, ", caseNum, ")") b.WriteString("}\n\n") } + + stringio.Write(&jsonMarshalCases, "case ", caseNum, ":\n") + stringio.Write(&jsonMarshalCases, "val = v.", caseName, "()\n") + + stringio.Write(&jsonUnmarshalCases, "case \"", c.Name, "\":\n") + if c.Type != nil { + stringio.Write(&jsonUnmarshalCases, "var tmp ", typeRep, "\n") + stringio.Write(&jsonUnmarshalCases, "if err := json.Unmarshal(data, &tmp); err != nil {\n") + stringio.Write(&jsonUnmarshalCases, "return err\n") + stringio.Write(&jsonUnmarshalCases, "}\n") + stringio.Write(&jsonUnmarshalCases, "*v = ", constructorName, "(tmp)\n") + } else { + stringio.Write(&jsonUnmarshalCases, "*v = ", constructorName, "()\n") + } } stringsName := file.DeclareName("strings" + GoName(goName, true)) @@ -881,6 +899,39 @@ func (g *generator) variantRep(file *gen.File, dir wit.Direction, t *wit.TypeDef stringio.Write(&b, "return ", stringsName, "[v.Tag()]\n") b.WriteString("}\n\n") + file.Import("encoding/json") + b.WriteString(formatDocComments("MarshalJSON implements [json.Marshaler].", true)) + stringio.Write(&b, "func (v ", goName, ") MarshalJSON() ([]byte, error) {\n") + stringio.Write(&b, "ret := make(map[string]any)\n") + stringio.Write(&b, "var val any\n") + stringio.Write(&b, "switch v.Tag() {\n") + stringio.Write(&b, jsonMarshalCases.String()) + stringio.Write(&b, "}\n") + stringio.Write(&b, "ret[v.String()] = val\n") + stringio.Write(&b, "return json.Marshal(ret)\n") + b.WriteString("}\n\n") + + b.WriteString(formatDocComments("UnmarshalJSON implements [json.Unmarshaler].", true)) + stringio.Write(&b, "func (v *", goName, ") UnmarshalJSON(buf []byte) error {\n") + stringio.Write(&b, "tagger := make(map[string]json.RawMessage)\n") + stringio.Write(&b, "var tag string\n") + stringio.Write(&b, "var data json.RawMessage\n") + stringio.Write(&b, "if err := json.Unmarshal(buf, &tagger); err != nil {\n") + stringio.Write(&b, "return err\n") + stringio.Write(&b, "}\n") + stringio.Write(&b, "if len(tagger) != 1 {\n") + stringio.Write(&b, "return nil\n") + stringio.Write(&b, "}\n") + stringio.Write(&b, "for tag, data = range tagger {\n") + stringio.Write(&b, "break\n") + stringio.Write(&b, "}\n") + + stringio.Write(&b, "switch tag {\n") + stringio.Write(&b, jsonUnmarshalCases.String()) + stringio.Write(&b, "}\n") + stringio.Write(&b, "return nil\n") + b.WriteString("}\n\n") + return b.String() }