func (msg *protoMessage) Merge(other *protoMessage) error {
	if msg.Type() != other.Type() {
		return fmt.Errorf("Cannot merge protobufs of different types: Merge(%s, %s) ", msg.Type(), other.Type())
	}
	if err := msg.CheckMutable("merge"); err != nil {
		return err
	}
	for fieldName, val := range other.fields {
		fieldDesc := getFieldDescriptor(msg.msgDesc, fieldName)
		if fieldDesc == nil {
			continue
		}
		merged, err := mergeField(msg.fields[fieldName], val)
		if err != nil {
			return err
		}
		msg.SetField(fieldName, merged)
	}
	return nil
}
Merges values from other into msg following proto.Merge logic
package protomodule
import (
	"fmt"
	"sort"
	"go.starlark.net/starlark"
	"go.starlark.net/syntax"
	"google.golang.org/protobuf/encoding/protojson"
	"google.golang.org/protobuf/encoding/prototext"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/reflect/protoreflect"
)
func NewMessage(msg proto.Message) (*protoMessage, error) {
	msgReflect := msg.ProtoReflect()
	fields := make(map[string]starlark.Value)
	var rangeErr error
	msgReflect.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
		if isFieldSet(v, fd) {
			starlarkValue, err := valueToStarlark(v, fd)
			if err != nil {
				rangeErr = err
				return false
			}
			fields[string(fd.Name())] = starlarkValue
		}
		return true
	})
	if rangeErr != nil {
		return nil, rangeErr
	}
	cloned := proto.Clone(msg)
	proto.Reset(cloned)
	return &protoMessage{
		msg:     cloned,
		msgDesc: msgReflect.Descriptor(),
		fields:  fields,
		frozen:  false,
	}, nil
}
func AsProtoMessage(v starlark.Value) (proto.Message, bool) {
	if msg, ok := v.(*protoMessage); ok {
		return msg.toProtoMessage(), true
	}
	return nil, false
}
type protoMessage struct {
	msg     proto.Message
	msgDesc protoreflect.MessageDescriptor
	fields  map[string]starlark.Value
	frozen  bool
}
var _ starlark.Value = (*protoMessage)(nil)
var _ starlark.HasAttrs = (*protoMessage)(nil)
var _ starlark.HasSetField = (*protoMessage)(nil)
var _ starlark.Comparable = (*protoMessage)(nil)
func (msg *protoMessage) String() string {
	return fmt.Sprintf("<%s %s>", msg.Type(), (prototext.MarshalOptions{Multiline: false}).Format(msg.toProtoMessage()))
}
func (msg *protoMessage) Type() string         { return string(msg.msgDesc.FullName()) }
func (msg *protoMessage) Truth() starlark.Bool { return starlark.True }
func (msg *protoMessage) Hash() (uint32, error) {
	return 0, fmt.Errorf("unhashable type: %s", msg.Type())
}
func (msg *protoMessage) Freeze() {
	if !msg.frozen {
		msg.frozen = true
		for _, field := range msg.fields {
			field.Freeze()
		}
	}
}
func (msg *protoMessage) Clear() error {
	if err := msg.CheckMutable("clear"); err != nil {
		return err
	}
	msg.fields = make(map[string]starlark.Value)
	return nil
}
func (msg *protoMessage) CheckMutable(verb string) error {
	if msg.frozen {
		return fmt.Errorf("cannot %s frozen message", verb)
	}
	return nil
}
func (msg *protoMessage) CompareSameType(op syntax.Token, y starlark.Value, depth int) (bool, error) {
	other, ok := y.(*protoMessage)
	if !ok {
		return false, nil
	}
	switch op {
	case syntax.EQL:
		eql := proto.Equal(msg.toProtoMessage(), other.toProtoMessage())
		return eql, nil
	case syntax.NEQ:
		eql := proto.Equal(msg.toProtoMessage(), other.toProtoMessage())
		return !eql, nil
	default:
		return false, fmt.Errorf("Only == and != operations are supported on protobufs, found %s", op.String())
	}
}
func (msg *protoMessage) MarshalJSON() ([]byte, error) {
	jsonData, err := (protojson.MarshalOptions{
		UseProtoNames: true,
	}).Marshal(msg.toProtoMessage())
	if err != nil {
		return nil, err
	}
	return []byte(jsonData), nil
}
func (msg *protoMessage) Attr(name string) (starlark.Value, error) {
	if val, ok := msg.fields[name]; ok {
		return val, nil
	}
	fieldDesc := getFieldDescriptor(msg.msgDesc, name)
	if fieldDesc == nil {
		return starlark.None, fmt.Errorf("AttributeError: `%s' value has no field %q", msg.Type(), name)
	}
	val := fieldDesc.Default()
	starlarkValue, err := valueToStarlark(val, fieldDesc)
	if err != nil {
		return starlark.None, err
	}
	if fieldDesc.IsList() || fieldDesc.IsMap() || fieldDesc.Kind() == protoreflect.MessageKind {
		msg.SetField(name, starlarkValue)
	}
	return starlarkValue, nil
}
func (msg *protoMessage) AttrNames() []string {
	return fieldNames(msg.msgDesc)
}
func fieldNames(msgDesc protoreflect.MessageDescriptor) []string {
	out := []string{}
	fields := msgDesc.Fields()
	for i := 0; i < fields.Len(); i++ {
		fieldName := string(fields.Get(i).Name())
		out = append(out, fieldName)
	}
	sort.Strings(out)
	return out
}
func (msg *protoMessage) SetField(name string, val starlark.Value) error {
	fieldDesc := getFieldDescriptor(msg.msgDesc, name)
	if fieldDesc == nil {
		return fmt.Errorf("AttributeError: `%s' value has no field %q", msg.Type(), name)
	}
	if err := msg.CheckMutable("set field of"); err != nil {
		return err
	}
	if fieldDesc.IsList() {
		if starlarkListVal, ok := val.(*starlark.List); ok {
			if fieldDesc.Kind() == protoreflect.MessageKind {
				for i := 0; i < starlarkListVal.Len(); i++ {
					msg, err := maybeConvertToWrapper(fieldDesc, starlarkListVal.Index(i))
					if err != nil {
						return err
					}
					if msg != nil {
						starlarkListVal.SetIndex(i, msg)
					}
				}
			}
			list, err := newProtoRepeatedFromList(fieldDesc, starlarkListVal)
			if err != nil {
				return err
			}
			val = list
		}
	} else if fieldDesc.IsMap() {
		if starlarkDictVal, ok := val.(*starlark.Dict); ok {
			mapVal, err := newProtoMapFromDict(fieldDesc.MapKey(), fieldDesc.MapValue(), starlarkDictVal)
			if err != nil {
				return err
			}
			val = mapVal
		}
	} else if fieldDesc.Kind() == protoreflect.MessageKind {
		msg, err := maybeConvertToWrapper(fieldDesc, val)
		if err != nil {
			return err
		}
		if msg != nil {
			val = msg
		}
	}
	if fieldAllowsNone(fieldDesc) && val == starlark.None {
		delete(msg.fields, name)
		return nil
	}
	_, err := valueFromStarlark(msg.msg.ProtoReflect(), fieldDesc, val)
	if err != nil {
		return err
	}
	oneof := fieldDesc.ContainingOneof()
	if oneof != nil {
		fields := oneof.Fields()
		for i := 0; i < fields.Len(); i++ {
			delete(msg.fields, string(fields.Get(i).Name()))
		}
	}
	msg.fields[name] = val
	return nil
}
func (msg *protoMessage) SetDefaults() error {
	if err := msg.CheckMutable("set field defaults of"); err != nil {
		return err
	}
	for _, fieldName := range fieldNames(msg.msgDesc) {
		fieldDesc := getFieldDescriptor(msg.msgDesc, fieldName)
		if fieldDesc == nil {
			continue
		}
		if _, ok := msg.fields[fieldName]; ok {
			continue
		}
		if !fieldDesc.HasDefault() {
			continue
		}
		val, err := valueToStarlark(fieldDesc.Default(), fieldDesc)
		if err != nil {
			return err
		}
		msg.SetField(fieldName, val)
	}
	return nil
}