pub struct RecordInstance {Show 16 fields
pub name: String,
pub record: Box<dyn Record>,
pub common: CommonFields,
pub subscribers: HashMap<String, Vec<Subscriber>>,
pub parsed_inp: ParsedLink,
pub parsed_out: ParsedLink,
pub parsed_flnk: ParsedLink,
pub parsed_sdis: ParsedLink,
pub parsed_tsel: ParsedLink,
pub device: Option<Box<dyn DeviceSupport>>,
pub subroutine: Option<Arc<SubroutineFn>>,
pub processing: AtomicBool,
pub notify: Option<Arc<NotifyWaitSet>>,
pub last_posted: HashMap<String, EpicsValue>,
pub reprocess_generation: Arc<AtomicU64>,
pub info: HashMap<String, String>,
/* private fields */
}Expand description
A type-erased record instance stored in the database.
Fields§
§name: String§record: Box<dyn Record>§common: CommonFields§subscribers: HashMap<String, Vec<Subscriber>>§parsed_inp: ParsedLink§parsed_out: ParsedLink§parsed_flnk: ParsedLink§parsed_sdis: ParsedLink§parsed_tsel: ParsedLink§device: Option<Box<dyn DeviceSupport>>§subroutine: Option<Arc<SubroutineFn>>§processing: AtomicBool§notify: Option<Arc<NotifyWaitSet>>§last_posted: HashMap<String, EpicsValue>§reprocess_generation: Arc<AtomicU64>Generation counter for ReprocessAfter timer cancellation. Bumped each process cycle. Spawned timers check this to avoid stale re-processes from accumulated timers.
info: HashMap<String, String>Per-record info tags from info("key", "value") directives in
the .db file (epics-base info(…) grammar). Consumers include
asyn (asyn:READBACK), record-as-PV bridge tags
(Q:group, Q:form), and IOC-specific extensions. Empty for
records loaded without info(…) clauses.
Implementations§
Source§impl RecordInstance
impl RecordInstance
pub fn new(name: String, record: impl Record) -> Self
pub fn new_boxed(name: String, record: Box<dyn Record>) -> Self
Sourcepub fn set_info(&mut self, key: impl Into<String>, value: impl Into<String>)
pub fn set_info(&mut self, key: impl Into<String>, value: impl Into<String>)
Set a single info("key", "value") tag on this record. Last
write wins. Used by the .db loader (info(...) directive) and
dbpf-style tools.
Sourcepub fn get_info(&self, key: &str) -> Option<&str>
pub fn get_info(&self, key: &str) -> Option<&str>
Look up a single info tag. Returns None when the record has
no tag with that key.
Sourcepub fn invalidate_metadata_cache(&self)
pub fn invalidate_metadata_cache(&self)
Invalidate the metadata cache. Called after writing any metadata-class field (EGU, PREC, HOPR/LOPR, alarm limits, DRVH/DRVL, enum strings). The next snapshot will rebuild the cache from the new values.
Sourcepub fn notify_field_written(&self, field: &str)
pub fn notify_field_written(&self, field: &str)
Hook called by the database after a field is written. If the field is in the metadata-class set, the cache is invalidated so the next snapshot picks up the new value.
Field name is automatically uppercased.
Sourcepub fn notify_field_written_if_changed(
&self,
field: &str,
prev: Option<&EpicsValue>,
)
pub fn notify_field_written_if_changed( &self, field: &str, prev: Option<&EpicsValue>, )
Like [notify_field_written] but skips the invalidation when
the put did not actually change the field’s value. Mirrors
epics-base faac1df1 — DBE_PROPERTY events fire only on
real changes, not on idempotent writes (the C path compares
paddr->pfield against the converted payload before setting
the propertyUpdate flag).
prev is the value captured BEFORE the put. Callers that
don’t need the change-detection (e.g. internal writers that
know the field is non-metadata) can keep using
[notify_field_written].
Sourcepub fn is_processing(&self) -> bool
pub fn is_processing(&self) -> bool
Check if the record is currently processing (PACT equivalent).
Sourcepub fn resolve_field(&self, name: &str) -> Option<EpicsValue>
pub fn resolve_field(&self, name: &str) -> Option<EpicsValue>
Unified field resolution: record fields → common fields → virtual fields.
Sourcepub fn resolve_string_view_field(&self, name: &str) -> Option<EpicsValue>
pub fn resolve_string_view_field(&self, name: &str) -> Option<EpicsValue>
Resolve a field for EPICS $ long-string (character-array) access.
The $ channel-name modifier (C dbChannel.c:486-505) re-views a
field as a DBR_CHAR array: a DBF_STRING field becomes a char
array of field_size elements, a link field a char array of
PVLINK_STRINGSZ, and every other field type is rejected with
S_dbLib_fieldNotFound. pvxs serves that char view as a
form = "String" long-string NTScalar — it reads the DBR_CHAR
bytes and NUL-terminates them back into a string
(ioc/iocsource.cpp:133-136, ioc/channel.cpp:62-74).
Both DBF_STRING fields and link fields resolve to an
EpicsValue::String in this database (a link resolves to its
textual form, see Self::get_common_field), so a field is
$-eligible exactly when it resolves to a string value. Returns
that string value for an eligible field, or None for a field the
$ modifier cannot view as a char array (the
S_dbLib_fieldNotFound case) — the single owner of the
dbChannel $-eligibility rule for the channel-resolution layer.
Sourcepub fn client_field_value(&self, field: &str) -> Option<EpicsValue>
pub fn client_field_value(&self, field: &str) -> Option<EpicsValue>
The client-facing value of field: the resolved value with a
DBF_MENU field promoted to its DBR_ENUM form (see
Self::promote_menu_value), so a wire type derived directly from
the value matches the GET/MONITOR data. Used by the CA create-
channel path, which reads the native type from the value rather
than from Self::snapshot_for_field.
Sourcepub fn snapshot_for_field(&self, field: &str) -> Option<Snapshot>
pub fn snapshot_for_field(&self, field: &str) -> Option<Snapshot>
Build a Snapshot with full metadata for the given field.
Sourcepub fn get_common_field(&self, name: &str) -> Option<EpicsValue>
pub fn get_common_field(&self, name: &str) -> Option<EpicsValue>
Get a common field value.
Sourcepub fn put_common_field(
&mut self,
name: &str,
value: EpicsValue,
) -> CaResult<CommonFieldPutResult>
pub fn put_common_field( &mut self, name: &str, value: EpicsValue, ) -> CaResult<CommonFieldPutResult>
Set a common field value. Returns what scan index changes are needed.
Sourcepub fn get_virtual_field(&self, name: &str) -> Option<EpicsValue>
pub fn get_virtual_field(&self, name: &str) -> Option<EpicsValue>
Get virtual fields (NAME, RTYP).
Sourcepub fn evaluate_alarms(&mut self)
pub fn evaluate_alarms(&mut self)
Evaluate alarms based on record type and current value. Uses rec_gbl_set_sevr to accumulate into nsta/nsev.
Sourcepub fn process_local(
&mut self,
) -> CaResult<(ProcessSnapshot, Vec<(&'static str, EventMask)>)>
pub fn process_local( &mut self, ) -> CaResult<(ProcessSnapshot, Vec<(&'static str, EventMask)>)>
Basic process: process record, evaluate alarms, timestamp, build snapshot. This does NOT handle links — see process_with_context in database.rs.
Returns the value/log snapshot plus a list of alarm-field posts
(SEVR/STAT/AMSG/ACKS) with their individual C event masks.
SEVR is posted DBE_VALUE only; STAT/AMSG carry DBE_ALARM
(sevr/amsg change) and/or DBE_VALUE (stat change). The caller
must fire these via notify_field so a DBE_VALUE-only .SEVR
subscriber is not missed on an alarm-only change and a
DBE_ALARM-only subscriber is not wrongly notified — C parity
with recGblResetAlarms (recGbl.c:201-220), matching the
processing.rs link path.
Sourcepub fn check_deadband_ext(&mut self) -> (bool, bool)
pub fn check_deadband_ext(&mut self) -> (bool, bool)
Check MDEL/ADEL deadbands for VAL monitor/archive filtering.
Returns (monitor_trigger, archive_trigger).
Updates MLST/ALST (record-owned) and the CommonFields
mlst/alst shadow when a trigger fires. Records without
MDEL/ADEL (e.g. motor) default to deadband=0 (any actual
change triggers).
Delegates per-axis deadband comparison to the free function
[check_deadband] below — see that function’s docstring for
the four-quadrant NaN/infinity rule mirroring C
recGblCheckDeadband (recGbl.c:345-370).
C-parity design note: the Rust port uses NaN as the
“never posted” sentinel for MLST/ALST. C achieves the
same first-publish guarantee by allocating MLST/ALST in
BSS-zeroed storage with a value of 0.0 that the C code is
allowed to match against — but the first observed value is
not necessarily 0.0, and the C rule “MLST==0 means never
posted” relies on the deadband comparison abs(val - 0.0)
firing on any non-zero first value. NaN is strictly more
correct for the Rust port because a legitimate first
val=0.0 still fires on NaN.is_nan() → true. This
sentinel-as-design is intentional, documented inside
[check_deadband] (the oldval.is_nan() → return true short
circuit). It is NOT a deviation inherited from an earlier
silent compromise — record_tests.rs::deadband_* pins both
the NaN-sentinel behaviour and the C four-quadrant transitions.
Sourcepub fn notify_from_snapshot(&self, snapshot: &ProcessSnapshot)
pub fn notify_from_snapshot(&self, snapshot: &ProcessSnapshot)
Notify subscribers from a snapshot (call outside lock).
Each entry carries its own posting mask: only subscribers whose
mask intersects that field’s mask are notified, and the
delivered MonitorEvent reports exactly that field’s classes
(C db_post_events(prec, &field, mask) per-field granularity).
Sourcepub fn notify_field(&self, field: &str, mask: EventMask)
pub fn notify_field(&self, field: &str, mask: EventMask)
Notify subscribers of a specific field, filtering by event mask.
Sourcepub fn notify_record_alarm(&self)
pub fn notify_record_alarm(&self)
C db_post_events(precord, NULL, DBE_ALARM): post a record-wide
alarm event. Delivers to every subscriber on any field whose mask
includes DBE_ALARM, each carrying its own monitored field’s current
value (the per-field notify_field already filters by mask
intersection). Used by the alarm-acknowledge (ACKT/ACKS) put path so
an alarm-mask monitor on any field observes the acknowledgement.
Sourcepub fn notify_field_with_origin(
&self,
field: &str,
mask: EventMask,
origin: u64,
)
pub fn notify_field_with_origin( &self, field: &str, mask: EventMask, origin: u64, )
Notify subscribers with an origin tag for self-write filtering.
Sourcepub fn add_subscriber(
&mut self,
field: &str,
sid: u32,
data_type: DbFieldType,
mask: u16,
) -> Option<Receiver<MonitorEvent>>
pub fn add_subscriber( &mut self, field: &str, sid: u32, data_type: DbFieldType, mask: u16, ) -> Option<Receiver<MonitorEvent>>
Add a subscriber for a specific field. Returns None when the
per-field subscriber cap (EPICS_CAS_MAX_SUBSCRIBERS_PER_PV)
is reached. the parallel cap on ProcessVariable
defends against a misbehaving client opening many
MONITOR ops against one shared PV; the same defence is needed
for record fields, which the CA server’s
ChannelTarget::RecordField path lands on.
Sourcepub fn attach_filter_to_last_subscriber(
&mut self,
field: &str,
filter: Arc<dyn SubscriptionFilter>,
) -> bool
pub fn attach_filter_to_last_subscriber( &mut self, field: &str, filter: Arc<dyn SubscriptionFilter>, ) -> bool
Attach a filter to the most recently added subscriber for
field. Returns false when no subscriber exists yet on that
field (call add_subscriber first). The CA / PVA channel-name
parsers will use this once .{filter:opts} syntax is wired.
Tests can also use it directly to compose filter chains.
Sourcepub fn remove_subscriber(&mut self, sid: u32)
pub fn remove_subscriber(&mut self, sid: u32)
Remove a subscriber by subscription ID from all fields.
Sourcepub fn set_subscriber_active(&mut self, sid: u32, active: bool)
pub fn set_subscriber_active(&mut self, sid: u32, active: bool)
Pause / resume one subscriber’s event flow at the source
(db_event_disable / db_event_enable). active == false
suppresses every subsequent post to this subscriber AND drops any
pending coalesced overflow, so a resumed monitor restarts from the
source-side edge rather than replaying a value captured while it
was paused. No-op if no subscriber has this sid. The caller holds
the record write lock, so this is exclusive with the read-locked
post paths that consult Subscriber::active.
Sourcepub fn pop_coalesced(&self, sid: u32) -> Option<MonitorEvent>
pub fn pop_coalesced(&self, sid: u32) -> Option<MonitorEvent>
Take any pending coalesced overflow event for sid across all
fields. Drops-oldest semantics: if the per-subscriber mpsc filled
while the consumer was slow, the newest event was stashed in the
coalesce slot and is returned here.
Sourcepub fn cleanup_subscribers(&mut self)
pub fn cleanup_subscribers(&mut self)
Clean up closed subscriber channels.