use crate::curve::AggregateExt;
use crate::iterators::curve::{AggregationIterator, CapacityCheckIterator, InverseCurveIterator};
use crate::server::{
ActualServerExecution, ConstrainedServerDemand, HigherPriorityServerDemand, Server,
UnconstrainedServerExecution,
};
use crate::curve::curve_types::CurveType;
use crate::iterators::server::actual_execution::ActualServerExecutionIterator;
use crate::iterators::{ClonableCurveIterator, CurveIterator, ReclassifyIterator};
use crate::time::TimeUnit;
use alloc::boxed::Box;
use alloc::vec::Vec;
#[derive(Debug)]
pub struct System<'a> {
servers: &'a [Server<'a>],
}
impl<'a> System<'a> {
#[must_use]
pub const fn new(servers: &'a [Server<'a>]) -> System<'a> {
System { servers }
}
#[must_use]
pub const fn as_servers(&self) -> &'a [Server<'a>] {
self.servers
}
#[must_use]
pub fn aggregated_higher_priority_demand_curve_iter<'b, CSDCI>(
constrained_demand_curves: CSDCI,
) -> impl CurveIterator<CurveKind = HigherPriorityServerDemand> + Clone + 'b
where
CSDCI::Item: CurveIterator<CurveKind = ConstrainedServerDemand> + Clone + 'b,
CSDCI: IntoIterator,
{
constrained_demand_curves
.into_iter()
.aggregate::<ReclassifyIterator<_, _>>()
}
pub fn aggregated_higher_priority_actual_execution_curve_iter<'b>(
&'b self,
server_index: usize,
) -> AggregationIterator<
Box<dyn ClonableCurveIterator<'b, CurveKind = ActualServerExecution> + 'b>,
<ActualServerExecution as CurveType>::WindowKind,
> {
let mut curves: Vec<Box<dyn ClonableCurveIterator<CurveKind = ActualServerExecution>>> =
alloc::vec::Vec::with_capacity(2);
if server_index > 0 {
curves.push(Box::new(
self.fixed_actual_execution_curve_iter(server_index - 1),
));
if server_index > 1 {
let curve = self
.aggregated_higher_priority_actual_execution_curve_iter(server_index - 1)
.reclassify();
curves.push(Box::new(curve));
}
}
AggregationIterator::new(curves)
}
#[must_use]
pub fn system_wide_hyper_period(&self, server_index: usize) -> TimeUnit {
self.servers[..=server_index]
.iter()
.map(|server| server.properties.interval)
.chain(
self.servers
.iter()
.flat_map(|server| server.as_tasks().iter().map(|task| task.interval)),
)
.fold(TimeUnit::ONE, TimeUnit::lcm)
}
pub fn analysis_end(&self, server_index: usize) -> TimeUnit {
let res = self.servers[..=server_index]
.iter()
.map(|server| (server.properties.interval, TimeUnit::ZERO))
.chain(self.servers.iter().flat_map(|server| {
server
.as_tasks()
.iter()
.map(|task| (task.interval, task.offset))
}))
.fold((TimeUnit::ONE, TimeUnit::ZERO), |acc, next| {
(TimeUnit::lcm(acc.0, next.0), acc.1.max(next.1))
});
res.0 + res.1
}
#[must_use]
pub fn original_unconstrained_server_execution_curve_iter(
&self,
server_index: usize,
) -> impl CurveIterator<CurveKind = UnconstrainedServerExecution> + Clone + '_ {
#![allow(clippy::redundant_closure_for_method_calls)]
let csdi = self.servers[..server_index]
.iter()
.map(|server| server.constraint_demand_curve_iter());
let ahpc = System::aggregated_higher_priority_demand_curve_iter(csdi);
InverseCurveIterator::new(ahpc)
}
#[must_use]
pub fn fixed_unconstrained_server_execution_curve_iter(
&self,
server_index: usize,
) -> impl CurveIterator<CurveKind = UnconstrainedServerExecution> + Clone + '_ {
let ahpc = self.aggregated_higher_priority_actual_execution_curve_iter(server_index);
InverseCurveIterator::new(ahpc)
}
#[must_use]
pub fn original_actual_execution_curve_iter(
&self,
server_index: usize,
) -> impl CurveIterator<CurveKind = ActualServerExecution> + Clone + '_ {
let unchecked_unconstrained_execution =
self.original_unconstrained_server_execution_curve_iter(server_index);
let props = self.servers[server_index].properties;
let checked_unconstrained_execution = CapacityCheckIterator::new(
unchecked_unconstrained_execution,
props.capacity,
props.interval,
);
let constrained_demand = self.servers[server_index].constraint_demand_curve_iter();
ActualServerExecutionIterator::new(
self.servers[server_index].properties,
checked_unconstrained_execution,
constrained_demand,
)
}
#[must_use]
pub fn fixed_actual_execution_curve_iter(
&self,
server_index: usize,
) -> impl CurveIterator<CurveKind = ActualServerExecution> + Clone + '_ {
let unchecked_unconstrained_execution =
self.fixed_unconstrained_server_execution_curve_iter(server_index);
let props = self.servers[server_index].properties;
let checked_unconstrained_execution = CapacityCheckIterator::new(
unchecked_unconstrained_execution,
props.capacity,
props.interval,
);
let constrained_demand = self.servers[server_index].constraint_demand_curve_iter();
ActualServerExecutionIterator::new(
self.servers[server_index].properties,
checked_unconstrained_execution,
constrained_demand,
)
}
}