blob: f02a2d7be0e25f4a175be9fe54bd6b715870217e [file] [log] [blame]
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package protodetecttypes identifies static types (go/types, typically
// obtained at build time) generated by protoc-gen-go. The protodetectreflect
// package is the counterpart for dynamic types (reflect, obtained at runtime).
package protodetecttypes
import (
"go/types"
"reflect"
"strings"
)
// Type represents a go/types.Type obtained at build time.
type Type struct{ T types.Type }
// IsMessage reports whether t is a generated message.
func (t Type) IsMessage() bool {
return t.MessageAPI() != Invalid
}
// MessageAPI determines the API of the generated message.
func (t Type) MessageAPI() MessageAPI {
if t, ok := t.T.Underlying().(*types.Struct); ok && t.NumFields() > 0 {
return determineAPI(reflect.StructTag(t.Tag(0)))
}
return Invalid
}
// MessageAPI determines which API is used for the generated message type.
type MessageAPI int
const (
// Invalid indicates the specified type is not a proto message.
Invalid MessageAPI = iota
// OpenAPI indicates a message generated in the open struct API,
// where the message representation is a Go struct with exported fields.
OpenAPI
// HybridAPI indicates a message generated in the hybrid API,
// where the message has properties of both OpenAPI and OpaqueAPI.
HybridAPI
// OpaqueAPI indicates a message generated in the opaque API,
// where the message can only be interacted with through accessor methods.
OpaqueAPI
)
// DetermineAPI determines the message API from a magic struct tag that
// protoc-gen-go emits for all messages.
func determineAPI(tag reflect.StructTag) MessageAPI {
switch s := tag.Get("protogen"); {
case strings.HasPrefix(s, "open."):
return OpenAPI
case strings.HasPrefix(s, "hybrid."):
return HybridAPI
case strings.HasPrefix(s, "opaque."):
return OpaqueAPI
default:
return Invalid
}
}