1 // Copyright 2024 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 5 package proto
6 7 // ValueOrNil returns nil if has is false, or a pointer to a new variable
8 // containing the value returned by the specified getter.
9 //
10 // This function is similar to the wrappers (proto.Int32(), proto.String(),
11 // etc.), but is generic (works for any field type) and works with the hasser
12 // and getter of a field, as opposed to a value.
13 //
14 // This is convenient when populating builder fields.
15 //
16 // Example:
17 //
18 // hop := attr.GetDirectHop()
19 // injectedRoute := ripb.InjectedRoute_builder{
20 // Prefixes: route.GetPrefixes(),
21 // NextHop: proto.ValueOrNil(hop.HasAddress(), hop.GetAddress),
22 // }
23 func ValueOrNil[T any](has bool, getter func() T) *T {
24 if !has {
25 return nil
26 }
27 v := getter()
28 return &v
29 }
30 31 // ValueOrDefault returns the protobuf message val if val is not nil, otherwise
32 // it returns a pointer to an empty val message.
33 //
34 // This function allows for translating code from the old Open Struct API to the
35 // new Opaque API.
36 //
37 // The old Open Struct API represented oneof fields with a wrapper struct:
38 //
39 // var signedImg *accountpb.SignedImage
40 // profile := &accountpb.Profile{
41 // // The Avatar oneof will be set, with an empty SignedImage.
42 // Avatar: &accountpb.Profile_SignedImage{signedImg},
43 // }
44 //
45 // The new Opaque API treats oneof fields like regular fields, there are no more
46 // wrapper structs:
47 //
48 // var signedImg *accountpb.SignedImage
49 // profile := &accountpb.Profile{}
50 // profile.SetSignedImage(signedImg)
51 //
52 // For convenience, the Opaque API also offers Builders, which allow for a
53 // direct translation of struct initialization. However, because Builders use
54 // nilness to represent field presence (but there is no non-nil wrapper struct
55 // anymore), Builders cannot distinguish between an unset oneof and a set oneof
56 // with nil message. The above code would need to be translated with help of the
57 // ValueOrDefault function to retain the same behavior:
58 //
59 // var signedImg *accountpb.SignedImage
60 // return &accountpb.Profile_builder{
61 // SignedImage: proto.ValueOrDefault(signedImg),
62 // }.Build()
63 func ValueOrDefault[T interface {
64 *P
65 Message
66 }, P any](val T) T {
67 if val == nil {
68 return T(new(P))
69 }
70 return val
71 }
72 73 // ValueOrDefaultBytes is like ValueOrDefault but for working with fields of
74 // type []byte.
75 func ValueOrDefaultBytes(val []byte) []byte {
76 if val == nil {
77 return []byte{}
78 }
79 return val
80 }
81