blob: 9a123c2b27c766591d4ec6c33a6bffe00173976e [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
5package impl
6
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.
16 protoV1 "github.com/golang/protobuf/proto"
17 descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
18)
19
20// Every enum and message type generated by protoc-gen-go since commit 2fc053c5
21// on February 25th, 2016 has had a method to get the raw descriptor.
22// Types that were not generated by protoc-gen-go or were generated prior
23// to that version are not supported.
24//
25// The []byte returned is the encoded form of a FileDescriptorProto message
26// compressed using GZIP. The []int is the path from the top-level file
27// to the specific message or enum declaration.
28type (
29 legacyEnum interface {
30 EnumDescriptor() ([]byte, []int)
31 }
32 legacyMessage interface {
33 Descriptor() ([]byte, []int)
34 }
35)
36
37var fileDescCache sync.Map // map[*byte]*descriptorV1.FileDescriptorProto
38
39// loadFileDesc unmarshals b as a compressed FileDescriptorProto message.
40//
41// This assumes that b is immutable and that b does not refer to part of a
42// concatenated series of GZIP files (which would require shenanigans that
43// rely on the concatenation properties of both protobufs and GZIP).
44// File descriptors generated by protoc-gen-go do not rely on that property.
45func loadFileDesc(b []byte) *descriptorV1.FileDescriptorProto {
46 // Fast-path: check whether we already have a cached file descriptor.
47 if v, ok := fileDescCache.Load(&b[0]); ok {
48 return v.(*descriptorV1.FileDescriptorProto)
49 }
50
51 // Slow-path: decompress and unmarshal the file descriptor proto.
52 m := new(descriptorV1.FileDescriptorProto)
53 zr, err := gzip.NewReader(bytes.NewReader(b))
54 if err != nil {
55 panic(err)
56 }
57 b, err = ioutil.ReadAll(zr)
58 if err != nil {
59 panic(err)
60 }
61 // TODO: What about extensions?
62 // The protoV1 API does not eagerly unmarshal extensions.
63 if err := protoV1.Unmarshal(b, m); err != nil {
64 panic(err)
65 }
66 fileDescCache.Store(&b[0], m)
67 return m
68}