== contract.go ==
// Code generated by go-jsonrpc-codegen. DO NOT EDIT.

package generated

import (
	json "encoding/json"
	rpc "example.com/collections/rpc"
)

func pointer[T any](value T) *T { return &value }

// Contract returns a fresh prepared runtime contract.
func Contract() rpc.Contract {
	return rpc.Contract{
		Peers: []rpc.PeerContract{
			{Name: "client", Methods: []rpc.MethodContract{
			}},
			{Name: "server", Methods: []rpc.MethodContract{
				{Name: "exchange", Kind: "either", Params: "positional", Positional: []string{"items", "table"}, NullResult: false,
					RefersToCall: nil,
					ValidateParams: func(data json.RawMessage) error { _, err := decodeValue[Input](data); return err },
					ValidateResult: func(data json.RawMessage) error { _, err := decodeValue[Input](data); return err },
					Errors: []rpc.ErrorContract{
					},
				},
			}},
		},
	}
}
== peer.go ==
// Code generated by go-jsonrpc-codegen. DO NOT EDIT.

package generated

import (
	context "context"
	json "encoding/json"
	rpc "example.com/collections/rpc"
)

// Peer accepts local handlers and calls the other peer.
type Peer struct { *rpc.Peer }

// Handlers holds the typed functions that this peer accepts.
type Handlers struct {
}

func NewPeer(handlers Handlers, options rpc.Options) (*Peer, error) {
	runtime, err := rpc.NewPeer(Contract(), "client", options)
	if err != nil { return nil, err }
	peer := &Peer{Peer: runtime}
	return peer, nil
}

func (peer *Peer) Exchange(ctx context.Context, input Input) (Input, error) {
	params := []any{input.Items,input.Table,}
	if len(params) == 2 && input.Table == nil { params = params[:1] }
	var raw json.RawMessage
	err := peer.Peer.Call(ctx, "exchange", params, &raw)
	if err != nil { var zero Input; return zero, decodeExchangeError(err) }
	return decodeValue[Input](raw)
}

func decodeExchangeError(err error) error {
	return err
}

func (peer *Peer) NotifyExchange(ctx context.Context, input Input) error {
	params := []any{input.Items,input.Table,}
	if len(params) == 2 && input.Table == nil { params = params[:1] }
	return peer.Peer.Notify(ctx, "exchange", params)
}
== types.go ==
// Code generated by go-jsonrpc-codegen. DO NOT EDIT.

package generated

import (
	bytes "bytes"
	json "encoding/json"
	rpc "example.com/collections/rpc"
	fmt "fmt"
	sort "sort"
)

func decodeValue[T any](data []byte) (T, error) {
	var value T
	if bytes.Equal(bytes.TrimSpace(data), []byte("null")) {
		if _, document := any(value).(json.RawMessage); !document { return value, fmt.Errorf("I expected a non-null value for construct `%T`.", value) }
	}
	if err := json.Unmarshal(data, &value); err != nil { return value, err }
	return value, nil
}

func decodeObject(data []byte, construct string) (map[string]json.RawMessage, error) {
	var raw map[string]json.RawMessage
	if err := json.Unmarshal(data, &raw); err != nil { return nil, err }
	if raw == nil { return nil, fmt.Errorf("I expected an object for construct `%s`.", construct) }
	return raw, nil
}

type Choice interface { isChoice() }

type ChoiceDecimal struct { Value rpc.Number }
func (ChoiceDecimal) isChoice() {}
func (value ChoiceDecimal) MarshalJSON() ([]byte, error) {
	return json.Marshal(map[string]any{"decimal": value.Value})
}

type ChoiceInteger struct { Value rpc.Integer }
func (ChoiceInteger) isChoice() {}
func (value ChoiceInteger) MarshalJSON() ([]byte, error) {
	return json.Marshal(map[string]any{"integer": value.Value})
}

type ChoiceText struct { Value string }
func (ChoiceText) isChoice() {}
func (value ChoiceText) MarshalJSON() ([]byte, error) {
	return json.Marshal(map[string]any{"text": value.Value})
}

func decodeChoice(data []byte) (Choice, error) {
	raw, err := decodeObject(data, "example.collections#Choice")
	if err != nil { return nil, err }
	if len(raw) != 1 { return nil, fmt.Errorf("I expected one member in union `example.collections#Choice`.") }
	for tag, data := range raw {
		switch tag {
		case "decimal":
			value, err := decodeValue[rpc.Number](data)
			if err != nil { return nil, err }
			return ChoiceDecimal{Value: value}, nil
		case "integer":
			value, err := decodeValue[rpc.Integer](data)
			if err != nil { return nil, err }
			return ChoiceInteger{Value: value}, nil
		case "text":
			value, err := decodeValue[string](data)
			if err != nil { return nil, err }
			return ChoiceText{Value: value}, nil
		default: return nil, fmt.Errorf("I found unknown member `%s` in union `example.collections#Choice`.", tag)
		}
	}
	return nil, fmt.Errorf("I expected union `example.collections#Choice`.")
}

type Input struct {
	Items Items `json:"items"`
	Table *Table `json:"table,omitempty"`
}

func (value *Input) UnmarshalJSON(data []byte) error {
	raw, err := decodeObject(data, "example.collections#Input")
	if err != nil { return err }
	var decoded Input
	if data, ok := raw["items"]; ok {
		member, err := decodeValue[Items](data)
		if err != nil { return fmt.Errorf("I could not read member `example.collections#Input$items`: %w", err) }
		decoded.Items = member
	} else { return fmt.Errorf("I expected required member `example.collections#Input$items`.") }
	if data, ok := raw["table"]; ok {
		member, err := decodeValue[Table](data)
		if err != nil { return fmt.Errorf("I could not read member `example.collections#Input$table`: %w", err) }
		decoded.Table = &member
	}
	*value = decoded
	return nil
}

type Items []Choice

func (value *Items) UnmarshalJSON(data []byte) error {
	var raw []json.RawMessage
	if err := json.Unmarshal(data, &raw); err != nil { return err }
	if raw == nil { return fmt.Errorf("I expected list `example.collections#Items`.") }
	decoded := make(Items, len(raw))
	for index, data := range raw {
		item, err := decodeChoice(data)
		if err != nil { return err }
		decoded[index] = item
	}
	*value = decoded
	return nil
}

type Table map[string]Choice

func (value *Table) UnmarshalJSON(data []byte) error {
	raw, err := decodeObject(data, "example.collections#Table")
	if err != nil { return err }
	decoded := make(Table, len(raw))
	keys := make([]string, 0, len(raw))
	for key := range raw { keys = append(keys, key) }
	sort.Strings(keys)
	for _, key := range keys {
		data := raw[key]
		item, err := decodeChoice(data)
		if err != nil { return err }
		decoded[string(key)] = item
	}
	*value = decoded
	return nil
}
