use std::sync::{Arc, Mutex};
use crate::model::token::{self, Usage};
#[derive(Clone, Default)]
pub(crate) struct Ledger {
calls: Arc<Mutex<Vec<Option<Usage>>>>,
children: Arc<Mutex<Vec<Option<Usage>>>>,
}
impl Ledger {
pub(crate) fn settle(&self, usage: Option<Usage>) {
self.calls
.lock()
.expect("run usage lock poisoned")
.push(usage);
}
pub(crate) fn settle_child(&self, usage: Option<Usage>) {
if usage.is_some() {
self.children
.lock()
.expect("child usage lock poisoned")
.push(usage);
}
}
pub(crate) fn refine_last(&self, usage: Option<Usage>) {
if let Some(last) = self
.calls
.lock()
.expect("run usage lock poisoned")
.last_mut()
{
*last = usage;
}
}
pub(crate) fn refine_saved(&self, previous: Option<&Usage>, updated: &Usage) {
fn added(previous: Option<u64>, updated: Option<u64>) -> Option<u64> {
updated.map(|value| value.saturating_sub(previous.unwrap_or(0)))
}
self.settle(Some(Usage {
input: added(previous.and_then(|v| v.input), updated.input),
output: added(previous.and_then(|v| v.output), updated.output),
total: added(previous.and_then(|v| v.total), updated.total),
input_details: updated
.input_details
.as_ref()
.map(|details| token::InputDetails {
cached: added(
previous.and_then(|v| v.input_details.as_ref()?.cached),
details.cached,
),
}),
output_details: updated
.output_details
.as_ref()
.map(|details| token::OutputDetails {
think: added(
previous.and_then(|v| v.output_details.as_ref()?.think),
details.think,
),
}),
..Default::default()
}));
}
pub(crate) fn total(&self) -> Option<Usage> {
let calls = self
.calls
.lock()
.expect("run usage lock poisoned")
.iter()
.cloned()
.fold(None, token::merge);
self.children
.lock()
.expect("child usage lock poisoned")
.iter()
.cloned()
.fold(calls, token::merge)
}
}