blob: 267fd0f1f624df86096decf41b63910034ff3ded [file] [log] [blame]
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +05301// 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
5package 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// }
23func 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()
63func 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.
75func ValueOrDefaultBytes(val []byte) []byte {
76 if val == nil {
77 return []byte{}
78 }
79 return val
80}