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§
Sourcefn map_op<'a>(
&'a self,
template: &'a ParsedOp,
parent: Arc<dyn Kernel>,
) -> MapOpFuture<'a>
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§
Sourcefn default_status_metrics(&self) -> Vec<StatusMetric>
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).
Sourcefn display_preference(&self) -> DisplayPreference
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
Sourcefn known_op_fields(&self) -> Option<&'static [&'static str]>
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).
Sourcefn known_op_params(&self) -> &'static [&'static str]
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).
Sourcefn declare_controls(&self, _parent: &Arc<RwLock<Component>>)
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.
Sourcefn shutdown<'a>(&'a self) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>
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.
Sourcefn accessor_payload(&self) -> Option<Arc<dyn Any + Send + Sync>>
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".