Idle
Idle is an asynchronous and hot-reloadable C++ dynamic component framework
Install / Use
/learn @Naios/IdleREADME
Idle is an asynchronous, hot-reloadable, and highly reactive dynamic component framework similar to OSGI that is:
- :package: Modular: Your program logic is encapsulated into services that provide interfaces for usage
- :cyclone: Dynamic: Services can come and go whenever they want, Idle will keep your application stable
- :rocket: Progressive: Your code is recompiled automatically asynchronously into your application
Therefore Idle can improve your workflow significantly through decreased code iteration time and cleaner code-bases based on the SOLID principles, especially interface segregation. Idle is a C++ engine that is capable of hot-reloading large multi-module codebases on the fly through a scheduled dependency graph. What a game engine is to graphics, that is Idle for C++, without targeting a specific domain. Idle can be used for almost any C++ application type e.g. servers, GUIs, or graphic engines.
Traditional solutions to C++ hot-reloading, such as binary patching, usually do not work when headers are modified, files are added, or code is modified out-of-function or even on optimized release builds. Idle solves this by using shared library loading/unloading techniques that are far more powerful than existing solutions, which are usually limited to simple classes and re-loadable loops. Therefore, Idle can automatically reload headers, compilation units, embedded resources and also takes changes of dependencies and build-system files into account.
Additionally, as C++ becomes more asynchronous in the future, the difficult question of how we can effectively use asynchrony in large applications arises. Idle provides simple patterns and solutions to solve such problems. Furthermore, C++ applications can be prototyped rapidly through Idle's asynchronous ecosystem that provides a CLI, logging, configuration, and persistency.
:wrench: Idle is currently in development and therefore not ready for production yet. But, Idle is highly suited already for side-projects, coding playgrounds, and case studies.
Table of Contents
Preview
The following demonstration shows how a multi-module GUI application can be hot-reloaded with Idle:
https://user-images.githubusercontent.com/1146834/133030091-a0e7f2bf-bf5f-4b98-b53a-bed4d802c599.mp4
The actual application shown in this demo is not included in this repository
Features
Dynamic Component System
An application in Idle is based on multiple fundamental concepts:
- idle::Interface: Provides an arbitrary API for implementation
- idle::Service: Provides the actual implementation of a running entity inside the system.
- Clusters that describe a direct relation of an idle::Service to another to allow local configuration.
- Usages that express a relation of an idle::Service to cluster-external entities.
Therefore Idle provides many improvements over traditional dynamic component systems:
- Zero run-time overhead and while your system is stable: references to connected interfaces are cached and not mutated while you possibly could access it (except on request, to ensure your service is always thread-safe).
- Declarative dependencies allow simple dependency configuration without manifests (no XML/JSON).
- For the locale configuration of services idle uses strongly typed property classes instead of bug-prone string key-value pairs. You fetch the global configuration from your dedicated idle::Config service and propagate these back to nested components!
Asynchronous Ecosystem
To build an asynchronous application, Idle provides a feature-rich and ready to use asynchronous ecosystem based on components and interfaces:
- Concurrency abstractions:
- continuable as future/task primitive with optional C++20 coroutine support
- (event-loop) executor and programmer-friendly custom threads.
- Asynchronous PluginHotswap:
- CMake-driven - can reload code in < 2s based on your machine.
- Compatible with MSBuild and Ninja on Windows and make and Ninja on Posix.
- Asynchronous FileWatcher (based on efsw)
- Asynchronous ProcessGroup (base on boost::process)
- Asynchronous Command interface and a default command processor
- A terminal repl with command auto-completion and activity progress indicators (based on replxx).
- Uniform logger facade for pluggable log message sinks (spdlog for example)
- A configuration system based on a custom reflection system that can adapt to any configuration format (TOML currently implemented).
- Changes to the configuration file are detected automatically and dependent services are updated accordingly.
- The configuration file is kept in sync automatically with recently added configuration values and their description.
- A storage system to persist data across hot-swaps using our reflection system or a user-provided byte buffer.
Networking/HTTP abstractions are considered out-of-scope for this project but might be provided through an external module later

Usage Introduction
This short introduction covers only a small part of the functionality of Idle. To get into the framework we provide you various examples that you can try out dynamically inside the Idle CLI.
Managed Lifetime
Because Idle understands the dependencies of your code and data, it can manage its lifetime much better than you could express it manually. Services are lazy by design and provide an asynchronous onStart and onStop override-able method for managing its lifetime. Thus the application start is automatically parallelized and fast, whereas stopping service cleans up resources safely:
class HelloWorldService : public idle::Service {
public:
using Super::Super;
continuable<> onStart() override {
return idle::async([] {
puts("HelloWorldService service is being started!");
});
}
continuable<> onStop() override {
return idle::async([] {
puts("HelloWorldService service is being stopped!");
});
}
};
For initialization, services also provide a thread-safe onInit and onDestroy method that is always dispatched on the same event loop (regardless of the thread that initialized or destroyed the service).
class HelloWorldService : public idle::Service {
public:
using Super::Super;
void onInit() override {
IDLE_ASSERT(root().is_on_event_loop());
}
void sayHello() {
puts("Hello!");
}
};
Initialization always happens automatically before starting the service:
Ref<Context> context = Context::create();
Ref<HelloWorldService> hello_world = idle::spawn<HelloWorldService>(*context);
hello_world->start().then([=] {
hello_world->sayHello();
});
Services not referenced anymore are stopped and garbage-collected automatically.
Eager Services through the Autostarted Interface
Because an idle::Service is lazy by design, we have to start it manually through service->start(). Starting a service automatically is supported by the ecosystem itself, rather than the core system. We can export an idle::Autostarted interface from any service, which causes the service to be started automatically (because a global idle::Autostarter service will create a dependency on it).
class AutostartedService : public idle::Implements<idle::Autostarted> {
public:
using Super::Super;
};
IDLE_DECLARE(AutostartedService)
The IDLE_DECLAREmacro introduces the AutostartedService to the system and can be used in any executable or plugin directly.
Clean Dependencies through Interfaces
Dependencies in idle are expressed in two ways: parent-child relationships and usages.
idle provides many helper classes for expressing dependencies between services, specialized in cardinality (1:1, 1:n), and flexibility (statically or changeable at run-time).
Every helper class creates Usage objects in different ways and can also be created for a custom purpose.
The Dependency class models a 1:1 non-runtime-changeable dependency, for example, we can make our HelloWorldService depend on the idle::Log as following:
class HelloWorldService : public idle::Service {
public:
using Super::Super;
continuable<> onStart() override {
return idle::async([this] {
IDLE_LOG_INFO(log_, "{} is being started!", this->name());
});
}
private:
idle::Dependency<idle::Log> log_{*this};
};
IDLE_DECLARE(HelloWorldService)
