use crate::{mut_state_fn, state::*, collections::hlists::FilterHList, collections::hlists::StreamHList};
use hlist2::{HList, Nil, ops::Append};
pub struct Event<
const N: usize,
const MUT: bool = false,
Subdivision = (),
Callback = (),
Output = (),
Stream = Nil,
Filter = Nil,
> {
pub callback: Callback,
pub stream: Stream,
pub filter: Filter, pub subdivision: Subdivision,
output_marker: std::marker::PhantomData<fn(Output)>,
}
impl<const N: usize> Event<N> {
pub fn new<F: StateFnMut<N, Output = Output>, Output>(callback: F) -> Event<N, false, (), F, Output> {
Event {
callback,
stream: Nil,
filter: Nil,
subdivision: (),
output_marker: Default::default(),
}
}
pub fn new_mut<F: MutStateFnMut<N, Output = Output>, Output>(
callback: F,
) -> Event<N, true, (), F, Output> {
Event {
callback,
stream: Nil,
filter: Nil,
subdivision: (),
output_marker: Default::default(),
}
}
pub fn stop_integration() -> Event<N, true, (), impl MutStateFnMut<N, Output = f64>, f64> {
Event::new_mut(mut_state_fn!(
|t| {
let tt = *t;
*t = f64::INFINITY;
tt
}
))
}
pub fn ode_state() -> Event<N, false, (), impl StateFnMut<N, Output= [f64; N]>, [f64; N]> {
Event::new(ODEStateFnMut(|x| x))
}
pub fn ode2_state() -> Event<N, false, (), impl StateFnMut<N, Output = (f64, [f64; N])>, (f64, [f64; N])>
{
Event::new(ODE2StateFnMut(|t, x| (t, x)))
}
}
impl<const N: usize, const MUT: bool, Subdivision, Callback, Output, Stream, Filter: HList + Append>
crate::Filter<N> for Event<N, MUT, Subdivision, Callback, Output, Stream, Filter>
{
type Output<T> =
Event<N, MUT, Subdivision, Callback, Output, Stream, <Filter as Append>::Output<T>>;
fn filter<F: StateFnMut<N, Output = bool>>(self, f: F) -> Self::Output<F> {
let callback = self.callback;
let stream = self.stream;
let filter = self.filter.append(f);
let subdivision = self.subdivision;
Event {
callback,
stream,
filter,
subdivision,
output_marker: self.output_marker,
}
}
}
impl<const N: usize, const MUT: bool, Subdivision, Callback, Stream, Filter, Output>
Event<N, MUT, Subdivision, Callback, Output, Stream, Filter>
{
pub fn subdivide(self, n: usize) -> Event<N, MUT, usize, Callback, Output, Stream, Filter> {
let callback = self.callback;
let stream = self.stream;
let filter = self.filter;
let subdivision = n;
Event {
callback,
stream,
filter,
subdivision,
output_marker: self.output_marker,
}
}
}
impl<const N: usize, const MUT: bool, Subdivision, Callback, Stream, Filter, Output>
Event<N, MUT, Subdivision, Callback, Output, Stream, Filter>
where
Self: Sized,
Stream: HList + Append,
{
pub fn to<F: FnMut(Output)>(
self,
s: F,
) -> Event<N, MUT, Subdivision, Callback, Output, <Stream as Append>::Output<F>, Filter> {
let callback = self.callback;
let stream = self.stream.append(s);
let filter = self.filter;
let subdivision = self.subdivision;
Event {
callback,
stream,
filter,
subdivision,
output_marker: self.output_marker,
}
}
pub fn to_std(
self,
) -> Event<
N,
MUT,
Subdivision,
Callback,
Output,
<Stream as Append>::Output<impl FnMut(Output)>,
Filter,
>
where
Output: std::fmt::Debug,
{
self.to(|value: Output| println!("{value:?}"))
}
pub fn to_file(
self,
filename: &str,
) -> Event<
N,
MUT,
Subdivision,
Callback,
Output,
<Stream as Append>::Output<impl FnMut(Output)>,
Filter,
>
where
Output: std::fmt::Debug,
{
use std::io::Write;
let mut file = std::fs::File::create_buffered(filename).unwrap();
self.to(move |value: Output| writeln!(&mut file, "{:?}", value).unwrap())
}
pub fn to_vec(
self,
vec: &mut Vec<Output>,
) -> Event<
N,
MUT,
Subdivision,
Callback,
Output,
<Stream as Append>::Output<impl FnMut(Output)>,
Filter,
> {
self.to(|value: Output| vec.push(value))
}
pub fn to_var(
self,
value: &mut Output,
) -> Event<
N,
MUT,
Subdivision,
Callback,
Output,
<Stream as Append>::Output<impl FnMut(Output)>,
Filter,
> {
self.to(|v: Output| *value = v)
}
pub fn to_float_range(
self,
range: &mut std::ops::Range<Output>,
) -> Event<
N,
MUT,
Subdivision,
Callback,
Output,
<Stream as Append>::Output<impl FnMut(Output)>,
Filter,
>
where
Output: num_traits::Float,
{
*range = Output::infinity()..Output::neg_infinity();
self.to(|v: Output| *range = range.start.min(v)..range.end.max(v))
}
}
impl<const N: usize, const M: usize, const MUT: bool, Subdivision, Callback, Item, Stream, Filter>
Event<N, MUT, Subdivision, Callback, [Item; M], Stream, Filter>
where
Stream: HList + Append,
{
pub fn to_csv(
self,
filename: &str,
) -> Event<
N,
MUT,
Subdivision,
Callback,
[Item; M],
<Stream as Append>::Output<impl FnMut([Item; M])>,
Filter,
>
where
Item: std::fmt::Display,
{
use std::io::Write;
let mut file = std::fs::File::create_buffered(filename).unwrap();
self.to(move |values: [Item; M]| {
for val in values {
write!(&mut file, "{},", val).unwrap();
}
write!(&mut file, "\n").unwrap();
})
}
pub fn to_table(
self,
filename: &str,
separator: &str,
header: Option<&str>,
) -> Event<
N,
MUT,
Subdivision,
Callback,
[Item; M],
<Stream as Append>::Output<impl FnMut([Item; M])>,
Filter,
>
where
Item: std::fmt::Display,
{
use std::io::Write;
let mut file = std::fs::File::create_buffered(filename).unwrap();
if let Some(header) = header {
writeln!(&mut file, "{header}").unwrap();
}
self.to(move |values: [Item; M]| {
for val in values {
write!(&mut file, "{}{separator}", val).unwrap();
}
writeln!(&mut file, "").unwrap();
})
}
pub fn to_vecs(
self,
vecs: [&mut Vec<Item>; M],
) -> Event<
N,
MUT,
Subdivision,
Callback,
[Item; M],
<Stream as Append>::Output<impl FnMut([Item; M])>,
Filter,
>
where
Item: Copy,
{
self.to(move |value: [Item; M]| {
for i in 0..M {
vecs[i].push(value[i]);
}
})
}
pub fn to_float_ranges(
self,
mut ranges: [&mut std::ops::Range<Item>; M],
) -> Event<
N,
MUT,
Subdivision,
Callback,
[Item; M],
<Stream as Append>::Output<impl FnMut([Item; M])>,
Filter,
>
where
Item: num_traits::Float,
{
for range in ranges.iter_mut() {
**range = Item::max_value()..Item::min_value();
}
self.to(move |values: [Item; M]| {
for (range, v) in ranges.iter_mut().zip(values.iter()) {
**range = range.start.min(*v)..range.end.max(*v)
}
})
}
}
pub trait EventCall<const N: usize> {
fn call(&mut self, state: &mut impl State<N>);
}
pub trait EventCallConcrete<const N: usize, S: State<N>> {
fn call(&mut self, state: &mut S);
}
impl<const N: usize, S: State<N>, EC: EventCall<N>> EventCallConcrete<N, S> for EC {
fn call(&mut self, state: &mut S) {
self.call(state);
}
}
impl<const N: usize, Callback, Output, Stream, Filter> EventCall<N>
for Event<N, false, (), Callback, Output, Stream, Filter>
where
Callback: StateFnMut<N, Output = Output>,
Output: Copy,
Stream: StreamHList<Output>,
Filter: FilterHList<N>,
{
fn call(&mut self, state: &mut impl State<N>) {
if self.filter.all(state) {
let output = self.callback.eval(state);
self.stream.call_each(output);
}
}
}
impl<const N: usize, Callback, Output, Stream, Filter> EventCall<N>
for Event<N, false, usize, Callback, Output, Stream, Filter>
where
Callback: StateFnMut<N, Output = Output>,
Output: Copy,
Stream: StreamHList<Output>,
Filter: FilterHList<N>,
{
fn call(&mut self, state: &mut impl State<N>) {
for i in 1..self.subdivision {
let t = state.t_prev()
+ (state.t() - state.t_prev()) * (i as f64) / (self.subdivision as f64);
if self.filter.all_at(state, t) {
let output = self.callback.eval_at(state, t);
self.stream.call_each(output);
}
}
if self.filter.all(state) {
let output = self.callback.eval(state);
self.stream.call_each(output);
}
}
}
impl<const N: usize, Callback, Output, Stream, Filter> EventCall<N>
for Event<N, true, (), Callback, Output, Stream, Filter>
where
Callback: MutStateFnMut<N, Output= Output>,
Output: Copy,
Stream: StreamHList<Output>,
Filter: FilterHList<N>,
{
fn call(&mut self, state: &mut impl State<N>) {
if self.filter.all(state) {
state.make_zero_step();
let output = self.callback.eval_mut(state);
state.push_current();
self.stream.call_each(output);
}
}
}
#[macro_export]
macro_rules! event {
($($expr:tt)*) => {
$crate::Event::new($crate::state_fn!($($expr)*))
};
}
#[macro_export]
macro_rules! event_mut {
($($expr:tt)*) => {
$crate::Event::new_mut($crate::mut_state_fn!($($expr)*))
};
}