package organ import ( "fmt" ) // HostFunc is a function that performs the same operation as an organ, // implemented in host-side Go. This is the fallback when no organ is // available or all organs fail. type HostFunc func(input []byte) ([]byte, error) // Dispatcher routes operations to the best available organ, falling // back to host-side code if no organ is loaded or all organs fail. // // The fallback hierarchy: // 1. Best WASM organ of the type (highest fitness) // 2. Second-best WASM organ (if any) // 3. Host-side Go implementation (always available) type Dispatcher struct { Registry *Registry Type OrganType Opcode byte Host HostFunc // always-available fallback } // Dispatch sends input through the fallback hierarchy. // Returns the result and which tier produced it (0 = best organ, // 1 = second-best organ, 2 = host fallback). func (d *Dispatcher) Dispatch(input []byte) (result []byte, tier int, err error) { if d.Registry != nil { organs := d.Registry.All(d.Type) for i, org := range organs { result, err = d.Registry.Call(org.Manifest.ID, d.Opcode, input) if err == nil { return result, i, nil } // Organ failed — try next. } } // All organs failed or none loaded — use host fallback. if d.Host == nil { return nil, -1, fmt.Errorf("no organ or host fallback for %s", d.Type) } result, err = d.Host(input) if err != nil { return nil, -1, fmt.Errorf("host fallback: %w", err) } tier = 2 if d.Registry != nil && len(d.Registry.All(d.Type)) > 0 { // Organs existed but all failed. tier = len(d.Registry.All(d.Type)) } return result, tier, nil } // CanDispatch checks whether any organ can handle this input. // Uses the CanDigest opcode (0x01) for enzyme organs. // Returns true if any organ or host reports capability. func (d *Dispatcher) CanDispatch(input []byte) bool { if d.Registry != nil { organs := d.Registry.All(d.Type) for _, org := range organs { result, err := d.Registry.Call(org.Manifest.ID, OpCanDigest, input) if err == nil && len(result) > 0 && result[0] == 0x01 { return true } } } // No organ can handle it — host decides. return d.Host != nil }