Docs
Creating plugins

Creating plugins

A datagen Plugin is a dynamic library that can be loaded by datagen to extend its functionality. The plugin itself is a struct, which implements the Plugin trait. This trait defines the functions that are called by datagen to initialize the plugin and to get the generators, transformers and serializers that are provided by the plugin.

In addition to the Plugin trait, the plugin struct may also implement the PluginConstructor trait. This trait defines a function that is called by datagen to create a new instance of the plugin struct.

In order to expose the plugin to datagen, the plugin needs to be compiled to a dynamic library, exposing a new_plugin function using abi_stable (opens in a new tab). The easiest way of adding this function is by using the declare_plugin! macro.

Plugin creation

First, you need to define a struct, which implements the Plugin trait. The Plugin trait has one function that needs to be implemented: name, which returns the name of the function. The transform, generate and serialize functions are optional and can be implemented if the plugin provides transformers, generators or serializers. The Plugin trait also requires the Debug trait to be implemented.

src/lib.rs
use datagen_rs::plugins::plugin::{Plugin, PluginSerializeCallback};
use datagen_rs::generate::datagen_context::DatagenContextRef;
use datagen_rs::generate::generated_schema::GeneratedSchema;
use serde_json::Value;
 
#[derive(Debug, Default)]
struct MyPlugin;
 
impl Plugin for MyPlugin {
    fn name(&self) -> &'static str {
        "my-plugin"
    }
 
    // Optional: Implement the `generate` function
    // if the plugin provides a generator.
    fn generate(
        &self,
        schema: DatagenContextRef,
        args: Value
    ) -> anyhow::Result<Arc<GeneratedSchema>> {
        // ...
    }
 
    // Optional: Implement the `transform` function
    // if the plugin provides a transformer.
    fn transform(
        &self,
        schema: DatagenContextRef,
        value: Arc<GeneratedSchema>,
        args: Value,
    ) -> anyhow::Result<Arc<GeneratedSchema>> {
        // ...
    }
 
    // Optional: Implement the `serialize` function
    // if the plugin provides a serializer.
    fn serialize(
        &self,
        value: &Arc<GeneratedSchema>,
        args: Value
    ) -> anyhow::Result<String> {
        // ...
    }
 
    fn serialize_with_progress(
        &self,
        value: &Arc<GeneratedSchema>,
        args: Value,
        callback: PluginSerializeCallback,
    ) -> anyhow::Result<String> {
        // ...
    }
}

If your plugin requires arguments for initialization, you can implement the PluginConstructor trait. This trait defines a function that is called by datagen to create a new instance of the plugin struct.

use datagen_rs::plugins::plugin::{PluginConstructor, PluginOptions};
 
impl PluginConstructor for MyPlugin {
    fn new(args: Value, options: PluginOptions) -> anyhow::Result<Self> {
        // ...
    }
}

Exposing the plugin

In order to expose the plugin to datagen, the plugin needs to be compiled to a dynamic library, exposing a get_library and new_plugin function using abi_stable (opens in a new tab). The easiest way of adding these functions is by using the declare_plugin! macro.

use datagen_rs::plugins::plugin::declare_plugin;
 
declare_plugin!(MyPlugin);

If your plugin doesn't implement PluginConstructor, you need to add the constructor call to the declare_plugin! macro.

use datagen_rs::plugins::plugin::declare_plugin;
 
declare_plugin!(MyPlugin, MyPlugin::default);

Compiling the plugin

In order to compile the plugin, you need to add the following to your Cargo.toml:

Cargo.toml
[package]
name = "my-plugin"
version = "0.1.0"
edition = "2021"
 
[lib]
crate-type = ["dylib"]
 
[dependencies]
datagen-rs = { version = "0.1.0", features = ["plugin-abi"] }
abi_stable = "0.11.3"