use super::stream::Stream;
use crate::core::stream::StreamIter;
use std::rc::Rc;
use std::sync::Arc;
pub trait Goal<T: Default>: Clone + RawGoal<T> {}
impl<T: Default, G: Clone + RawGoal<T>> Goal<T> for G {}
pub trait RawGoal<T: Default> {
fn apply(&self, s: T) -> Stream<T>;
fn run(&self, n: usize) -> Stream<T> {
self.apply(T::default()).take_inf(n)
}
fn run_inf(&self) -> Stream<T> {
self.apply(T::default()).take_inf_all()
}
fn iter(&self) -> StreamIter<T> {
self.apply(T::default()).into_iter()
}
}
impl<T: Default, G: Fn(T) -> Stream<T>> RawGoal<T> for G {
fn apply(&self, s: T) -> Stream<T> {
self(s)
}
}
impl<T: Default, G: Goal<T>> RawGoal<T> for Arc<G> {
fn apply(&self, s: T) -> Stream<T> {
(**self).apply(s)
}
}
impl<T: Default> RawGoal<T> for Arc<dyn RawGoal<T>> {
fn apply(&self, s: T) -> Stream<T> {
(**self).apply(s)
}
}
impl<T: Default, G: RawGoal<T>> RawGoal<T> for Rc<G> {
fn apply(&self, s: T) -> Stream<T> {
(**self).apply(s)
}
}
impl<T: Default> RawGoal<T> for Rc<dyn RawGoal<T>> {
fn apply(&self, s: T) -> Stream<T> {
(**self).apply(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn dummy_goal(_: ()) -> Stream<()> {
Stream::empty()
}
fn run_goal<T: Default>(g: impl Goal<T>) -> Stream<T> {
g.apply(T::default())
}
#[test]
fn an_arcd_dyn_rawgoal_is_a_goal() {
let adg: Arc<dyn RawGoal<()>> = Arc::new(dummy_goal);
run_goal(adg);
}
#[test]
fn an_rcd_dyn_rawgoal_is_a_goal() {
let adg: Rc<dyn RawGoal<()>> = Rc::new(dummy_goal);
run_goal(adg);
}
}