wrapperopaque.go

 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
 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}