use crate::{
models::{Evaluator, Genotype, Request, Terminated},
repositories::requests,
};
use futures::future::BoxFuture;
use tracing::instrument;
use uuid::Uuid;
pub(crate) struct Terminator {
request_id: Uuid,
requests: requests::Repository,
}
impl Terminator {
#[instrument(level = "debug", skip(requests), fields(request_id = %request_id))]
pub(crate) fn new(requests: requests::Repository, request_id: Uuid) -> Self {
Terminator {
request_id,
requests,
}
}
}
impl Terminated for Terminator {
#[instrument(level = "debug", skip(self), fields(request_id = %self.request_id))]
fn is_terminated(&self) -> BoxFuture<'_, bool> {
let requests = self.requests.clone();
Box::pin(async move {
match requests.get_request_conclusion(&self.request_id).await {
Ok(Some(_)) => true, Err(err) => {
tracing::warn!(message = "Failed to check request conclusion", err = ?err);
false
}
_ => false, }
})
}
}
pub(crate) trait TypeErasedEvaluator: Send + Sync {
fn fitness<'a>(
&self,
genotype: &Genotype,
request: &'a Request,
terminated: &'a Box<dyn Terminated>,
) -> BoxFuture<'a, Result<f64, anyhow::Error>>;
}
pub(crate) struct ErasedEvaluator<P, E: Evaluator<P>> {
evaluator: E,
decode: fn(&[i64]) -> P,
}
impl<P, E: Evaluator<P>> ErasedEvaluator<P, E> {
pub(crate) fn new(evaluator: E, decode: fn(&[i64]) -> P) -> Self {
Self { evaluator, decode }
}
}
impl<P, E> TypeErasedEvaluator for ErasedEvaluator<P, E>
where
E: Evaluator<P> + Send + Sync + 'static,
{
#[instrument(level = "debug", skip(self, genotype, request, terminated), fields(genotype_id = %genotype.id(), genome_length = genotype.genome().len()))]
fn fitness<'a>(
&self,
genotype: &Genotype,
request: &'a Request,
terminated: &'a Box<dyn Terminated>,
) -> BoxFuture<'a, Result<f64, anyhow::Error>> {
let phenotype = (self.decode)(&genotype.genome());
self.evaluator
.fitness(genotype.id(), phenotype, request, terminated)
}
}