ActorSimulationCodegen

Copy Markdown View Source

Turn an actor_simulation model into a runnable project in another language: C++ (CAF or OMNeT++), Go (Phony), Pony, Rust (Ractor) or Java (VLINGO XOOM). Each generated project comes with build files, a CI workflow, a test suite and, for every target but OMNeT++, callback interfaces, so behaviour can be customised without editing generated code.

Prototype in Elixir where a simulated hour takes a millisecond, then take the same model to production.

Hex.pm Documentation

The family

PackageWhat it is forAdd it when
gen_server_virtual_timevirtual clock, GenServer/gen_statem wrappersyou test code with timers
gen_server_virtual_time_migratemix virtual_time.migrate rewrites GenServer codeyou already have servers and want to keep them
actor_simulationactor-system DSL, statistics, sequence diagramsyou model parts of a system talking to each other
actor_simulation_codegen (this one)generate runnable projects in six runtimesyou want the same model in another language

This package depends on actor_simulation, which brings gen_server_virtual_time with it.

Install

def deps do
  [{:actor_simulation_codegen, "~> 1.0.1"}]
end

Targets

GeneratorLanguageFrameworkOutput
CAFC++C++ Actor FrameworkTyped actors, CMake build, Conan deps, tests
PhonyGoPhonyZero-alloc actors, Go modules, tests
PonyPonyPony LanguageType-safe actors, Corral deps, PonyTest
RactorRustRactorGen_server-inspired, Cargo, async/await
VLINGOJavaVLINGO XOOMProtocol actors, Maven, JUnit 5
OMNeT++C++OMNeT++Discrete-event simulation, NED files, CMake

Each is generated from the same simulation:

simulation = ActorSimulation.new()
|> ActorSimulation.add_actor(:publisher,
    send_pattern: {:periodic, 100, :event},
    targets: [:sub1, :sub2, :sub3])
|> ActorSimulation.add_actor(:sub1)
|> ActorSimulation.add_actor(:sub2)
|> ActorSimulation.add_actor(:sub3)

# C++ with the C++ Actor Framework
{:ok, files} = ActorSimulation.CAFGenerator.generate(simulation,
  project_name: "PubSubActors",
  enable_callbacks: true)
ActorSimulation.CAFGenerator.write_to_directory(files, "caf_output/")

# Go with Phony
{:ok, files} = ActorSimulation.PhonyGenerator.generate(simulation,
  project_name: "pubsub",
  enable_callbacks: true)
ActorSimulation.PhonyGenerator.write_to_directory(files, "phony_output/")

# Rust with Ractor
{:ok, files} = ActorSimulation.RactorGenerator.generate(simulation,
  project_name: "pubsub",
  enable_callbacks: true)
ActorSimulation.RactorGenerator.write_to_directory(files, "ractor_output/")

Then build the output with its own toolchain — each generated project ships a README.md with the exact commands:

TargetBuild
CAFcmake + conan
OMNeT++cmake (NED files and a runnable config)
Ponymake (Corral for dependencies)
Phonygo test ./...
Ractorcargo test
VLINGOmvn compile exec:exec (forked JVM)

Callback interfaces let you change behaviour without touching generated files:

// CAF: publisher_callbacks_impl.cpp
void publisher_callbacks::on_event() {
  log_to_database();
  send_metrics();
}
// Ractor: publisher.rs
impl PublisherCallbacks for MyPublisherCallbacks {
    fn on_event(&self) {
        println!("Publishing event with custom handler");
    }
}

Guides

License

MIT License - See the LICENSE file for details.