pub struct ItemUpdate { /* private fields */ }Expand description
One real-time update, decoded: the new state of one item of one subscription, plus which of its fields this update actually changed.
This is what a caller consumes from the subscription’s event stream
(docs/adr/0003-typed-event-stream-as-delivery-surface.md) — but not
directly: Updates yields a
SubscriptionEvent, of which an update is one
variant among the things that can happen to a subscription. Matching it out
is the loop:
use futures_util::StreamExt;
use lightstreamer_rs::{SubscriptionEvent, Updates};
async fn print_changes(mut updates: Updates) {
while let Some(event) = updates.next().await {
if let SubscriptionEvent::Update(update) = event {
println!("{}: {:?}", update.item_name(), update.changed_fields());
}
}
}§Every field is readable, not just the changed ones
An update on the wire is a delta: a field the server did not mention is
“unchanged compared to the previous update of the same field”
[docs/spec/04-notifications.md §2.2]. This type carries the item’s
complete state after the delta was applied, so
field and field_by_name always
answer, whether or not this particular update touched the field. Use
changed_fields or
is_field_changed to ask what moved.
§Positions are 1-based
Item and field positions match the specification’s own numbering — items
and fields are numbered from 1 [docs/spec/04-notifications.md §2.1,
§3.2] — so a position printed in a log lines up with a position in a
packet capture.
Implementations§
Source§impl ItemUpdate
impl ItemUpdate
Sourcepub const fn item_index(&self) -> usize
pub const fn item_index(&self) -> usize
The item’s 1-based position within the subscription.
This is the <item> argument of the U notification verbatim; the
order of items “is determined by the Metadata Adapter”
[docs/spec/04-notifications.md §2.1].
Sourcepub fn item_name(&self) -> &str
pub fn item_name(&self) -> &str
The item’s name.
TLCP never sends item names — SUBOK reports only a count
[docs/spec/04-notifications.md §3.1] — so this is the name the caller
declared for this position when it subscribed. If the caller subscribed
to a server-side group and did not declare a name for this position,
this returns the item’s 1-based index rendered in decimal, so that it is
always printable. Use declared_item_name
when the difference matters.
Sourcepub fn declared_item_name(&self) -> Option<&str>
pub fn declared_item_name(&self) -> Option<&str>
Sourcepub const fn kind(&self) -> UpdateKind
pub const fn kind(&self) -> UpdateKind
Whether this update is snapshot content or a live change
[docs/spec/04-notifications.md §2.4].
Sourcepub const fn is_snapshot(&self) -> bool
pub const fn is_snapshot(&self) -> bool
Shorthand for self.kind().is_snapshot().
Sourcepub fn field_count(&self) -> usize
pub fn field_count(&self) -> usize
How many fields the subscription’s schema has
[docs/spec/04-notifications.md §3.1].
Sourcepub fn field_name(&self, position: usize) -> Option<&str>
pub fn field_name(&self, position: usize) -> Option<&str>
Sourcepub fn field(&self, position: usize) -> Option<FieldValue<'_>>
pub fn field(&self, position: usize) -> Option<FieldValue<'_>>
The value of the field at position (1-based), or None if the
schema has no such field.
Note the two levels: None means there is no such field, whereas
Some(FieldValue::Null) means the field exists and is null.
See the module documentation on null versus empty.
Sourcepub fn field_by_name(&self, name: &str) -> Option<FieldValue<'_>>
pub fn field_by_name(&self, name: &str) -> Option<FieldValue<'_>>
The value of the field the caller declared as name, or None if no
declared field has that name.
Only names the caller declared are matched: the decimal stand-ins that
field_name returns for undeclared positions are
not lookup keys, so field_by_name("3") cannot accidentally resolve
to the third field of a subscription whose fields were never named.
Names are compared exactly, and if the caller declared the same name
twice the first position wins.
Sourcepub fn field_position(&self, name: &str) -> Option<usize>
pub fn field_position(&self, name: &str) -> Option<usize>
The 1-based position of the field the caller declared as name, or
None if no declared field has that name.
Sourcepub fn changed_fields(&self) -> ChangedFields<'_> ⓘ
pub fn changed_fields(&self) -> ChangedFields<'_> ⓘ
The fields this update changed, in ascending position order.
“Changed” means the update carried an explicit token for the field,
which is exactly what the specification’s own worked examples mark
Changed [docs/spec/04-notifications.md §2.5]. It is not a comparison
of values: an update that sets a field to the value it already had is
still a change, and the spec’s third example does precisely that to its
status field. Fields left out by an empty token or skipped by a ^N
run are absent, since both spellings mean “unchanged”
[docs/spec/04-notifications.md §2.2].
Sourcepub fn changed_count(&self) -> usize
pub fn changed_count(&self) -> usize
How many fields this update changed.
Sourcepub fn is_field_changed(&self, position: usize) -> bool
pub fn is_field_changed(&self, position: usize) -> bool
Whether this update carried a token for the field at position
(1-based).
Sourcepub fn is_field_changed_by_name(&self, name: &str) -> bool
pub fn is_field_changed_by_name(&self, name: &str) -> bool
Whether this update carried a token for the field the caller declared as
name. false if there is no such declared field.
Sourcepub fn is_command_mode(&self) -> bool
pub fn is_command_mode(&self) -> bool
Whether this update belongs to a COMMAND-mode subscription, i.e. one
activated by SUBCMD [docs/spec/04-notifications.md §3.2].
Sourcepub fn key(&self) -> Option<FieldValue<'_>>
pub fn key(&self) -> Option<FieldValue<'_>>
The row this update is about, for a COMMAND-mode subscription.
None if the subscription is not in COMMAND mode. Otherwise the
value of the field SUBCMD designated as the key
[docs/spec/04-notifications.md §3.2] — an ordinary field, decoded like
any other, so it can legitimately be FieldValue::Null and that is
reported rather than hidden.
§What a DELETE does, and does not, do here
ItemCommand::Delete tells the caller to drop its own
representation of the row. It does not erase anything inside this crate:
the field values this crate keeps per item are the baseline that the
next update’s unchanged-field markers are resolved against
[docs/spec/04-notifications.md §2.2], and discarding that baseline
would make the very next U undecodable.
SPEC-AMBIGUITY (command-delta-baseline): the specification “does not
state … whether unchanged-field markers in a U are resolved against
the previous update of the same key or of the same item”, noting that
the decoding algorithm “speaks only of ‘the previous update of the same
field’, without qualification by key”
[docs/spec/04-notifications.md §3.3]. This crate takes the algorithm
literally and keeps one baseline per item, because that is the only
reading the spec actually states; a per-key baseline would be an
invention, and it would have no defined value for a key seen for the
first time.
Sourcepub fn command(&self) -> Option<ItemCommand>
pub fn command(&self) -> Option<ItemCommand>
What this update did to the row named by key, for a
COMMAND-mode subscription.
None if the subscription is not in COMMAND mode, or if the command
field is null — a null command names no operation, so this crate reports
its absence rather than guessing one.
§Check is_command_changed before acting
The command is an ordinary field, and an ordinary field that this update
did not carry keeps the value the previous update gave it
[docs/spec/04-notifications.md §2.2]. So a U that leaves the command
field unchanged makes this method return the previous update’s
command, and a caller that deletes a row whenever it sees
ItemCommand::Delete would delete on the strength of an operation
that already happened.
SPEC-AMBIGUITY (command-delta-baseline): the specification does not
state the client-side COMMAND state machine, nor “whether
unchanged-field markers in a U are resolved against the previous
update of the same key or of the same item”
[docs/spec/04-notifications.md §3.3]. This crate does not invent one:
it reports the field value the decoding algorithm produces, and reports
separately whether this update carried it, so the caller can require
the stronger evidence before doing something destructive.
Sourcepub fn is_command_changed(&self) -> bool
pub fn is_command_changed(&self) -> bool
Whether this update carried a token for the command field, as
opposed to inheriting its value from an earlier update of the same item
[docs/spec/04-notifications.md §2.2, §2.5].
false when the subscription is not in COMMAND mode.
Sourcepub fn is_key_changed(&self) -> bool
pub fn is_key_changed(&self) -> bool
Whether this update carried a token for the key field.
false when the subscription is not in COMMAND mode. A false here
does not mean the row is unknown: under the per-item baseline this crate
keeps (see key) it means the key is the one the previous
update named.
Trait Implementations§
Source§impl Clone for ItemUpdate
impl Clone for ItemUpdate
Source§fn clone(&self) -> ItemUpdate
fn clone(&self) -> ItemUpdate
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more