github.com/traefik/yaegi@v0.15.1/_test/issue-1460.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "net/netip" 8 "reflect" 9 ) 10 11 func unmarshalJSON[T any](b []byte, x *[]T) error { 12 if *x != nil { 13 return errors.New("already initialized") 14 } 15 if len(b) == 0 { 16 return nil 17 } 18 return json.Unmarshal(b, x) 19 } 20 21 func SliceOfViews[T ViewCloner[T, V], V StructView[T]](x []T) SliceView[T, V] { 22 return SliceView[T, V]{x} 23 } 24 25 type StructView[T any] interface { 26 Valid() bool 27 AsStruct() T 28 } 29 30 type SliceView[T ViewCloner[T, V], V StructView[T]] struct { 31 ж []T 32 } 33 34 type ViewCloner[T any, V StructView[T]] interface { 35 View() V 36 Clone() T 37 } 38 39 func (v SliceView[T, V]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } 40 41 func (v *SliceView[T, V]) UnmarshalJSON(b []byte) error { return unmarshalJSON(b, &v.ж) } 42 43 type Slice[T any] struct { 44 ж []T 45 } 46 47 func (v Slice[T]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) } 48 49 func (v *Slice[T]) UnmarshalJSON(b []byte) error { return unmarshalJSON(b, &v.ж) } 50 51 func SliceOf[T any](x []T) Slice[T] { 52 return Slice[T]{x} 53 } 54 55 type IPPrefixSlice struct { 56 ж Slice[netip.Prefix] 57 } 58 59 type viewStruct struct { 60 Int int 61 Strings Slice[string] 62 StringsPtr *Slice[string] `json:",omitempty"` 63 } 64 65 func main() { 66 ss := SliceOf([]string{"bar"}) 67 in := viewStruct{ 68 Int: 1234, 69 Strings: ss, 70 StringsPtr: &ss, 71 } 72 73 var buf bytes.Buffer 74 encoder := json.NewEncoder(&buf) 75 encoder.SetIndent("", "") 76 err1 := encoder.Encode(&in) 77 b := buf.Bytes() 78 var got viewStruct 79 err2 := json.Unmarshal(b, &got) 80 println(err1 == nil, err2 == nil, reflect.DeepEqual(got, in)) 81 } 82 83 // Output: 84 // true true true