MetricsContext

Struct MetricsContext 

Source
pub struct MetricsContext<'a> { /* private fields */ }
Expand description

MetricsContext provides an imperative API for complex aggregation logic in instruction hooks generated by declarative macros.

Note: You don’t write instruction hooks directly. Instead, use declarative macros:

  • #[aggregate] for aggregations (Sum, Count, Min, Max, etc.)
  • #[track_from] for field tracking
  • #[register_pda] for PDA mappings

These macros generate instruction hooks internally that use MetricsContext.

It wraps VM registers to provide type-safe access to:

  • Instruction data (accounts, args)
  • Entity state (current field values)
  • Context metadata (slot, signature, timestamp)
// Define your entity struct with declarative macros
struct TradingMetrics {
    #[aggregate(
        from = [Buy, Sell],
        field = data::amount,
        strategy = Sum,
        lookup_by = accounts::mint
    )]
    total_volume: u64,
     
    #[aggregate(
        from = [Buy, Sell],
        strategy = Count,
        lookup_by = accounts::mint
    )]
    trade_count: u64,
}

// The macro generates hooks that use MetricsContext internally
// to implement the aggregation logic.

§Direct MetricsContext Usage (Internal/Advanced)

If you’re implementing custom runtime logic or extending the macro system, you can use MetricsContext directly with field descriptors:

// Generate field descriptors - replaces field_accessor! macro
impl_field_descriptors!(TradingMetrics {
    total_volume: u64,
    trade_count: u64
});

// In generated hook function (example - you don't write this)
fn generated_update_metrics(ctx: &mut MetricsContext) {
    let volume = ctx.get_field(TradingMetrics::total_volume());
    ctx.set_field(TradingMetrics::total_volume(), 1000);
    ctx.increment_field(TradingMetrics::trade_count(), 1);
}

§Field Accessor API (Legacy - Still Supported)

// Define field accessors once
field_accessor!(TotalVolume, u64, "total_volume");
field_accessor!(TradeCount, u64, "trade_count");

// Use with compile-time type checking
ctx.get_field_legacy(TotalVolume)       // returns Option<u64>
ctx.set_field_legacy(TotalVolume, 100)  // type-checked at compile time
ctx.increment_field_legacy(TradeCount, 1)

§String-based API (Legacy - Use for dynamic field access only)

ctx.get::<u64>("total_volume")  // String-based, runtime errors possible
ctx.set("total_volume", 100)
ctx.increment("trade_count", 1)

Implementations§

Source§

impl<'a> MetricsContext<'a>

Source

pub fn new( state_reg: Register, registers: &'a mut Vec<RegisterValue>, compiled_paths: &'a HashMap<String, CompiledPath>, slot: Option<u64>, signature: Option<String>, timestamp: i64, ) -> Self

Create a new MetricsContext wrapping VM state

Source

pub fn account(&self, name: &str) -> Option<String>

Get an account address from the instruction by name Example: ctx.account("user") returns the user account address

Source

pub fn data<T: for<'de> Deserialize<'de>>(&self, field: &str) -> Option<T>

Get a typed field from instruction data Example: ctx.data::<u64>("amount") returns the amount field

Source

pub fn get<T: for<'de> Deserialize<'de>>(&self, field_path: &str) -> Option<T>

Get a typed value from the current entity state (string-based API) Example: ctx.get::<u64>("total_volume") returns the current total_volume value

Source

pub fn get_ref<T, F>(&self, field_ref: &F) -> Option<T>
where T: for<'de> Deserialize<'de>, F: FieldRef<T>,

Get a typed value using a field reference (NEW RECOMMENDED API) Example: ctx.get_ref(&field!(entity, total_volume)) returns Option

This provides compile-time field name validation and type inference.

Source

pub fn get_field<T, F>(&self, field: F) -> Option<F::Value>
where F: FieldDescriptor<T>,

Type-safe field getter using struct field descriptors (NEW ENHANCED API) Example: ctx.get_field(TradingMetrics::total_volume()) returns Option<u64>

This provides compile-time type checking with direct struct field access.

Source

pub fn get_field_legacy<F: FieldAccessor>(&self, _field: F) -> Option<F::Value>

Type-safe field getter using legacy FieldAccessor trait Example: ctx.get_field_legacy(TotalVolume) returns Option<u64>

This eliminates string literals and provides compile-time type checking.

Source

