Skip to main content

RecordInstance

Struct RecordInstance 

Source
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

Source

pub fn new(name: String, record: impl Record) -> Self

Source

pub fn new_boxed(name: String, record: Box<dyn Record>) -> Self

Source

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.

Source

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.

Source

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.

Source

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.

Source

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 faac1df1DBE_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].

Source

pub fn is_processing(&self) -> bool

Check if the record is currently processing (PACT equivalent).

Source

pub fn resolve_field(&self, name: &str) -> Option<EpicsValue>

Unified field resolution: record fields → common fields → virtual fields.

Source

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.

Source

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.

Source

pub fn snapshot_for_field(&self, field: &str) -> Option<Snapshot>

Build a Snapshot with full metadata for the given field.

Source

pub fn get_common_field(&self, name: &str) -> Option<EpicsValue>

Get a common field value.

Source

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.

Source

pub fn get_virtual_field(&self, name: &str) -> Option<EpicsValue>

Get virtual fields (NAME, RTYP).

Source

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.

Source

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.

Source

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.

Source

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).

Source

pub fn notify_field(&self, field: &str, mask: EventMask)

Notify subscribers of a specific field, filtering by event mask.

Source

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.

Source

pub fn notify_field_with_origin( &self, field: &str, mask: EventMask, origin: u64, )

Notify subscribers with an origin tag for self-write filtering.

Source

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.

Source

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.

Source

pub fn remove_subscriber(&mut self, sid: u32)

Remove a subscriber by subscription ID from all fields.

Source

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.

Source

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.

Source

pub fn cleanup_subscribers(&mut self)

Clean up closed subscriber channels.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more