Skip to main content

sim_lib_sequence/
runtime_iter.rs

1use std::sync::Arc;
2
3use sim_kernel::{Cx, Error, Result, Value};
4
5use crate::{force_sequence_bounded, lazy_sequence_value};
6
7/// Source of values addressed by contiguous integer keys.
8///
9/// This keeps array projection independent from any one table implementation:
10/// mutation tables, language objects, or host-backed stores can all provide the
11/// same integer-key lookup surface without adding a dependency edge.
12pub trait RuntimeIndexSource: Send + Sync {
13    /// Returns the value at `index`, or `None` to end the contiguous projection.
14    fn value_at_runtime_index(&self, cx: &mut Cx, index: i64) -> Result<Option<Value>>;
15}
16
17/// Function-backed [`RuntimeIndexSource`].
18pub struct RuntimeIndexLookup<F> {
19    lookup: F,
20}
21
22impl<F> RuntimeIndexLookup<F> {
23    /// Builds an index source from a lookup function.
24    pub fn new(lookup: F) -> Self {
25        Self { lookup }
26    }
27}
28
29impl<F> RuntimeIndexSource for RuntimeIndexLookup<F>
30where
31    F: Fn(&mut Cx, i64) -> Result<Option<Value>> + Send + Sync,
32{
33    fn value_at_runtime_index(&self, cx: &mut Cx, index: i64) -> Result<Option<Value>> {
34        (self.lookup)(cx, index)
35    }
36}
37
38/// Builds a lazy sequence over contiguous integer keys starting at `first_index`.
39///
40/// The sequence stops at the first missing key. This is intentionally a generic
41/// array projection, not a language-specific length or border rule.
42pub fn runtime_index_sequence<S>(cx: &mut Cx, source: Arc<S>, first_index: i64) -> Result<Value>
43where
44    S: RuntimeIndexSource + 'static,
45{
46    lazy_sequence_value(
47        cx,
48        Arc::new(move |cx, offset| {
49            let offset = i64::try_from(offset)
50                .map_err(|_| Error::Eval("runtime index offset overflow".to_owned()))?;
51            let index = first_index
52                .checked_add(offset)
53                .ok_or_else(|| Error::Eval("runtime index overflow".to_owned()))?;
54            source.value_at_runtime_index(cx, index)
55        }),
56    )
57}
58
59/// Builds a lazy sequence over contiguous integer keys from a lookup function.
60pub fn runtime_index_lookup_sequence<F>(cx: &mut Cx, lookup: F, first_index: i64) -> Result<Value>
61where
62    F: Fn(&mut Cx, i64) -> Result<Option<Value>> + Send + Sync + 'static,
63{
64    runtime_index_sequence(cx, Arc::new(RuntimeIndexLookup::new(lookup)), first_index)
65}
66
67/// Forces a bounded contiguous integer-key projection into a vector.
68pub fn runtime_index_values<S>(
69    cx: &mut Cx,
70    source: Arc<S>,
71    first_index: i64,
72    max: usize,
73    context: &str,
74) -> Result<Vec<Value>>
75where
76    S: RuntimeIndexSource + 'static,
77{
78    let sequence = runtime_index_sequence(cx, source, first_index)?;
79    force_sequence_bounded(cx, &sequence, max, context)
80}