use sim_kernel::{
Datum, DatumStore, Error, Event, Expr, HandleId, ObserveMode, RealizeRequest, Ref, Result,
Symbol, Term,
};
use sim_lib_server::Site;
use sim_lib_stream_core::{PlacedFragment, StreamEnvelope, StreamValue};
pub fn stream_realize_request(term: Term, buffer_limit: Option<usize>) -> RealizeRequest {
let mut request = RealizeRequest::new(term).observing(ObserveMode::Events);
request.buffer_limit = buffer_limit;
request
}
pub fn realize_stream_events(
cx: &mut sim_kernel::Cx,
request: &RealizeRequest,
stream: &StreamValue,
) -> Result<Vec<Event>> {
if request.observe != ObserveMode::Events {
return Err(Error::Eval(
"stream realization requires ObserveMode::Events".to_owned(),
));
}
let run = Ref::Handle(HandleId::fresh());
let request_ref = realize_request_ref(cx, request)?;
let mut events = vec![Event::started(run.clone(), 0, request_ref)?];
let mut seq = 1u64;
let mut emitted = 0usize;
let limit = request.answer_limit.unwrap_or(usize::MAX);
while emitted < limit {
let Some(item) = stream.next_packet()? else {
break;
};
events.push(item.chunk_event(cx, run.clone(), seq)?);
seq = seq.saturating_add(1);
emitted += 1;
}
if stream.is_done()? {
events.push(Event::done(run, seq)?);
}
Ok(events)
}
pub fn realize_placed_stream_events(
cx: &mut sim_kernel::Cx,
fragment: PlacedFragment,
site: &dyn Site,
) -> Result<Vec<StreamEnvelope>> {
sim_lib_server::realize_stream_events(cx, fragment, site)
}
fn realize_request_ref(cx: &mut sim_kernel::Cx, request: &RealizeRequest) -> Result<Ref> {
let id = cx.datum_store_mut().intern(Datum::Node {
tag: Symbol::qualified("stream/fabric", "RealizeRequest"),
fields: vec![
(
Symbol::new("term"),
Datum::try_from(Expr::from(request.term.clone()))?,
),
(
Symbol::new("observe"),
Datum::String(observe_name(request.observe).to_owned()),
),
(
Symbol::new("buffer-limit"),
optional_usize_datum(request.buffer_limit),
),
(
Symbol::new("answer-limit"),
optional_usize_datum(request.answer_limit),
),
],
})?;
Ok(Ref::Content(id))
}
fn optional_usize_datum(value: Option<usize>) -> Datum {
value.map_or(Datum::Nil, |value| Datum::String(value.to_string()))
}
fn observe_name(observe: ObserveMode) -> &'static str {
match observe {
ObserveMode::FinalOnly => "final-only",
ObserveMode::Events => "events",
ObserveMode::Ledger => "ledger",
}
}