handle.mx raw

   1  // Package unique implements the upstream Go unique package for Moxie.
   2  //
   3  // It is not a full implementation: while it should behave the same way, it
   4  // doesn't free unreferenced uniqued objects.
   5  package unique
   6  
   7  import (
   8  	"sync"
   9  	"unsafe"
  10  )
  11  
  12  var (
  13  	// We use a two-level map because that way it's easier to store and retrieve
  14  	// values.
  15  	globalMap map[unsafe.Pointer]any // map value type is always map[T]Handle[T]
  16  
  17  	globalMapMutex sync.Mutex
  18  )
  19  
  20  // Unique handle for the given value. Comparing two handles is cheap.
  21  type Handle[T comparable] struct {
  22  	value *T
  23  }
  24  
  25  // Value returns a shallow copy of the T value that produced the Handle.
  26  func (h Handle[T]) Value() T {
  27  	return *h.value
  28  }
  29  
  30  // Make a new unqique handle for the given value.
  31  func Make[T comparable](value T) Handle[T] {
  32  	// Very simple implementation of the unique package. This is much, *much*
  33  	// simpler than the upstream implementation. Sadly it's not possible to
  34  	// reuse the upstream version because it relies on implementation details of
  35  	// the upstream runtime.
  36  	// It probably isn't as efficient as the upstream version, but the first
  37  	// goal here is compatibility. If the performance is a problem, it can be
  38  	// optimized later.
  39  
  40  	globalMapMutex.Lock()
  41  
  42  	// The map isn't initialized at program startup (and after a test run), so
  43  	// create it.
  44  	if globalMap == nil {
  45  		globalMap = map[unsafe.Pointer]any{}
  46  	}
  47  
  48  	// Retrieve the type-specific map, creating it if not yet present.
  49  	typeptr, _ := decomposeInterface(value)
  50  	var typeSpecificMap map[T]Handle[T]
  51  	if typeSpecificMapValue, ok := globalMap[typeptr]; !ok {
  52  		typeSpecificMap = map[T]Handle[T]{}
  53  		globalMap[typeptr] = typeSpecificMap
  54  	} else {
  55  		typeSpecificMap = typeSpecificMapValue.(map[T]Handle[T])
  56  	}
  57  
  58  	// Retrieve the handle for the value, creating it if it isn't created yet.
  59  	var handle Handle[T]
  60  	if h, ok := typeSpecificMap[value]; !ok {
  61  		var clone T = value
  62  		handle.value = &clone
  63  		typeSpecificMap[value] = handle
  64  	} else {
  65  		handle = h
  66  	}
  67  
  68  	globalMapMutex.Unlock()
  69  
  70  	return handle
  71  }
  72  
  73  //go:linkname decomposeInterface runtime.decomposeInterface
  74  func decomposeInterface(i interface{}) (unsafe.Pointer, unsafe.Pointer)
  75