blob: 606327f9af66cdf24b9d302e80bf40b25f6ff658 [file] [log] [blame]
Joe Tsai90fe9962018-10-18 11:06:29 -07001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Joe Tsai08e00302018-11-26 22:32:06 -08005package legacy
Joe Tsai90fe9962018-10-18 11:06:29 -07006
7import (
8 "bytes"
9 "compress/gzip"
10 "io/ioutil"
11 "sync"
12
13 // TODO: Avoid reliance on old API. However, there is currently a
14 // chicken and egg problem where we need the descriptor protos to implement
15 // the new API.
Joe Tsaieeca8bb2018-12-04 16:24:22 -080016 protoV1 "github.com/golang/protobuf/v2/internal/legacy/protoV1"
Joe Tsaie1f8d502018-11-26 18:55:29 -080017
Joe Tsaieeca8bb2018-12-04 16:24:22 -080018 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Joe Tsaie1f8d502018-11-26 18:55:29 -080019 descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
Joe Tsai90fe9962018-10-18 11:06:29 -070020)
21
22// Every enum and message type generated by protoc-gen-go since commit 2fc053c5
23// on February 25th, 2016 has had a method to get the raw descriptor.
24// Types that were not generated by protoc-gen-go or were generated prior
25// to that version are not supported.
26//
27// The []byte returned is the encoded form of a FileDescriptorProto message
28// compressed using GZIP. The []int is the path from the top-level file
29// to the specific message or enum declaration.
30type (
Joe Tsai6dbffb72018-12-04 14:06:19 -080031 enumV1 interface {
Joe Tsai90fe9962018-10-18 11:06:29 -070032 EnumDescriptor() ([]byte, []int)
33 }
Joe Tsai6dbffb72018-12-04 14:06:19 -080034 messageV1 interface {
Joe Tsai90fe9962018-10-18 11:06:29 -070035 Descriptor() ([]byte, []int)
36 }
37)
38
Joe Tsaie1f8d502018-11-26 18:55:29 -080039var fileDescCache sync.Map // map[*byte]*descriptorpb.FileDescriptorProto
Joe Tsai90fe9962018-10-18 11:06:29 -070040
Joe Tsai6dbffb72018-12-04 14:06:19 -080041// loadFileDesc unmarshals b as a compressed FileDescriptorProto message.
Joe Tsai90fe9962018-10-18 11:06:29 -070042//
43// This assumes that b is immutable and that b does not refer to part of a
44// concatenated series of GZIP files (which would require shenanigans that
45// rely on the concatenation properties of both protobufs and GZIP).
46// File descriptors generated by protoc-gen-go do not rely on that property.
Joe Tsaie1f8d502018-11-26 18:55:29 -080047func loadFileDesc(b []byte) *descriptorpb.FileDescriptorProto {
Joe Tsai90fe9962018-10-18 11:06:29 -070048 // Fast-path: check whether we already have a cached file descriptor.
49 if v, ok := fileDescCache.Load(&b[0]); ok {
Joe Tsaie1f8d502018-11-26 18:55:29 -080050 return v.(*descriptorpb.FileDescriptorProto)
Joe Tsai90fe9962018-10-18 11:06:29 -070051 }
52
53 // Slow-path: decompress and unmarshal the file descriptor proto.
Joe Tsaie1f8d502018-11-26 18:55:29 -080054 m := new(descriptorpb.FileDescriptorProto)
Joe Tsai90fe9962018-10-18 11:06:29 -070055 zr, err := gzip.NewReader(bytes.NewReader(b))
56 if err != nil {
57 panic(err)
58 }
59 b, err = ioutil.ReadAll(zr)
60 if err != nil {
61 panic(err)
62 }
63 // TODO: What about extensions?
64 // The protoV1 API does not eagerly unmarshal extensions.
65 if err := protoV1.Unmarshal(b, m); err != nil {
66 panic(err)
67 }
68 fileDescCache.Store(&b[0], m)
69 return m
70}
Joe Tsai08e00302018-11-26 22:32:06 -080071
72// parentFileDescriptor returns the parent protoreflect.FileDescriptor for the
73// provide descriptor. It returns nil if there is no parent.
74func parentFileDescriptor(d pref.Descriptor) pref.FileDescriptor {
75 for ok := true; ok; d, ok = d.Parent() {
76 if fd, _ := d.(pref.FileDescriptor); fd != nil {
77 return fd
78 }
79 }
80 return nil
81}