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)
§Enhanced Field Descriptor API (NEW - Recommended)
// 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>
impl<'a> MetricsContext<'a>
Sourcepub 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
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
Sourcepub fn account(&self, name: &str) -> Option<String>
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
Sourcepub fn data<T: for<'de> Deserialize<'de>>(&self, field: &str) -> Option<T>
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
Sourcepub fn get<T: for<'de> Deserialize<'de>>(&self, field_path: &str) -> Option<T>
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
Sourcepub fn get_ref<T, F>(&self, field_ref: &F) -> Option<T>where
T: for<'de> Deserialize<'de>,
F: FieldRef<T>,
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.
Sourcepub fn get_field<T, F>(&self, field: F) -> Option<F::Value>where
F: FieldDescriptor<T>,
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.
Sourcepub fn get_field_legacy<F: FieldAccessor>(&self, _field: F) -> Option<F::Value>
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.
Sourcepub fn set<T: Serialize>(&mut self, field: &str, value: T)
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())
Sourcepub fn set_ref<T, F>(&mut self, field_ref: &F, value: T)
pub fn set_ref<T, F>(&mut self, field_ref: &F, value: 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.
Sourcepub fn set_field<T, F>(&mut self, field: F, value: F::Value)where
F: FieldDescriptor<T>,
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.
Sourcepub fn set_field_legacy<F: FieldAccessor>(&mut self, _field: F, value: F::Value)
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.
Sourcepub fn increment(&mut self, field: &str, amount: u64)
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)
Sourcepub fn increment_ref<F>(&mut self, field_ref: &F, amount: u64)
pub fn increment_ref<F>(&mut self, field_ref: &F, amount: 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.
Sourcepub fn increment_field<T, F>(&mut self, field: F, amount: u64)where
F: FieldDescriptor<T, Value = u64>,
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.
Sourcepub fn increment_field_legacy<F: FieldAccessor>(
&mut self,
_field: F,
amount: u64,
)
pub fn increment_field_legacy<F: FieldAccessor>( &mut self, _field: F, amount: 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.
Sourcepub fn sum(&mut self, field: &str, value: u64)
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)
Sourcepub fn sum_ref<F>(&mut self, field_ref: &F, value: u64)
pub fn sum_ref<F>(&mut self, field_ref: &F, value: 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.
Sourcepub fn sum_field<T, F>(&mut self, field: F, value: u64)where
F: FieldDescriptor<T, Value = u64>,
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.
Sourcepub fn sum_field_legacy<F: FieldAccessor>(&mut self, _field: F, value: u64)
pub fn sum_field_legacy<F: FieldAccessor>(&mut self, _field: F, value: 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.
Sourcepub fn add_unique(&mut self, field: &str, value: String)
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)