wrapperopaque.go raw

   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