wrpc 0.16.0

WebAssembly component-native RPC framework based on WIT
Documentation
package wrpc

import (
	"fmt"
	"log/slog"
)

func FlattenOption[T any](v **T) *T {
	if v == nil {
		return nil
	} else {
		return *v
	}
}

// ReadOptionStatus reads a single byte from `r` and returns:
// - `true` for `option::some`
// - `false` for `option::none`
func ReadOptionStatus(r ByteReader) (bool, error) {
	status, err := r.ReadByte()
	if err != nil {
		return false, fmt.Errorf("failed to read `option` status byte: %w", err)
	}
	switch status {
	case 0:
		return false, nil
	case 1:
		return true, nil
	default:
		return false, fmt.Errorf("invalid `option` status byte %d", status)
	}
}

// ReadOption reads an option from `r`
func ReadOption[T any](r ByteReader, f func(ByteReader) (T, error)) (*T, error) {
	slog.Debug("reading option status byte")
	ok, err := ReadOptionStatus(r)
	if err != nil {
		return nil, err
	}
	if !ok {
		return nil, nil
	}
	slog.Debug("reading `option::some` payload")
	v, err := f(r)
	if err != nil {
		return nil, fmt.Errorf("failed to read `option::some` value: %w", err)
	}
	return &v, nil
}

// ReadFlatOption reads an option from `r` without pointer indirection
func ReadFlatOption[T any](r IndexReader, f func(IndexReader) (T, error)) (v T, err error) {
	slog.Debug("reading option status byte")
	ok, err := ReadOptionStatus(r)
	if err != nil {
		return v, err
	}
	if !ok {
		return v, err
	}
	slog.Debug("reading `option::some` payload")
	v, err = f(r)
	if err != nil {
		return v, fmt.Errorf("failed to read `option::some` value: %w", err)
	}
	return v, nil
}

func WriteOption[T any](v *T, w ByteWriter, f func(T, ByteWriter) error) error {
	if v == nil {
		slog.Debug("writing `option::none` status byte")
		if err := w.WriteByte(0); err != nil {
			return fmt.Errorf("failed to write `option::none` byte: %w", err)
		}
		return nil
	}
	slog.Debug("writing `option::some` status byte")
	if err := w.WriteByte(1); err != nil {
		return fmt.Errorf("failed to write `option::some` status byte: %w", err)
	}
	slog.Debug("writing `option::some` payload")
	if err := f(*v, w); err != nil {
		return fmt.Errorf("failed to write `option::some` payload: %w", err)
	}
	return nil
}