Skip to main content

ItemUpdate

Struct ItemUpdate 

Source
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

Source

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

Source

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.

Source

pub fn declared_item_name(&self) -> Option<&str>

The item’s name, or None if the caller never declared one.

Unlike item_name this never invents a stand-in.

Source

pub const fn kind(&self) -> UpdateKind

Whether this update is snapshot content or a live change [docs/spec/04-notifications.md §2.4].

Source

pub const fn is_snapshot(&self) -> bool

Shorthand for self.kind().is_snapshot().

Source

pub fn field_count(&self) -> usize

How many fields the subscription’s schema has [docs/spec/04-notifications.md §3.1].

Source

pub fn field_name(&self, position: usize) -> Option<&str>

The name of the field at position (1-based), or None if the schema has no such field.

As with item_name, the protocol does not transmit field names; an undeclared position renders as its 1-based index.

Source

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.

Source

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.

Source

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.

Source

pub fn fields(&self) -> Fields<'_>

Every field of the schema, in order, changed or not.

Source

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

Source

pub fn changed_count(&self) -> usize

How many fields this update changed.

Source

pub fn is_field_changed(&self, position: usize) -> bool

Whether this update carried a token for the field at position (1-based).

Source

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.

Source

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

Source

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.

Source

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.

Source

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.

Source

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

Source§

fn clone(&self) -> ItemUpdate

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ItemUpdate

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for ItemUpdate

Source§

impl PartialEq for ItemUpdate

Source§

fn eq(&self, other: &ItemUpdate) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for ItemUpdate

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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