func toProto()

in lib/proto/proto.go [435:545]


func toProto(fdesc protoreflect.FieldDescriptor, v starlark.Value) (protoreflect.Value, error) {
	switch fdesc.Kind() {
	case protoreflect.BoolKind:
		// To avoid mistakes, we require v be exactly a bool.
		if v, ok := v.(starlark.Bool); ok {
			return protoreflect.ValueOfBool(bool(v)), nil
		}

	case protoreflect.Fixed32Kind,
		protoreflect.Uint32Kind:
		// uint32
		if i, ok := v.(starlark.Int); ok {
			if u, ok := i.Uint64(); ok && uint64(uint32(u)) == u {
				return protoreflect.ValueOfUint32(uint32(u)), nil
			}
			return noValue, fmt.Errorf("invalid %s: %v", typeString(fdesc), i)
		}

	case protoreflect.Int32Kind,
		protoreflect.Sfixed32Kind,
		protoreflect.Sint32Kind:
		// int32
		if i, ok := v.(starlark.Int); ok {
			if i, ok := i.Int64(); ok && int64(int32(i)) == i {
				return protoreflect.ValueOfInt32(int32(i)), nil
			}
			return noValue, fmt.Errorf("invalid %s: %v", typeString(fdesc), i)
		}

	case protoreflect.Uint64Kind,
		protoreflect.Fixed64Kind:
		// uint64
		if i, ok := v.(starlark.Int); ok {
			if u, ok := i.Uint64(); ok {
				return protoreflect.ValueOfUint64(u), nil
			}
			return noValue, fmt.Errorf("invalid %s: %v", typeString(fdesc), i)
		}

	case protoreflect.Int64Kind,
		protoreflect.Sfixed64Kind,
		protoreflect.Sint64Kind:
		// int64
		if i, ok := v.(starlark.Int); ok {
			if i, ok := i.Int64(); ok {
				return protoreflect.ValueOfInt64(i), nil
			}
			return noValue, fmt.Errorf("invalid %s: %v", typeString(fdesc), i)
		}

	case protoreflect.StringKind:
		if s, ok := starlark.AsString(v); ok {
			return protoreflect.ValueOfString(s), nil
		} else if b, ok := v.(starlark.Bytes); ok {
			// TODO(adonovan): allow bytes for string? Not friendly to a Java port.
			return protoreflect.ValueOfBytes([]byte(b)), nil
		}

	case protoreflect.BytesKind:
		if s, ok := starlark.AsString(v); ok {
			// TODO(adonovan): don't allow string for bytes: it's hostile to a Java port.
			// Instead provide b"..." literals in the core
			// and a bytes(str) conversion.
			return protoreflect.ValueOfBytes([]byte(s)), nil
		} else if b, ok := v.(starlark.Bytes); ok {
			return protoreflect.ValueOfBytes([]byte(b)), nil
		}

	case protoreflect.DoubleKind:
		switch v := v.(type) {
		case starlark.Float:
			return protoreflect.ValueOfFloat64(float64(v)), nil
		case starlark.Int:
			return protoreflect.ValueOfFloat64(float64(v.Float())), nil
		}

	case protoreflect.FloatKind:
		switch v := v.(type) {
		case starlark.Float:
			return protoreflect.ValueOfFloat32(float32(v)), nil
		case starlark.Int:
			return protoreflect.ValueOfFloat32(float32(v.Float())), nil
		}

	case protoreflect.GroupKind,
		protoreflect.MessageKind:
		// Keep consistent with MessageDescriptor.CallInternal!
		desc := fdesc.Message()
		switch v := v.(type) {
		case *Message:
			if desc != v.desc() {
				return noValue, fmt.Errorf("got %s, want %s", v.desc().FullName(), desc.FullName())
			}
			return protoreflect.ValueOfMessage(v.msg), nil // alias it directly

		case *starlark.Dict:
			dest := newMessage(desc)
			err := setFields(dest, v.Items())
			return protoreflect.ValueOfMessage(dest), err
		}

	case protoreflect.EnumKind:
		enumval, err := enumValueOf(fdesc.Enum(), v)
		if err != nil {
			return noValue, err
		}
		return protoreflect.ValueOfEnum(enumval.Number()), nil
	}

	return noValue, fmt.Errorf("got %s, want %s", v.Type(), typeString(fdesc))
}