wa-lang.org/wazero@v1.0.2/experimental/listener.go (about) 1 package experimental 2 3 import ( 4 "context" 5 6 "wa-lang.org/wazero/api" 7 ) 8 9 // FunctionListenerFactoryKey is a context.Context Value key. Its associated value should be a FunctionListenerFactory. 10 // 11 // See https://github.com/tetratelabs/wazero/issues/451 12 type FunctionListenerFactoryKey struct{} 13 14 // FunctionListenerFactory returns FunctionListeners to be notified when a 15 // function is called. 16 type FunctionListenerFactory interface { 17 // NewListener returns a FunctionListener for a defined function. If nil is 18 // returned, no listener will be notified. 19 NewListener(api.FunctionDefinition) FunctionListener 20 } 21 22 // FunctionListener can be registered for any function via 23 // FunctionListenerFactory to be notified when the function is called. 24 type FunctionListener interface { 25 // Before is invoked before a function is called. The returned context will 26 // be used as the context of this function call. 27 // 28 // # Params 29 // 30 // - ctx: the context of the caller function which must be the same 31 // instance or parent of the result. 32 // - def: the function definition. 33 // - paramValues: api.ValueType encoded parameters. 34 Before(ctx context.Context, def api.FunctionDefinition, paramValues []uint64) context.Context 35 36 // After is invoked after a function is called. 37 // 38 // # Params 39 // 40 // - ctx: the context returned by Before. 41 // - def: the function definition. 42 // - err: nil if the function didn't err 43 // - resultValues: api.ValueType encoded results. 44 After(ctx context.Context, def api.FunctionDefinition, err error, resultValues []uint64) 45 } 46 47 // TODO: We need to add tests to enginetest to ensure contexts nest. A good test can use a combination of call and call 48 // indirect in terms of depth and breadth. The test could show a tree 3 calls deep where the there are a couple calls at 49 // each depth under the root. The main thing this can help prevent is accidentally swapping the context internally. 50 51 // TODO: Errors aren't handled, and the After hook should accept one along with the result values. 52 53 // TODO: The context parameter of the After hook is not the same as the Before hook. This means interceptor patterns 54 // are awkward. e.g. something like timing is difficult as it requires propagating a stack. Otherwise, nested calls will 55 // overwrite each other's "since" time. Propagating a stack is further awkward as the After hook needs to know the 56 // position to read from which might be subtle.