1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
package config
import (
"fmt"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
)
// Because you followed autogenpb's advice (you did follow it right?) you now
// win the automation lottery.
//
// for this .proto file, GetProtobufName(pb) returns "repos"
// Then, ConfigLoad(), ConfigSave(), CacheLoad() and CacheSave()
// all do exactly what is expected:
//
// Automatically work with the files:
//
// ~/.config/<appname>/repos.pb
//
// or
//
// ~/.cache/<appname/repos.pb
//
// message Repos {
// string uuid = 1;
// string version = 2;
// repeated Repo repos = 3;
func GetProtobufName(pb proto.Message) (string, error) {
// 1. Get the protoreflect.Message interface.
msg := pb.ProtoReflect()
// 2. Get the message's descriptor.
descriptor := msg.Descriptor()
// 3. Get all the field descriptors for the message.
fields := descriptor.Fields()
// find string "uuid"
fieldNumber := protoreflect.FieldNumber(1)
fieldDescriptor := fields.ByNumber(fieldNumber)
if fieldDescriptor == nil {
return "", fmt.Errorf("message %q has no field with number 1", descriptor.FullName())
}
if fieldDescriptor.Name() != "uuid" {
return "", fmt.Errorf("message %q field(1) != 'uuid' is (%s)", descriptor.FullName(), fieldDescriptor.Name())
}
// find string "version"
fieldNumber = protoreflect.FieldNumber(2)
fieldDescriptor = fields.ByNumber(fieldNumber)
if fieldDescriptor == nil {
return "", fmt.Errorf("message %q has no field(2)", descriptor.FullName())
}
if fieldDescriptor.Name() != "version" {
return "", fmt.Errorf("message %q field(2) != 'version' is (%s)", descriptor.FullName(), fieldDescriptor.Name())
}
// 4. Find the field descriptor specifically by its number (3).
// This is the crucial step.
fieldNumber = protoreflect.FieldNumber(3)
fieldDescriptor = fields.ByNumber(fieldNumber)
// 5. Add some safety checks.
if fieldDescriptor == nil {
return "", fmt.Errorf("message %q has no field with number 3", descriptor.FullName())
}
// Optional but recommended: verify it's a repeated field as you expect.
// IsList() is the reflection equivalent of `repeated`.
if !fieldDescriptor.IsList() {
return "", fmt.Errorf("field with number 3 (%q) is not a repeated field", fieldDescriptor.Name())
}
// 6. Get the name from the descriptor and return it.
// The name is of type protoreflect.Name, so we cast it to a string.
return string(fieldDescriptor.Name()), nil
}
func GetThirdFieldName(pb proto.Message) (string, error) {
// 1. Get the protoreflect.Message interface.
msg := pb.ProtoReflect()
// 2. Get the message's descriptor.
descriptor := msg.Descriptor()
// 3. Get all the field descriptors for the message.
fields := descriptor.Fields()
// 4. Find the field descriptor specifically by its number (3).
// This is the crucial step.
fieldNumber := protoreflect.FieldNumber(3)
fieldDescriptor := fields.ByNumber(fieldNumber)
// 5. Add some safety checks.
if fieldDescriptor == nil {
return "", fmt.Errorf("message %q has no field with number 3", descriptor.FullName())
}
// Optional but recommended: verify it's a repeated field as you expect.
// IsList() is the reflection equivalent of `repeated`.
if !fieldDescriptor.IsList() {
return "", fmt.Errorf("field with number 3 (%q) is not a repeated field", fieldDescriptor.Name())
}
// 6. Get the name from the descriptor and return it.
// The name is of type protoreflect.Name, so we cast it to a string.
return string(fieldDescriptor.Name()), nil
}
|