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