pub fn set<T: Serialize>(&mut self, field: &str, value: T)

Set a field value in the entity state (string-based API) Example: ctx.set("last_trade_timestamp", ctx.timestamp())

Source

pub fn set_ref<T, F>(&mut self, field_ref: &F, value: T)
where T: Serialize, F: FieldRef<T>,

Set a field value using a field reference (NEW RECOMMENDED API) Example: ctx.set_ref(&field!(entity, total_volume), 1000)

This provides compile-time field name validation and type checking.

Source

pub fn set_field<T, F>(&mut self, field: F, value: F::Value)
where F: FieldDescriptor<T>,

Type-safe field setter using struct field descriptors (NEW ENHANCED API) Example: ctx.set_field(TradingMetrics::total_volume(), 1000) sets total_volume to 1000

This provides compile-time type checking with direct struct field access.

Source

pub fn set_field_legacy<F: FieldAccessor>(&mut self, _field: F, value: F::Value)

Type-safe field setter using legacy FieldAccessor trait Example: ctx.set_field_legacy(TotalVolume, 1000) sets total_volume to 1000

This eliminates string literals and provides compile-time type checking.

Source

pub fn increment(&mut self, field: &str, amount: u64)

Increment a numeric field by a given amount (string-based API) Example: ctx.increment("whale_trade_count", 1)

Source

pub fn increment_ref<F>(&mut self, field_ref: &F, amount: u64)
where F: FieldRef<u64>,

Increment a numeric field using a field reference (NEW RECOMMENDED API) Example: ctx.increment_ref(&field!(entity, trade_count), 1)

This provides compile-time field name validation. Works with u64 fields.

Source

pub fn increment_field<T, F>(&mut self, field: F, amount: u64)
where F: FieldDescriptor<T, Value = u64>,

Type-safe increment using struct field descriptors (NEW ENHANCED API) Example: ctx.increment_field(TradingMetrics::trade_count(), 1)

Works with u64 fields and provides compile-time type checking.

Source

pub fn increment_field_legacy<F: FieldAccessor>( &mut self, _field: F, amount: u64, )
where F::Value: Into<u64> + From<u64>,

Type-safe increment using legacy FieldAccessor trait Example: ctx.increment_field_legacy(TradeCount, 1)

Works with any numeric type that can convert to/from u64.

Source

pub fn sum(&mut self, field: &str, value: u64)

Add a value to a numeric accumulator (alias for increment - string-based API) Example: ctx.sum("total_fees", fee_amount)

Source

pub fn sum_ref<F>(&mut self, field_ref: &F, value: u64)
where F: FieldRef<u64>,

Add a value to a numeric accumulator using a field reference (NEW RECOMMENDED API) Example: ctx.sum_ref(&field!(entity, total_fees), fee_amount)

This is an alias for increment_ref() that may be clearer for accumulation use cases.

Source

pub fn sum_field<T, F>(&mut self, field: F, value: u64)
where F: FieldDescriptor<T, Value = u64>,

Type-safe sum using struct field descriptors (NEW ENHANCED API) Example: ctx.sum_field(TradingMetrics::total_fees(), fee_amount)

Works with u64 fields and provides compile-time type checking.

Source

pub fn sum_field_legacy<F: FieldAccessor>(&mut self, _field: F, value: u64)
where F::Value: Into<u64> + From<u64>,

Type-safe sum using legacy FieldAccessor trait Example: ctx.sum_field_legacy(TotalFees, fee_amount)

Works with any numeric type that can convert to/from u64.

Source

pub fn add_unique(&mut self, field: &str, value: String)

Add a value to a unique set and update the count field Example: ctx.add_unique("unique_traders", user_address)

Source

pub fn timestamp(&self) -> i64

Get the current timestamp in milliseconds

Source

pub fn slot(&self) -> u64

Get the blockchain slot number

Source

pub fn signature(&self) -> &str

Get the transaction signature

Auto Trait Implementations§

§

impl<'a> Freeze for MetricsContext<'a>

§

impl<'a> RefUnwindSafe for MetricsContext<'a>

§

impl<'a> Send for MetricsContext<'a>

§

impl<'a> Sync for MetricsContext<'a>

§

impl<'a> Unpin for MetricsContext<'a>

§

impl<'a> !UnwindSafe for MetricsContext<'a>

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> Same for T

Source§

type Output = T

Should always be Self
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