Skip to main content

DriverAdapter

Trait DriverAdapter 

Source
pub trait DriverAdapter:
    Send
    + Sync
    + 'static {
    // Required methods
    fn name(&self) -> &str;
    fn map_op<'a>(
        &'a self,
        template: &'a ParsedOp,
        parent: Arc<dyn Kernel>,
    ) -> MapOpFuture<'a>;

    // Provided methods
    fn default_status_metrics(&self) -> Vec<StatusMetric> { ... }
    fn display_preference(&self) -> DisplayPreference { ... }
    fn known_op_fields(&self) -> Option<&'static [&'static str]> { ... }
    fn known_op_params(&self) -> &'static [&'static str] { ... }
    fn declare_controls(&self, _parent: &Arc<RwLock<Component>>) { ... }
    fn shutdown<'a>(&'a self) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> { ... }
    fn accessor_payload(&self) -> Option<Arc<dyn Any + Send + Sync>> { ... }
}
Expand description

A protocol-specific driver adapter. Constructed once per activity, shared across fibers via Arc.

The adapter owns the driver connection (session, client, pool) and provides OpDispensers that pre-process each op template at init time.

Required Methods§

Source

fn name(&self) -> &str

Human-readable adapter name (e.g., “cql”, “http”, “stdout”).

Source

fn map_op<'a>( &'a self, template: &'a ParsedOp, parent: Arc<dyn Kernel>, ) -> MapOpFuture<'a>

Map an op template into a dispenser. Called once per unique op template at activity startup — before any cycles execute.

Init-time work: parse the op, prepare statements, pre-compute bind-point resolution, validate field names, attach metrics.

parent is the phase scope kernel — the Polydat context the op template’s matter (phase bindings:, result: block, etc.) should attach to. Adapters that need their own Polydat context for op-template-scope name resolution clone the Arc and either retain it directly (no op-level matter) or use it as the parent their canonical kernel is bound under (polydat::kernel::bind_under / ScopeModule::instantiate_under) (op-level matter present); adapters with no Polydat needs ignore the parameter. The Arc lets the dispenser own a long-lived reference to the canonical kernel without re-cloning state. See SRD-68 §“Adapter API surface”. Construct an OpDispenser for one op template — the per-op dispenser-initialization stack frame.

This is where the currying stack completes: prepare any protocol-level handles (CQL: prepare statement, read parameter metadata), build the per-cycle data pullers, fold everything into the dispenser the runtime will then call repeatedly with execute(cycle, ctx). Nothing about init-time state needs to outlive this call — once map_op returns, the dispenser holds whatever it needs and the rest is dropped.

§Per-op binder verification (the typed-lvalue contract)

Per-op compulsion: for any op-template field this dispenser will bind through a typed-parameter API (anything beyond pure text concatenation into a Str lvalue), the implementor MUST construct the appropriate Binder shape from its protocol-side metadata (positional / named / single — see polydat::binder) and verify it against parent via polydat::binder::verify_against_kernel before returning the dispenser. A verification failure surfaces as a map_op Err; construction stops before any cycle runs and the operator sees the rvalue→lvalue mismatch (one violation per slot, no silent passthrough).

This is stack-local work: the binder is constructed, verified, used to wire up the typed binding path in the dispenser, and dropped. It is NOT cached on the adapter, returned as a sidecar, or otherwise persisted past the map_op return. Per-op-template, not adapter-wide.

Adapters whose every op-template field is a text template (stdout, http body templates, testkit captures) can skip the verify step — every wire reference’s lvalue is Str and the rvalue→lvalue rule permits any rvalue into a Str lvalue, so verification is always a no-op for them. The runtime guard in wires::substitute_via_wires remains the catch-all safety net for that path.

Provided Methods§

Source

fn default_status_metrics(&self) -> Vec<StatusMetric>

Default metric names to display on the status line for this adapter.

Each entry is a metric name (matching adapter_metrics() labels) and a display label. Workloads can override this via a status: field on phases or ops. Default: empty (no adapter-specific status).

Source

fn display_preference(&self) -> DisplayPreference

Preferred display mode for this adapter.

When multiple adapters are involved in a workload, the runtime uses the most restrictive (lowest) mode. Adapters that use raw terminal output (plotter) return Off to prevent the TUI from entering alternate screen.

  • Auto: adapter is compatible with TUI (default)
  • Off: adapter requires raw stderr/stdout, TUI must not activate
Source

fn known_op_fields(&self) -> Option<&'static [&'static str]>

Declare the set of op-field names this adapter knows how to interpret. SRD 30 §“Core-first field processing” requires that after the core runtime strips its own fields, every remaining key in ParsedOp.op must be in this list — an unknown field is a hard error, not a silent pass-through.

Return None (the default) to opt out of strict validation during the transition; existing adapters that haven’t been audited remain permissive. Adapters that return Some(...) get the “unknown field” guard automatically — core rejects templates with fields the adapter doesn’t claim.

Returning an empty slice Some(&[]) is a valid declaration for an adapter that consumes no op fields (e.g. stdout rendering the raw bindings only).

Source

fn known_op_params(&self) -> &'static [&'static str]

Adapter-specific params keys allowed under an op’s top-level params (not op) section. Returned keys extend the core’s crate::validation::CORE_OP_PARAMS allow-list at op-validation time. Default: empty — adapters that don’t need extras simply rely on the core vocab. Override to declare adapter-only params (e.g. CQL’s cl: consistency-level overrides if those were lifted from op to params someday).

Source

fn declare_controls(&self, _parent: &Arc<RwLock<Component>>)

Declare adapter-specific dynamic controls (SRD 23) on a subcomponent attached to the activity’s component. Called once per activity, after the activity declares its own concurrency / rate controls. The default no-op fits adapters that have no adapter-level dynamic knobs.

Convention: each adapter that overrides this attaches a single subcomponent named after itself (e.g. cql, http) under parent, and declares all of its dynamic controls there. That keeps controls reachable from every descendant scope via the standard SRD-16 walk-up while giving each adapter a stable component path label.

The trait method takes an &dyn DriverAdapter (i.e. &self), so adapters that hold per-instance state (handles, atomics) can wire up control appliers that write into that state. Multiple ops in one activity see the same adapter instance and the same controls — there is exactly one subcomponent per adapter per activity.

Source

fn shutdown<'a>(&'a self) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>

Async teardown hook fired by the resource pool when a shared adapter’s last reference detaches (or at session shutdown). Default: no-op — drop is enough for adapters whose underlying driver closes synchronously in its destructor.

Override to await a driver-specific close handshake. The CQL adapter’s override calls Session::close().await (which wraps cass_session_close) inside a 5-second timeout so a hung node doesn’t pin the runtime.

The future returned here borrows &self for the duration of the await; callers keep the adapter Arc alive across the await so the borrow stays valid.

Source

fn accessor_payload(&self) -> Option<Arc<dyn Any + Send + Sync>>

SRD-104 — the adapter’s accessor payload: a type-erased handle (Arc<dyn Any + Send + Sync>) a kernel node can obtain by fingerprint through its kernel tree’s resource scope (ResourceScope::lookup). The resource pool surfaces this through crate::resource_pool::SharedResource::accessor_payload (the pool-shared wrapper delegates here) and stores it on the entry at init. Default None — an adapter opts in only when it wants kernels to reach a live handle (the first consumer is the CQL session handle, SRD-103). Built over the adapter’s own connected session, so the payload and the op-execution path share one resource.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§