pub struct ReplayDriver { /* private fields */ }Expand description
Serves a captured (time, PV) trace through the real Driver trait, for validating
that a live MrftEngine run reproduces a golden-master trace’s result when driven
through the actual async abstraction – not just when fed the trace directly, as
core-replay-harness already does at the pure-engine level.
Reading the configured PV tag returns the next unconsumed sample’s PV value, with its
real recorded time in TagValue.timestamp. This is the one Driver implementation
in this crate where that field is genuinely meaningful rather than a diagnostic-only
extra: crate::types::TagValue’s own doc comment is clear that a live driver’s
timestamp must never become “the tick time the tuning engine itself runs on, which comes
from the caller’s own polling clock instead” – true and load-bearing for
OpcDaDriver/SimulatorDriver, whose reported (or absent) timestamps cannot be
trusted to reconstruct a control loop’s real tick cadence. ReplayDriver is a
deliberate, narrow exception to that rule, not a violation of it: it is not a live
driver at all, its entire purpose is exact historical replay, and the recorded time
is the tick time a validation test needs – reading it straight back out of the trait
boundary is simpler and less redundant than threading the same value through some
separate side channel the test would otherwise have to keep in lockstep with this
driver’s own internal cursor.
Reading the configured MV tag returns the last written value (or the seeded initial MV
before any write), matching crate::SimulatorDriver’s convention exactly. Running a
PV read past the last recorded sample is DriverError::Operation (wrapping
ReplayTraceExhausted) rather than panicking or silently repeating/holding the last
value, since either of those would let a real regression (the engine failing to
complete) masquerade as a passing test.
Uses std::sync::Mutex, matching crate::SimulatorDriver: every operation here is
synchronous index/vec bookkeeping with no .await point in the critical section.
Implementations§
Source§impl ReplayDriver
impl ReplayDriver
Sourcepub fn new(
pv_tag: impl Into<TagId>,
mv_tag: impl Into<TagId>,
samples: Vec<ReplaySample>,
initial_mv: f32,
) -> ReplayDriver
pub fn new( pv_tag: impl Into<TagId>, mv_tag: impl Into<TagId>, samples: Vec<ReplaySample>, initial_mv: f32, ) -> ReplayDriver
Builds a replay driver from an already-parsed sample sequence. initial_mv is what
the MV tag reads as before the first write – mirroring
crate::SimulatorDriver::new’s initial_mv parameter, and matching the fact that
a real trace’s MV convention (see crates/bhtune-core/tests/golden_replay.rs’s
FixtureInitial::mv_ini) is likewise supplied out of band from the tick sequence
itself.
Sourcepub fn from_fixture_json(
pv_tag: impl Into<TagId>,
mv_tag: impl Into<TagId>,
json: &str,
initial_mv: f32,
) -> DriverResult<ReplayDriver>
pub fn from_fixture_json( pv_tag: impl Into<TagId>, mv_tag: impl Into<TagId>, json: &str, initial_mv: f32, ) -> DriverResult<ReplayDriver>
Parses a golden-master fixture JSON document’s ticks[].time/ticks[].pv fields
(see [FixtureFile]) into the sample sequence ReplayDriver::new expects, so a
validation test can point this driver directly at the same fixture file
core-replay-harness already validates against (tests/golden/fixtures/*.json)
rather than hand-transcribing the tick sequence a second time. A parse failure is
DriverError::Operation, matching this crate’s error-model doc comment’s own
forward-looking note that golden-trace parse errors belong there.
Sourcepub fn writes(&self) -> Vec<RecordedWrite>
pub fn writes(&self) -> Vec<RecordedWrite>
Every MV write observed so far, in call order – for a validation test to compare against a golden fixture’s own expected per-tick MV sequence.
Trait Implementations§
Source§impl Debug for ReplayDriver
impl Debug for ReplayDriver
Source§impl Driver for ReplayDriver
impl Driver for ReplayDriver
Source§fn read<'life0, 'life1, 'async_trait>(
&'life0 self,
tags: &'life1 [TagId],
) -> Pin<Box<dyn Future<Output = DriverResult<Vec<TagValue>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn read<'life0, 'life1, 'async_trait>(
&'life0 self,
tags: &'life1 [TagId],
) -> Pin<Box<dyn Future<Output = DriverResult<Vec<TagValue>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn write<'life0, 'life1, 'async_trait>(
&'life0 self,
tag: &'life1 TagId,
value: TagWrite,
) -> Pin<Box<dyn Future<Output = DriverResult<WriteOutcome>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn write<'life0, 'life1, 'async_trait>(
&'life0 self,
tag: &'life1 TagId,
value: TagWrite,
) -> Pin<Box<dyn Future<Output = DriverResult<WriteOutcome>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn capabilities<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = DriverResult<DriverCapabilities>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn capabilities<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = DriverResult<DriverCapabilities>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn browse<'life0, 'async_trait>(
&'life0 self,
_request: BrowsePageRequest,
) -> Pin<Box<dyn Future<Output = DriverResult<BrowsePage>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn browse<'life0, 'async_trait>(
&'life0 self,
_request: BrowsePageRequest,
) -> Pin<Box<dyn Future<Output = DriverResult<BrowsePage>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn close_browse_session<'life0, 'life1, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = DriverResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn close_browse_session<'life0, 'life1, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = DriverResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn search<'life0, 'async_trait>(
&'life0 self,
_request: SearchRequest,
) -> Pin<Box<dyn Future<Output = DriverResult<Vec<SearchEvent>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn search<'life0, 'async_trait>(
&'life0 self,
_request: SearchRequest,
) -> Pin<Box<dyn Future<Output = DriverResult<Vec<SearchEvent>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn search_index_status<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexStatus>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn search_index_status<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexStatus>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn refresh_search_index<'life0, 'async_trait>(
&'life0 self,
_force: bool,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexStatus>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn refresh_search_index<'life0, 'async_trait>(
&'life0 self,
_force: bool,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexStatus>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn control_search_index<'life0, 'async_trait>(
&'life0 self,
_action: SearchIndexControlAction,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexStatus>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn control_search_index<'life0, 'async_trait>(
&'life0 self,
_action: SearchIndexControlAction,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexStatus>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn set_search_index_auto_refresh<'life0, 'async_trait>(
&'life0 self,
_enabled: bool,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexStatus>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn set_search_index_auto_refresh<'life0, 'async_trait>(
&'life0 self,
_enabled: bool,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexStatus>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn delete_search_index<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexStatus>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn delete_search_index<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexStatus>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn search_index<'life0, 'async_trait>(
&'life0 self,
_request: SearchIndexRequest,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexResponse>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn search_index<'life0, 'async_trait>(
&'life0 self,
_request: SearchIndexRequest,
) -> Pin<Box<dyn Future<Output = DriverResult<SearchIndexResponse>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Auto Trait Implementations§
impl !Freeze for ReplayDriver
impl RefUnwindSafe for ReplayDriver
impl Send for ReplayDriver
impl Sync for ReplayDriver
impl Unpin for ReplayDriver
impl UnsafeUnpin for ReplayDriver
impl UnwindSafe for ReplayDriver
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].