github.com/hsfzxjy/dgo/go@v0.2.0/go_callback.go (about) 1 package dgo 2 3 import ( 4 "fmt" 5 "log" 6 "reflect" 7 ) 8 9 func (p *Port) Pend(callback any) GoCallback { 10 callbackV := reflect.ValueOf(callback) 11 if callbackV.Kind() != reflect.Func { 12 panic("dgo:go: callback must be a function") 13 } 14 15 var callbackId uint64 16 for n := 0; n < 10; n++ { 17 callbackId = uint64(p.nextCallbackId.Add(1)) 18 _, loaded := p.goCallbacks.LoadOrStore(callbackId, callbackV) 19 if !loaded { 20 goto STORE_SUCCESS 21 } 22 } 23 panic(fmt.Sprintf("dgo:go: too many callbacks pending on %s", p)) 24 25 STORE_SUCCESS: 26 return GoCallback{callbackId, p} 27 } 28 29 func Pend(callback any, port *Port) GoCallback { 30 return portMap.ResolvePort(port).Pend(callback) 31 } 32 33 type GoCallback struct { 34 id uint64 // Id (32 bits) 35 port *Port 36 } 37 38 var _ _Serializable = GoCallback{} 39 40 func (cb GoCallback) specialInt() {} 41 func (cb GoCallback) getKind() _SpecialIntKind { return sikGoCallback } 42 func (cb GoCallback) getPayload() uint64 { return cb.id } 43 44 func (gcb *GoCallback) Remove() { 45 gcb.port.goCallbacks.Delete(gcb.id) 46 } 47 48 func (gcb *GoCallback) Exists() bool { 49 _, loaded := gcb.port.goCallbacks.Load(gcb.id) 50 return loaded 51 } 52 53 type invokingGoCallback struct { 54 payload uint64 // Flag (16 bits) | Id (32 bits) 55 port *Port 56 } 57 58 func (cb invokingGoCallback) String() string { 59 return fmt.Sprintf("invokingGoCallback[payload=%016X, port=%s]", cb.payload, cb.port) 60 } 61 62 func (cb invokingGoCallback) specialInt() {} 63 64 func (cb invokingGoCallback) handleCObjects(objs []*Dart_CObject) { 65 id := cb.payload & callbackIdMask 66 cf := CallbackFlag(cb.payload) 67 68 var ( 69 callbackV reflect.Value 70 loaded bool 71 ) 72 73 if cf.HasFallible() { 74 defer func() { 75 if p := recover(); p != nil { 76 log.Printf("%+v\n", p) 77 } 78 }() 79 } 80 81 if cf.HasPop() { 82 callbackV, loaded = cb.port.goCallbacks.LoadAndDelete(id) 83 } else { 84 callbackV, loaded = cb.port.goCallbacks.Load(id) 85 } 86 if !loaded { 87 panic(fmt.Sprintf("dgo:go: go callback not exist, %s", cb)) 88 } 89 90 hasPackArray := cf.HasPackArray() 91 92 var values []reflect.Value 93 var args []any 94 95 if hasPackArray { 96 args = make([]any, 0, len(objs)+2) 97 } else { 98 values = make([]reflect.Value, 0, len(objs)+2) 99 } 100 101 if cf.HasWithContext() { 102 context := &InvokeContext{cf, cb.port} 103 if hasPackArray { 104 args = append(args, context) 105 } else { 106 values = append(values, reflect.ValueOf(context)) 107 } 108 } 109 if cf.HasFast() { 110 if len(objs) != 0 { 111 panic(fmt.Sprintf("dgo:go: expect zero argument when called with FAST flag, %s", cb)) 112 } 113 var arg any 114 switch cf.FastKind() { 115 case CFFK_VOID: 116 goto SKIP 117 case CFFK_NIL: 118 if hasPackArray { 119 args = append(args, nil) 120 } else { 121 values = append(values, reflect.ValueOf(&arg).Elem()) 122 } 123 goto SKIP 124 case CFFK_NO: 125 arg = false 126 case CFFK_YES: 127 arg = true 128 } 129 if hasPackArray { 130 args = append(args, arg) 131 } else { 132 values = append(values, reflect.ValueOf(arg)) 133 } 134 SKIP: 135 } else { 136 for _, obj := range objs { 137 arg := cobjectParse(cb.port, obj) 138 if hasPackArray { 139 args = append(args, arg) 140 } else if arg == nil { 141 values = append(values, reflect.ValueOf(&arg).Elem()) 142 } else { 143 values = append(values, reflect.ValueOf(arg)) 144 } 145 } 146 } 147 if hasPackArray { 148 values = []reflect.Value{reflect.ValueOf(args)} 149 } 150 callbackV.Call(values) 151 }