use std::any::Any;
use rustev_contract::{
definition::Operation,
ids::ArtifactId,
run::{Charge, CostBound},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SpendUnit {
NanoUsd,
None,
}
#[derive(Debug, Clone)]
pub struct SpendBinding {
pub backend_id: String,
pub artifact: ArtifactId,
pub cost_unit: SpendUnit,
}
#[derive(Debug, Clone)]
pub struct SpendAttempt {
pub decision_id: String,
pub attempt_id: String,
pub backend_id: String,
pub target: u32,
pub artifact: ArtifactId,
pub operation: Operation,
pub bound: CostBound,
pub cost_unit: SpendUnit,
}
pub type SpendTicket = Box<dyn Any + Send>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SpendRefusal {
pub code: String,
}
impl SpendRefusal {
pub fn new(code: impl Into<String>) -> Self {
Self { code: code.into() }
}
}
pub trait SpendGate: Send + Sync {
fn reserve(&self, attempt: &SpendAttempt) -> Result<SpendTicket, SpendRefusal>;
fn reserve_acquisition(
&self,
_attempt: &AcquisitionSpendAttempt,
) -> Result<SpendTicket, SpendRefusal> {
Err(SpendRefusal::new("acquisition-unsupported"))
}
fn settle(&self, ticket: SpendTicket, charge: &Charge);
fn release(&self, ticket: SpendTicket);
}
#[derive(Clone, Copy)]
pub struct LiveSpend<'a> {
pub gate: &'a dyn SpendGate,
pub bindings: &'a [SpendBinding],
}
#[derive(Clone, Copy, Default)]
pub struct LiveSources<'a> {
pub acquisitions: &'a [LiveAcquisition],
pub pages: &'a [rustev_contract::acquisition::AcquisitionPage],
}
#[derive(Debug, Clone)]
pub struct LiveAcquisition {
pub source: rustev_contract::ids::SourceId,
pub posture: AcquisitionPosture,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AcquisitionPosture {
Captured,
Live,
}
#[derive(Debug, Clone)]
pub struct AcquisitionSpendAttempt {
pub decision_id: String,
pub attempt_id: String,
pub source: rustev_contract::ids::SourceId,
pub operation: String,
pub request: rustev_contract::ids::AcquisitionRequestId,
pub bound: CostBound,
}
pub(crate) struct HeldSpend<'a> {
gate: &'a dyn SpendGate,
ticket: Option<SpendTicket>,
}
impl<'a> HeldSpend<'a> {
pub(crate) fn new(gate: &'a dyn SpendGate, ticket: SpendTicket) -> Self {
Self {
gate,
ticket: Some(ticket),
}
}
pub(crate) fn release(mut self) {
self.gate.release(self.ticket.take().expect("held ticket"));
}
pub(crate) fn settle(mut self, charge: &Charge) {
self.gate
.settle(self.ticket.take().expect("held ticket"), charge);
}
}
impl Drop for HeldSpend<'_> {
fn drop(&mut self) {
if let Some(ticket) = self.ticket.take() {
self.gate.settle(ticket, &Charge::Unknown);
}
}
}