// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package proto // ValueOrNil returns nil if has is false, or a pointer to a new variable // containing the value returned by the specified getter. // // This function is similar to the wrappers (proto.Int32(), proto.String(), // etc.), but is generic (works for any field type) and works with the hasser // and getter of a field, as opposed to a value. // // This is convenient when populating builder fields. // // Example: // // hop := attr.GetDirectHop() // injectedRoute := ripb.InjectedRoute_builder{ // Prefixes: route.GetPrefixes(), // NextHop: proto.ValueOrNil(hop.HasAddress(), hop.GetAddress), // } func ValueOrNil[T any](has bool, getter func() T) *T { if !has { return nil } v := getter() return &v } // ValueOrDefault returns the protobuf message val if val is not nil, otherwise // it returns a pointer to an empty val message. // // This function allows for translating code from the old Open Struct API to the // new Opaque API. // // The old Open Struct API represented oneof fields with a wrapper struct: // // var signedImg *accountpb.SignedImage // profile := &accountpb.Profile{ // // The Avatar oneof will be set, with an empty SignedImage. // Avatar: &accountpb.Profile_SignedImage{signedImg}, // } // // The new Opaque API treats oneof fields like regular fields, there are no more // wrapper structs: // // var signedImg *accountpb.SignedImage // profile := &accountpb.Profile{} // profile.SetSignedImage(signedImg) // // For convenience, the Opaque API also offers Builders, which allow for a // direct translation of struct initialization. However, because Builders use // nilness to represent field presence (but there is no non-nil wrapper struct // anymore), Builders cannot distinguish between an unset oneof and a set oneof // with nil message. The above code would need to be translated with help of the // ValueOrDefault function to retain the same behavior: // // var signedImg *accountpb.SignedImage // return &accountpb.Profile_builder{ // SignedImage: proto.ValueOrDefault(signedImg), // }.Build() func ValueOrDefault[T interface { *P Message }, P any](val T) T { if val == nil { return T(new(P)) } return val } // ValueOrDefaultBytes is like ValueOrDefault but for working with fields of // type []byte. func ValueOrDefaultBytes(val []byte) []byte { if val == nil { return []byte{} } return val }