Skip to main content

Crate cordis

Crate cordis 

Source
Expand description

Cordis is a context-based plugin framework with scoped dependency injection, lifecycle-owned effects, events, configuration interception, and structured logging.

This crate is a Rust port of @deepseek-ai/cordis 4.x. The JavaScript implementation relies heavily on proxies, prototype chains, callable objects, and decorators. The Rust API keeps the same runtime model while replacing those language features with explicit, typed methods.

Naming note: the package is published as cordis-rs, but the library name and import path are cordis (matching upstream), and the sources live under crates/cordis in the repository.

§Quick start

use cordis::{plugin_sync, Context, Inject, PluginOutput};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

let root = Context::new();
let counter = Arc::new(AtomicUsize::new(0));
let _counter_effect = root.provide_arc("counter", counter.clone()).unwrap();

let greeter = plugin_sync::<(), _>("greeter", Inject::new(["counter"]),
    |ctx, _config| {
        let counter = ctx.require::<AtomicUsize>("counter")?;
        counter.fetch_add(1, Ordering::SeqCst);
        Ok(PluginOutput::default())
    });

let fiber = root.plugin(greeter, ());
fiber.try_wait().unwrap();
assert_eq!(counter.load(Ordering::SeqCst), 1);
fiber.dispose().unwrap();

§Naming vocabulary

The API keeps upstream Cordis verbs (emit, bail, waterfall, serial, parallel, on, once, provide, get, set, inject, isolate, intercept, effect, plugin, accessor, require, notify) and renames them only when a Rust convention conflicts strongly (e.g. Event::call_next instead of upstream’s next(), which collides with Iterator::next). The suffix/prefix conventions:

  • *_value — type-erased (Value/Config) variant; resolved_* — evaluated (as opposed to static) result; with_* — builder or “with extra parameter” variant; *Service — context-bound service facade.
  • is_/has_ — predicates; assert_ — panics (fallible checks are ensure_, e.g. Fiber::ensure_active); *_unchecked is reserved for genuinely unsafe APIs (this crate has none).
  • as_ — cheap borrow; to_ — expensive copy; into_ — ownership transfer.
  • _async suffixes mark genuinely suspending functions. The one exception is Fiber::dispose_async, kept for upstream parity with disposeAsync: it is a synchronous pass-through that never yields.

§Intercept meta-events

The five upstream interception points are ported as ordinary events on the root bus, named internal/get, internal/set, internal/config, internal/update, and internal/listener. Each fires with the operating context as its dispatch target, so context filters apply, and arguments are immutable Values — interception means wrapping or vetoing, never in-place mutation:

  • internal/get — waterfall around every strict service read (ReflectService::get_value / Context::require); accessor reads and relaxed reads bypass it. The innermost behavior resolves the service; listeners may wrap or replace the result.
  • internal/set — waterfall around service writes (ReflectService::set_value); listeners may veto a write by not calling Event::call_next.
  • internal/config — waterfall around config resolution (Fiber::update and activation); the effective config is the waterfall’s result, the original when untouched.
  • internal/update — waterfall around the restart an update schedules; skipping Event::call_next vetoes the restart (the config is stored either way).
  • internal/listener — bail fired before a listener is registered; a bail value cancels the registration and the caller receives an inert EffectHandle.

Like upstream, the interception events themselves fire no internal/dispatch meta-event, so meta-listeners cannot recurse through them.

Re-exports§

pub use context::Context;
pub use context::ContextMeta;
pub use context::Isolation;
pub use effect::AsyncDisposer;
pub use effect::EffectHandle;
pub use effect::EffectMeta;
pub use error::CordisError;
pub use error::ErrorCode;
pub use error::Result;
pub use error::ValidationError;
pub use error::ValidationIssue;
pub use events::DispatchMode;
pub use events::Event;
pub use events::EventOptions;
pub use events::EventResult;
pub use events::EventValue;
pub use events::EventsService;
pub use events::is_bailed;
pub use fiber::Fiber;
pub use fiber::FiberState;
pub use logger::ANSI16_PALETTE;
pub use logger::ANSI256_PALETTE;
pub use logger::Exporter;
pub use logger::ExporterConfig;
pub use logger::FormatterFn;
pub use logger::LogArg;
pub use logger::LogKind;
pub use logger::Logger;
pub use logger::LoggerIntercept;
pub use logger::LoggerLevel;
pub use logger::LoggerService;
pub use logger::Message;
pub use logger::color_code;
pub use logger::default_format;
pub use reflect::Accessor;
pub use reflect::Property;
pub use reflect::ReflectService;
pub use reflect::ServiceInfo;
pub use registry::Inject;
pub use registry::IntoPlugin;
pub use registry::Plugin;
pub use registry::PluginHandle;
pub use registry::PluginKey;
pub use registry::PluginOutput;
pub use registry::RegistryService;
pub use registry::RuntimeInfo;
pub use registry::plugin_async;
pub use registry::plugin_sync;
pub use service::Service;
pub use service::service_async;
pub use service::service_sync;
pub use value::Config;
pub use value::Value;

Modules§

context
Root and child contexts tying all Cordis services together.
effect
Lifecycle-owned effects and single-shot asynchronous disposers.
error
Framework errors and configuration validation diagnostics.
events
Disposal-aware event bus and Cordis dispatch strategies.
fiber
Plugin fiber lifecycle, dependency epochs, and effect cleanup.
logger
Structured logger facade, bounded buffer, formatting, and exporters.
reflect
Scoped service storage and explicit reflection APIs.
registry
Plugin entrypoints, dependency declarations, and runtime registry.
service
Typed service conventions and helpers.
utils
Runtime-agnostic future execution.
value
Cloneable, dynamically typed values used for services, events, and config.

Constants§

VERSION
Version of the cordis-rs core this binary was compiled against.