github.com/Big-big-orange/protoreflect@v0.0.0-20240408141420-285cedfdf6a4/desc/internal/source_info.go (about)

     1  package internal
     2  
     3  import (
     4  	"google.golang.org/protobuf/types/descriptorpb"
     5  )
     6  
     7  // SourceInfoMap is a map of paths in a descriptor to the corresponding source
     8  // code info.
     9  type SourceInfoMap map[string][]*descriptorpb.SourceCodeInfo_Location
    10  
    11  // Get returns the source code info for the given path. If there are
    12  // multiple locations for the same path, the first one is returned.
    13  func (m SourceInfoMap) Get(path []int32) *descriptorpb.SourceCodeInfo_Location {
    14  	v := m[asMapKey(path)]
    15  	if len(v) > 0 {
    16  		return v[0]
    17  	}
    18  	return nil
    19  }
    20  
    21  // GetAll returns all source code info for the given path.
    22  func (m SourceInfoMap) GetAll(path []int32) []*descriptorpb.SourceCodeInfo_Location {
    23  	return m[asMapKey(path)]
    24  }
    25  
    26  // Add stores the given source code info for the given path.
    27  func (m SourceInfoMap) Add(path []int32, loc *descriptorpb.SourceCodeInfo_Location) {
    28  	m[asMapKey(path)] = append(m[asMapKey(path)], loc)
    29  }
    30  
    31  // PutIfAbsent stores the given source code info for the given path only if the
    32  // given path does not exist in the map. This method returns true when the value
    33  // is stored, false if the path already exists.
    34  func (m SourceInfoMap) PutIfAbsent(path []int32, loc *descriptorpb.SourceCodeInfo_Location) bool {
    35  	k := asMapKey(path)
    36  	if _, ok := m[k]; ok {
    37  		return false
    38  	}
    39  	m[k] = []*descriptorpb.SourceCodeInfo_Location{loc}
    40  	return true
    41  }
    42  
    43  func asMapKey(slice []int32) string {
    44  	// NB: arrays should be usable as map keys, but this does not
    45  	// work due to a bug: https://github.com/golang/go/issues/22605
    46  	//rv := reflect.ValueOf(slice)
    47  	//arrayType := reflect.ArrayOf(rv.Len(), rv.Type().Elem())
    48  	//array := reflect.New(arrayType).Elem()
    49  	//reflect.Copy(array, rv)
    50  	//return array.Interface()
    51  
    52  	b := make([]byte, len(slice)*4)
    53  	j := 0
    54  	for _, s := range slice {
    55  		b[j] = byte(s)
    56  		b[j+1] = byte(s >> 8)
    57  		b[j+2] = byte(s >> 16)
    58  		b[j+3] = byte(s >> 24)
    59  		j += 4
    60  	}
    61  	return string(b)
    62  }
    63  
    64  // CreateSourceInfoMap constructs a new SourceInfoMap and populates it with the
    65  // source code info in the given file descriptor proto.
    66  func CreateSourceInfoMap(fd *descriptorpb.FileDescriptorProto) SourceInfoMap {
    67  	res := SourceInfoMap{}
    68  	PopulateSourceInfoMap(fd, res)
    69  	return res
    70  }
    71  
    72  // PopulateSourceInfoMap populates the given SourceInfoMap with information from
    73  // the given file descriptor.
    74  func PopulateSourceInfoMap(fd *descriptorpb.FileDescriptorProto, m SourceInfoMap) {
    75  	for _, l := range fd.GetSourceCodeInfo().GetLocation() {
    76  		m.Add(l.Path, l)
    77  	}
    78  }
    79  
    80  // NB: This wonkiness allows desc.Descriptor impl to implement an interface that
    81  // is only usable from this package, by embedding a SourceInfoComputeFunc that
    82  // implements the actual logic (which must live in desc package to avoid a
    83  // dependency cycle).
    84  
    85  // SourceInfoComputer is a single method which will be invoked to recompute
    86  // source info. This is needed for the protoparse package, which needs to link
    87  // descriptors without source info in order to interpret options, but then needs
    88  // to re-compute source info after that interpretation so that final linked
    89  // descriptors expose the right info.
    90  type SourceInfoComputer interface {
    91  	recomputeSourceInfo()
    92  }
    93  
    94  // SourceInfoComputeFunc is the type that a desc.Descriptor will embed. It will
    95  // be aliased in the desc package to an unexported name so it is not marked as
    96  // an exported field in reflection and not present in Go docs.
    97  type SourceInfoComputeFunc func()
    98  
    99  func (f SourceInfoComputeFunc) recomputeSourceInfo() {
   100  	f()
   101  }
   102  
   103  // RecomputeSourceInfo is used to initiate recomputation of source info. This is
   104  // is used by the protoparse package, after it interprets options.
   105  func RecomputeSourceInfo(c SourceInfoComputer) {
   106  	c.recomputeSourceInfo()
   107  }