Export Functions

Guide to export functions from your plugin to be used by other language modules within Plugify.

In the Plugify ecosystem, Go plugins can export functions to make them accessible to other plugins. This guide explains how to define and export functions in Go and provides examples to help you integrate your plugins seamlessly.

Basic Type Mapping

The following table lists how types are exposed to the JavaScript API:

C++ TypeGo TypePlugify AliasRef Support ?
voidvoid (not used in Go)void
boolboolbool
charbytechar8
char16_trunechar16
int8_tint8int8
int16_tint16int16
int32_tint32int32
int64_tint64int64
uint8_tuint8uint8
uint16_tuint16uint16
uint32_tuint32uint32
uint64_tuint64uint64
uintptr_tuintptrptr64
uintptr_tuintptrptr32
floatfloat32float
doublefloat64double
void*unsafe.Pointerfunction
plg::stringstringstring
plg::anyanyany
plg::vector<bool>boolbool
plg::vector<char>bytechar8
plg::vector<char16_t>runechar16
plg::vector<int8_t>int8int8
plg::vector<int16_t>int16int16
plg::vector<int32_t>int32int32
plg::vector<int64_t>int64int64
plg::vector<uint8_t>uint8uint8
plg::vector<uint16_t>uint16uint16
plg::vector<uint32_t>uint32uint32
plg::vector<uint64_t>uint64uint64
plg::vector<uintptr_t>uintptrptr64
plg::vector<uintptr_t>uintptrptr32
plg::vector<float>float32float
plg::vector<double>float64double
plg::vector<plg::string>stringstring
plg::vector<plg::any>anyany
plg::vector<plg::vec2>Vector2vec2
plg::vector<plg::vec3>Vector3vec3
plg::vector<plg::vec4>Vector4vec4
plg::vector<plg::mat4x4>Matrix4x4mat4x4
plg::vec2Vector2vec2
plg::vec3Vector3vec3
plg::vec4Vector4vec4
plg::mat4x4Matrix4x4mat4x4

Exporting Functions in Go

Exporting functions in Go requires marking the functions for export using the //export directive. These functions can then be called by other plugins. Plugify's Go Language Module handles the rest.

Using Generator to Simplify Function Export

The generator.go tool simplifies the process of exporting Go functions by:

  1. Scanning the Plugin Folder: It scans your plugin's root folder to identify functions to export.
  2. Reading the Manifest: It reads the .pplugin manifest file to understand the function signatures and types.
  3. Generating Files: It generates autoexport.go and autoexport.h files with the necessary code to export functions.

This tool eliminates the need for manual marshalling, making it easier for developers to integrate their Go plugins into the Plugify ecosystem.

Basic Example

Here’s a simple example of exporting a function in a Go plugin:

Function Definition

plugin.go
package main

import "C"

func AddNumbers(a int32, b int32) int32 {
    /**
     * Adds two integers.
     *
     * @param a: First integer.
     * @param b: Second integer.
     * @return: Sum of a and b.
     */
    return a + b
}

func main() {} // Required for Go plugins

Plugin Manifest

To export the function, describe it in the plugin manifest under the exportedMethods section:

plugin_name.pplugin
{
  "name": "ExampleGoPlugin",
  "version": "1.0.0",
  "exportedMethods": [
    {
      "name": "AddNumbers",
      "funcName": "__AddNumbers",
      "paramTypes": [
        {
          "type": "int32",
          "name": "a"
        },
        {
          "type": "int32",
          "name": "b"
        }
      ],
      "retType": {
        "type": "int32"
      }
    }
  ]
}

Generated Code

Run the generator.go tool to generate the autoexport.go and autoexport.h files. These files will handle the marshalling of Plugify types to Go types.

autoexport.go
package main

// #include "autoexports.h"
import "C"
import (
    "github.com/untrustedmodders/go-plugify"
    "reflect"
    "unsafe"
)

//export __AddNumbers
func __AddNumbers(a int32, b int32) int32 {
    return AddNumbers(a, b)
}

This generated code handles the conversion of Plugify types to Go types and ensures the function can be called from other plugins.

Advanced Example: Exporting Complex Functions

Here’s an example of exporting a function with complex parameter and return types:

Function Definition

plugin.go
package main

import "C"
import "unsafe"

