Skip to content

Instantly share code, notes, and snippets.

@edfletcher
Created February 5, 2023 22:21
Show Gist options
  • Select an option

  • Save edfletcher/ffbf99622dbef6e616fb75c0ce787059 to your computer and use it in GitHub Desktop.

Select an option

Save edfletcher/ffbf99622dbef6e616fb75c0ce787059 to your computer and use it in GitHub Desktop.
loadPlugin.go
func loadPlugin(path string) (*PluginImpl, error) {
ifaceType := reflect.TypeOf((*Plugin)(nil)).Elem()
pluginLoad, err := plugin.Open(path)
if err != nil {
return nil, err
}
// without stubbing the fields, reflect.ValueOf(...).Elem().FieldByName(...) below will return nil
newPlugin := newPluginImpl()
// for each method declared in the interface, look for the same-named concrete defintion
// in the loaded plugin. if that exists, find the field in the concrete implementation
// instance (PluginImpl) and set each function pointer accordingly
for i := 0; i < ifaceType.NumMethod(); i++ {
methodName := ifaceType.Method(i).Name
pluginMethod, err := pluginLoad.Lookup(methodName)
if err != nil {
return nil, err
}
implValue := reflect.ValueOf(&newPlugin).Elem()
if implValue.IsZero() {
return nil, fmt.Errorf("unable to get value of concrete impl")
}
implElem := implValue.FieldByName(methodName)
if implElem.IsZero() {
return nil, fmt.Errorf("unable to set value on concrete impl")
}
// must .Convert to the target type (implElem.Interface()), else will panic with a strangely-worded error:
// "reflect.Set: value of type T is not assignable to type T"
// (not a typo: the 'from' and 'to' types in the error message will be exactly the same, because
// indeed if we've made it this far the types will match, hence why .Convert() succeeds!)
implElem.Set(reflect.ValueOf(pluginMethod).Convert(reflect.TypeOf(implElem.Interface())))
}
return &newPlugin, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment