Although I am no longer primarily working as a developer, I continue to follow technical concepts with interest. I recently conducted a small experiment in Rust to get a better feel for the language. The goal was to map out a simple Core & Plugin architecture.

Rust offers interesting approaches for such architectures through its type system. The objective was to see how a modular structure can be built where a core system is extended by external modules.

The Implementation

1. The Plugin Trait

The basis is a Trait. This defines the necessary methods that every plugin must implement:

pub trait Plugin {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn process(&self, text: &str) -> String;
}

2. The Core Structure

The Core manages the plugins in a vector. Since the plugins can have different underlying types, Box<dyn Plugin> is used.

pub struct Core {
    plugins: Vec<Box<dyn Plugin>>,
}

impl Core {
    pub fn new() -> Self {
        Core {
            plugins: Vec::new(),
        }
    }

    pub fn register_plugin(&mut self, plugin: Box<dyn Plugin>) {
        println!("Registering plugin: {}", plugin.name());
        self.plugins.push(plugin);
    }
}

3. Implementation

For the experiment, various simple plugins were created (e.g., WordCounter, CaseConverter). The registration is done collectively:

pub fn register_all_plugins(core: &mut Core) {
    core.register_plugin(Box::new(word_counter::WordCounterPlugin::new()));
    core.register_plugin(Box::new(text_search::TextSearchPlugin::new()));
    core.register_plugin(Box::new(case_converter::CaseConverterPlugin::new()));
}

Real-World Applications

In practice, such architectures are used whenever systems need to remain extensible without modifying the core code. Typical examples include text editors or IDEs that support new languages through plugins, or CLI tools that can be customized for specific workflows. This modular setup is also common in web servers (as middleware) or data processing pipelines where various filters are applied sequentially to a data stream.

Well-known open-source projects that rely heavily on modularity in a similar way include:

  • Nushell: A modern shell whose functionality can be almost entirely extended through plugins.
  • Zellij: A terminal workspace that uses WebAssembly (WASM) to load isolated plugins.
  • Bevy: A powerful game engine designed so that even core features are implemented as interchangeable plugins.

Conclusion

The approach is functional and demonstrates how Rust handles dynamic dispatch. The strict requirements of the compiler ensure that interfaces must be cleanly defined. It was a useful attempt to better understand working with traits and box types in Rust.