func ProcessData(data []float64, prefix string) []string {
    /**
     * Processes an array of doubles and returns a formatted string.
     *
     * @param data: Array of double values.
     * @param length: Length of the array.
     * @param prefix: Prefix to add to each value.
     * @return: Formatted string.
     */
    result := ""
    for _, value := range data {
        result += fmt.Sprintf("%s%f", prefix, value)
    }

    return result
}

Plugin Manifest

plugin_name.pplugin
{
  "name": "ExampleGoPlugin",
  "version": "1.0.0",
  "exportedMethods": [
    {
      "name": "ProcessData",
      "funcName": "__ProcessData",
      "paramTypes": [
        {
          "type": "double[]",
          "name": "data"
        },
        {
          "type": "string",
          "name": "prefix"
        }
      ],
      "retType": {
        "type": "string"
      }
    }
  ]
}

Generated Code

Run the generator.go tool to generate the autoexport.go and autoexport.h files. These files will handle the marshalling of Plugify types to Go types.

autoexport.go
package main

// #include "autoexports.h"
import "C"
import (
    "github.com/untrustedmodders/go-plugify"
    "reflect"
    "unsafe"
)

//export __ProcessData
func __ProcessData(data *C.PlgVector, prefix *C.PlgString) C.PlgString {
    __result := ProcessData(plugify.GetVectorDataDouble((*plugify.PlgVector)(unsafe.Pointer(data))), plugify.GetStringData((*plugify.PlgString)(unsafe.Pointer(prefix))))
    __return := plugify.ConstructString(__result)
    return *(*C.String)(unsafe.Pointer(&__return))
}

This generated code handles the conversion of Plugify types to Go types and ensures the function can be called from other plugins.

Handling Callbacks

Plugify allows you to export functions that accept callbacks as parameters. Here’s an example:

Function Definition

plugin.go
package main

import "C"

func ExecuteWithCallback(value int32, inputStr string, callback PlugifyCallback) {
    /**
     * Executes a callback function with the provided parameters.
     *
     * @param value: Integer value.
     * @param inputStr: Input string.
     * @param callback: Callback function to execute.
     */
    result := callback(value, inputStr)
    fmt.Printf("Callback result: %s\n", result)
}

Plugin Manifest

plugin_name.pplugin
{
  "name": "ExampleGoPlugin",
  "version": "1.0.0",
  "exportedMethods": [
    {
      "name": "ExecuteWithCallback",
      "funcName": "__ExecuteWithCallback",
      "paramTypes": [
        {
          "type": "int32",
          "name": "value"
        },
        {
          "type": "string",
          "name": "inputStr"
        },
        {
          "type": "function",
          "name": "callback",
          "prototype": {
            "name": "ExampleCallback",
            "funcName": "__ExampleCallback",
            "paramTypes": [
              {
                "type": "int32",
                "name": "value"
              },
              {
                "type": "string",
                "name": "inputStr"
              }
            ],
            "retType": {
              "type": "string"
            }
          }
        }
      ],
      "retType": {
        "type": "void"
      }
    }
  ]
}

Generated Code

Run the generator.go tool to generate the autoexport.go and autoexport.h files. These files will handle the marshalling of Plugify types to Go types.

autoexport.go
package main

// #include "autoexports.h"
import "C"
import (
    "github.com/untrustedmodders/go-plugify"
    "reflect"
    "unsafe"
)

//export __ExecuteWithCallback
func __ExecuteWithCallback(value int32, inputStr *C.PlgString, callback unsafe.Pointer) {
    ExecuteWithCallback(value, plugify.GetStringData((*plugify.PlgString)(unsafe.Pointer(inputStr))), plugify.GetDelegateForFunctionPointer(callback, reflect.TypeOf(PlugifyCallback(nil))).(PlugifyCallback))
}

This generated code handles the conversion of Plugify types to Go types and ensures the function can be called from other plugins.

Best Practices

  1. Use //export: Always use the //export directive to mark functions for export.
  2. Follow Type Conventions: Adhere to Plugify's type conventions for parameters and return values.
  3. Document Your Functions: Clearly document the purpose, parameters, and return values of exported functions.
  4. Test Thoroughly: Test your exported functions to ensure they work as expected when called by other plugins.
  5. Update the Manifest: Always describe exported functions in the plugin manifest under the exportedMethods section.

Conclusion

Exporting functions in Go plugins is straightforward when you follow Plugify's conventions and best practices. By using the //export directive, adhering to type conventions, and describing functions in the plugin manifest, you can create robust and interoperable plugins. For more advanced use cases, such as handling callbacks, use the techniques outlined in this guide.