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