driver: allow preserving the Stimuli as a concrete List

This commit is contained in:
2022-08-12 18:03:10 -07:00
parent 40449c4165
commit 858e787c19
3 changed files with 87 additions and 22 deletions

View File

@@ -7,6 +7,7 @@ use crate::render::{self, MultiRenderer, Renderer};
use crate::sim::AbstractSim;
use crate::sim::units::{Frame, Time};
use crate::stim::AbstractStimulus;
use coremem_cross::compound::list;
use log::{info, trace};
use serde::{Deserialize, Serialize};
@@ -33,8 +34,8 @@ pub struct Driver<S, Stim=DynStimuli> {
/// generic stimuli collection which monomorphizes everything by boxing it.
pub type DynStimuli = Vec<Box<dyn AbstractStimulus>>;
impl<S: AbstractSim, Stim: Default> Driver<S, Stim> {
pub fn new(mut state: S) -> Self {
impl<S: AbstractSim, Stim> Driver<S, Stim> {
pub fn new_with_stim(mut state: S, stimuli: Stim) -> Self {
let diag = SyncDiagnostics::new();
state.use_diagnostics(diag.clone());
Self {
@@ -48,7 +49,7 @@ impl<S: AbstractSim, Stim: Default> Driver<S, Stim> {
Arc::new(meas::Energy::world()),
Arc::new(meas::Power::world()),
],
stimuli: Default::default(),
stimuli,
sim_end_time: None,
diag,
last_diag_time: Instant::now(),
@@ -60,12 +61,39 @@ impl<S: AbstractSim, Stim: Default> Driver<S, Stim> {
}
}
impl<S> Driver<S, DynStimuli> {
impl<S: AbstractSim> Driver<S, DynStimuli> {
pub fn new(state: S) -> Self {
Self::new_with_stim(state, DynStimuli::default())
}
pub fn add_stimulus<Stim: AbstractStimulus + 'static>(&mut self, s: Stim) {
self.stimuli.push(Box::new(s))
}
}
impl<S: AbstractSim> Driver<S, list::Empty> {
pub fn new_unboxed_stim(state: S) -> Self {
Self::new_with_stim(state, list::Empty::default())
}
}
impl<S: AbstractSim, Stim> Driver<S, Stim> {
pub fn with_stimulus<E>(self, s: E) -> Driver<S, Stim::Result>
where Stim: list::Prependable<E>
{
Driver {
state: self.state,
renderer: self.renderer,
render_pool: self.render_pool,
render_channel: self.render_channel,
measurements: self.measurements,
stimuli: self.stimuli.prepend(s),
sim_end_time: self.sim_end_time,
diag: self.diag,
last_diag_time: self.last_diag_time,
}
}
}
impl<S: AbstractSim, Stim> Driver<S, Stim> {
pub fn fill_region<Reg: Region, M: Into<S::Material> + Clone>(&mut self, region: &Reg, mat: M) {
self.state.fill_region(region, mat);

View File

@@ -1,4 +1,4 @@
use crate::compound::list::{Indexable, Meta};
use crate::compound::list::{Indexable, MaybeMeta, Meta};
use crate::compound::peano::{P0, P1, P2, P3, Peano, PNext};
#[cfg(feature = "serde")]
@@ -94,10 +94,22 @@ impl<E0, E1, E2, E3, T> Indexable<P3> for Node<E0, Node<E1, Node<E2, Node<E3, T>
}
}
impl<E0> IntoList for (E0,) {
type List = Node<E0, Null>;
pub trait IntoList {
type List;
fn into_list(self) -> Self::List;
}
impl IntoList for () {
type List = Null;
fn into_list(self) -> Self::List {
Node::new(self.0, Null)
Null
}
}
impl<E0> IntoList for (E0,) {
type List = Node<E0, <() as IntoList>::List>;
fn into_list(self) -> Self::List {
Node::new(self.0, ().into_list())
}
}
@@ -122,9 +134,27 @@ impl<E0, E1, E2, E3> IntoList for (E0, E1, E2, E3) {
}
}
pub trait IntoList {
type List;
fn into_list(self) -> Self::List;
pub trait Prependable<E> {
type Result;
fn prepend(self, e: E) -> Self::Result;
}
impl<E> Prependable<E> for Null {
type Result = Node<E, Null>;
fn prepend(self, e: E) -> Self::Result {
Node::new(e, self)
}
}
impl<E, H, T> Prependable<E> for Node<H, T> {
type Result = Node<E, Node<H, T>>;
fn prepend(self, e: E) -> Self::Result {
Node::new(e, self)
}
}
impl MaybeMeta for Null {
type Length = P0;
}
impl<H> Meta for Node<H, Null> {

View File

@@ -5,9 +5,11 @@ mod flat;
// mod tuple_consumer;
// pub use tuple_consumer::*;
// pub use linked::*;
pub use flat::IntoList;
pub use flat::{IntoList, Prependable};
pub use flat::exports::*;
pub type Empty = flat::Null;
/// something which can be indexed at `P`.
/// a List of length N is expected to implement `Indexable<P>` for all `P < N`.
pub trait Indexable<P: Peano> {
@@ -26,6 +28,15 @@ pub trait Meta {
type Length: PeanoNonZero;
}
/// implemented by any List, or Null (empty list)
pub trait MaybeMeta {
type Length: Peano;
}
impl<M: Meta> MaybeMeta for M {
type Length = M::Length;
}
/// implement on your own type for all `N` of a given list if you want to be able to walk the list.
pub trait Visitor<N: Peano, Arg> {
fn visit(&mut self, a: &Arg);
@@ -45,25 +56,21 @@ where
}
/// used internally to simplify trait bounds.
/// visits every element in the list at index `P` and less.
/// visits every element in the list at index less than `P`.
pub trait PartialListVisitor<L, P> {
fn visit_partial(&mut self, l: &L);
}
impl<L, V> PartialListVisitor<L, P0> for V
where
L: Indexable<P0>,
V: Visitor<P0, L::Element>,
{
fn visit_partial(&mut self, l: &L) {
self.visit(l.get_ref())
fn visit_partial(&mut self, _unused_basecase: &L) {
}
}
impl<L, V, P: Peano> PartialListVisitor<L, PNext<P>> for V
where
L: Indexable<PNext<P>>,
V: PartialListVisitor<L, P> + Visitor<PNext<P>, L::Element>,
L: Indexable<P>,
V: PartialListVisitor<L, P> + Visitor<P, L::Element>,
{
fn visit_partial(&mut self, l: &L) {
PartialListVisitor::<L, P>::visit_partial(self, l);
@@ -72,12 +79,12 @@ where
}
/// marker trait for a type which can visit every element in the list `L`.
pub trait ListVisitor<L: Meta>: PartialListVisitor<L, <<L as Meta>::Length as PeanoNonZero>::Prev> {}
pub trait ListVisitor<L: MaybeMeta>: PartialListVisitor<L, <L as MaybeMeta>::Length> {}
/// user-facing API to visit a list
pub fn visit<L, V>(l: &L, v: &mut V)
where
L: Meta,
L: MaybeMeta,
V: ListVisitor<L>,
{
v.visit_partial(l)