use std::{any::type_name, fmt::Display, marker::PhantomData};
use gmt_dos_clients_crseo::{OpticalModel, OpticalModelBuilder, crseo::FromBuilder};
use interface::{Data, TryRead, TryUpdate, TryWrite, UniqueIdentifier, Write};
pub mod error;
#[doc(inline)]
pub use error::KernelError;
use error::{KernelReadError, KernelUpdateError, KernelWriteError};
pub struct KernelFrame<T>(PhantomData<T>)
where
T: KernelSpecs;
impl<T> UniqueIdentifier for KernelFrame<T>
where
T: KernelSpecs + Send + Sync,
<T as KernelSpecs>::Input: UniqueIdentifier,
{
type DataType = <<T as KernelSpecs>::Input as UniqueIdentifier>::DataType;
}
impl<T> Write<KernelFrame<T>> for OpticalModel<<T as KernelSpecs>::Sensor>
where
T: KernelSpecs + Send + Sync,
KernelFrame<T>:
UniqueIdentifier<DataType = <<T as KernelSpecs>::Input as UniqueIdentifier>::DataType>,
<T as KernelSpecs>::Input: UniqueIdentifier,
Self: Write<<T as KernelSpecs>::Input>,
{
fn write(&mut self) -> Option<Data<KernelFrame<T>>> {
<Self as Write<<T as KernelSpecs>::Input>>::write(self)
.map(|data| data.transmute::<KernelFrame<T>>())
}
}
type Result<T> = std::result::Result<T, KernelError>;
pub trait KernelSpecs {
type Sensor: FromBuilder;
type Processor;
type Estimator;
type Controller;
type Input: Send + Sync;
type Data: Send + Sync;
type Output: Send + Sync;
fn processor(
model: &OpticalModelBuilder<<Self::Sensor as FromBuilder>::ComponentBuilder>,
) -> Result<Self::Processor>;
}
pub struct Kernel<T>
where
T: KernelSpecs,
{
pub(crate) processor: <T as KernelSpecs>::Processor,
estimator: Option<<T as KernelSpecs>::Estimator>,
controller: Option<<T as KernelSpecs>::Controller>,
}
impl<T> Kernel<T>
where
T: KernelSpecs,
{
pub fn controller(mut self, controller: <T as KernelSpecs>::Controller) -> Self {
self.controller = Some(controller);
self
}
}
impl<T> Display for Kernel<T>
where
T: KernelSpecs,
<T as KernelSpecs>::Processor: Display,
<T as KernelSpecs>::Estimator: Display,
<T as KernelSpecs>::Controller: Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{} KERNEL", type_name::<T>().to_uppercase())?;
writeln!(f, "|* processor:")?;
writeln!(f, "| {}", self.processor)?;
writeln!(f, "|* estimator:")?;
if let Some(estimator) = self.estimator.as_ref() {
writeln!(f, "|* estimator:")?;
writeln!(f, "| {}", estimator)?;
}
if let Some(integrator) = self.controller.as_ref() {
writeln!(f, "|* integrator:")?;
writeln!(f, "| {}", integrator)?;
}
Ok(())
}
}
impl<T> Kernel<T>
where
T: KernelSpecs,
{
pub fn new(
model: &OpticalModelBuilder<<T::Sensor as FromBuilder>::ComponentBuilder>,
) -> Result<Self> {
Ok(Self {
processor: <T as KernelSpecs>::processor(model)?,
estimator: None,
controller: None,
})
}
pub fn estimator(mut self, estimator: T::Estimator) -> Self {
self.estimator = Some(estimator);
self
}
pub fn processor(&self) -> &<T as KernelSpecs>::Processor {
&self.processor
}
}
impl<T> TryRead<KernelFrame<T>> for Kernel<T>
where
T: KernelSpecs,
KernelFrame<T>:
UniqueIdentifier<DataType = <<T as KernelSpecs>::Input as UniqueIdentifier>::DataType>,
<T as KernelSpecs>::Input: UniqueIdentifier,
<T as KernelSpecs>::Processor: TryRead<<T as KernelSpecs>::Input>,
<T as KernelSpecs>::Data: UniqueIdentifier,
<T as KernelSpecs>::Processor: TryWrite<<T as KernelSpecs>::Data>,
<T as KernelSpecs>::Estimator: TryRead<<T as KernelSpecs>::Data>,
<T as KernelSpecs>::Output: UniqueIdentifier,
<T as KernelSpecs>::Estimator: TryWrite<<T as KernelSpecs>::Output>,
<T as KernelSpecs>::Controller: TryRead<<T as KernelSpecs>::Output>,
<<T as KernelSpecs>::Processor as TryUpdate>::Error: 'static,
<<T as KernelSpecs>::Processor as TryWrite<<T as KernelSpecs>::Data>>::Error: 'static,
<<T as KernelSpecs>::Estimator as TryRead<<T as KernelSpecs>::Data>>::Error: 'static,
<<T as KernelSpecs>::Estimator as TryUpdate>::Error: 'static,
<<T as KernelSpecs>::Estimator as TryWrite<<T as KernelSpecs>::Output>>::Error: 'static,
<<T as KernelSpecs>::Controller as TryRead<<T as KernelSpecs>::Output>>::Error: 'static,
<<T as KernelSpecs>::Controller as TryUpdate>::Error: 'static,
<<T as KernelSpecs>::Processor as TryRead<<T as KernelSpecs>::Input>>::Error: 'static,
{
type Error = KernelReadError;
fn try_read(
&mut self,
data: Data<KernelFrame<T>>,
) -> std::result::Result<&mut Self, <Self as TryRead<KernelFrame<T>>>::Error> {
<<T as KernelSpecs>::Processor as TryRead<<T as KernelSpecs>::Input>>::boxed_try_read(
&mut self.processor,
data.transmute::<<T as KernelSpecs>::Input>(),
)?;
Ok(self)
}
}
impl<T> TryUpdate for Kernel<T>
where
T: KernelSpecs,
<T as KernelSpecs>::Data: UniqueIdentifier,
<T as KernelSpecs>::Processor: TryWrite<<T as KernelSpecs>::Data>,
<T as KernelSpecs>::Estimator: TryRead<<T as KernelSpecs>::Data>,
<T as KernelSpecs>::Output: UniqueIdentifier,
<T as KernelSpecs>::Estimator: TryWrite<<T as KernelSpecs>::Output>,
<T as KernelSpecs>::Controller: TryRead<<T as KernelSpecs>::Output>,
<<T as KernelSpecs>::Processor as TryUpdate>::Error: 'static,
<<T as KernelSpecs>::Processor as TryWrite<<T as KernelSpecs>::Data>>::Error: 'static,
<<T as KernelSpecs>::Estimator as TryRead<<T as KernelSpecs>::Data>>::Error: 'static,
<<T as KernelSpecs>::Estimator as TryUpdate>::Error: 'static,
<<T as KernelSpecs>::Estimator as TryWrite<<T as KernelSpecs>::Output>>::Error: 'static,
<<T as KernelSpecs>::Controller as TryRead<<T as KernelSpecs>::Output>>::Error: 'static,
<<T as KernelSpecs>::Controller as TryUpdate>::Error: 'static,
{
type Error = KernelUpdateError;
fn try_update(&mut self) -> std::result::Result<&mut Self, Self::Error> {
self.processor.boxed_try_update()?;
if let Some(estimator) = self.estimator.as_mut() {
if let Some(data) = <<T as KernelSpecs>::Processor as TryWrite<
<T as KernelSpecs>::Data,
>>::boxed_try_write(&mut self.processor)?
{
<<T as KernelSpecs>::Estimator as TryRead<<T as KernelSpecs>::Data>>::boxed_try_read(
estimator, data,
)
?;
estimator.boxed_try_update()?;
};
if let Some(integrator) = self.controller.as_mut() {
if let Some(data) = <<T as KernelSpecs>::Estimator as TryWrite<
<T as KernelSpecs>::Output,
>>::boxed_try_write(estimator)?
{
<<T as KernelSpecs>::Controller as TryRead<<T as KernelSpecs>::Output>>::boxed_try_read(
integrator, data,
)?;
integrator.boxed_try_update()?;
};
};
};
Ok(self)
}
}
impl<T> TryWrite<<T as KernelSpecs>::Output> for Kernel<T>
where
T: KernelSpecs,
<T as KernelSpecs>::Output: UniqueIdentifier,
<T as KernelSpecs>::Controller: TryWrite<<T as KernelSpecs>::Output>,
<T as KernelSpecs>::Data: UniqueIdentifier,
<T as KernelSpecs>::Processor: TryWrite<<T as KernelSpecs>::Data>,
<T as KernelSpecs>::Estimator: TryRead<<T as KernelSpecs>::Data>,
<T as KernelSpecs>::Output: UniqueIdentifier,
<T as KernelSpecs>::Estimator: TryWrite<<T as KernelSpecs>::Output>,
<T as KernelSpecs>::Controller: TryRead<<T as KernelSpecs>::Output>,
<<T as KernelSpecs>::Processor as TryUpdate>::Error: 'static,
<<T as KernelSpecs>::Processor as TryWrite<<T as KernelSpecs>::Data>>::Error: 'static,
<<T as KernelSpecs>::Estimator as TryRead<<T as KernelSpecs>::Data>>::Error: 'static,
<<T as KernelSpecs>::Estimator as TryUpdate>::Error: 'static,
<<T as KernelSpecs>::Estimator as TryWrite<<T as KernelSpecs>::Output>>::Error: 'static,
<<T as KernelSpecs>::Controller as TryRead<<T as KernelSpecs>::Output>>::Error: 'static,
<<T as KernelSpecs>::Controller as TryUpdate>::Error: 'static,
<<T as KernelSpecs>::Controller as TryWrite<<T as KernelSpecs>::Output>>::Error: 'static,
{
type Error = KernelWriteError;
fn try_write(
&mut self,
) -> std::result::Result<
Option<Data<<T as KernelSpecs>::Output>>,
<Self as TryWrite<<T as KernelSpecs>::Output>>::Error,
> {
Ok(if let Some(integrator) = self.controller.as_mut() {
<<T as KernelSpecs>::Controller as TryWrite<_>>::boxed_try_write(integrator)?
} else {
if let Some(estimator) = self.estimator.as_mut() {
<<T as KernelSpecs>::Estimator as TryWrite<_>>::boxed_try_write(estimator)?
} else {
None
}
})
}
}