use std::sync::Arc;
use sim_kernel::{Cx, Error, Result, Value};
use crate::{force_sequence_bounded, lazy_sequence_value};
pub trait RuntimeIndexSource: Send + Sync {
fn value_at_runtime_index(&self, cx: &mut Cx, index: i64) -> Result<Option<Value>>;
}
pub struct RuntimeIndexLookup<F> {
lookup: F,
}
impl<F> RuntimeIndexLookup<F> {
pub fn new(lookup: F) -> Self {
Self { lookup }
}
}
impl<F> RuntimeIndexSource for RuntimeIndexLookup<F>
where
F: Fn(&mut Cx, i64) -> Result<Option<Value>> + Send + Sync,
{
fn value_at_runtime_index(&self, cx: &mut Cx, index: i64) -> Result<Option<Value>> {
(self.lookup)(cx, index)
}
}
pub fn runtime_index_sequence<S>(cx: &mut Cx, source: Arc<S>, first_index: i64) -> Result<Value>
where
S: RuntimeIndexSource + 'static,
{
lazy_sequence_value(
cx,
Arc::new(move |cx, offset| {
let offset = i64::try_from(offset)
.map_err(|_| Error::Eval("runtime index offset overflow".to_owned()))?;
let index = first_index
.checked_add(offset)
.ok_or_else(|| Error::Eval("runtime index overflow".to_owned()))?;
source.value_at_runtime_index(cx, index)
}),
)
}
pub fn runtime_index_lookup_sequence<F>(cx: &mut Cx, lookup: F, first_index: i64) -> Result<Value>
where
F: Fn(&mut Cx, i64) -> Result<Option<Value>> + Send + Sync + 'static,
{
runtime_index_sequence(cx, Arc::new(RuntimeIndexLookup::new(lookup)), first_index)
}
pub fn runtime_index_values<S>(
cx: &mut Cx,
source: Arc<S>,
first_index: i64,
max: usize,
context: &str,
) -> Result<Vec<Value>>
where
S: RuntimeIndexSource + 'static,
{
let sequence = runtime_index_sequence(cx, source, first_index)?;
force_sequence_bounded(cx, &sequence, max, context)
}