use super::*;
use saddle_runtime::request_task::{RequestTaskBorrowedFuture, RequestTaskContext};
use std::alloc::{Layout, LayoutError};
pub(super) struct NormalFactory<B, C, Dispatch> {
pub(super) socket: TcpStream,
pub(super) adapter: saddle_boundary::ingress::ProfuseGwListenerAdapter,
pub(super) deployment: Option<C>,
pub(super) business: Option<BusinessConfig<B>>,
pub(super) ingress_token: Option<Arc<IngressToken>>,
pub(super) dispatch: Arc<Dispatch>,
pub(super) observer: saddle_observability::Observer,
pub(super) admission: Option<saddle_runtime::profusegw::ProfuseGwAdmissionEvent>,
pub(super) database: Option<Arc<ManagedDatabaseState>>,
pub(super) diagnostic_handle: Option<saddle_observability::EmergencyDiagnosticHandle>,
}
impl<B, C, Dispatch> NormalFactory<B, C, Dispatch> {
async fn body<DispatchFuture>(
self,
owner: &mut EntryRequestOwner,
task: RequestTaskContext,
) -> std::result::Result<(), saddle_observability::FrameworkRequestFailure<std::io::Error>>
where
Dispatch: Fn(
saddle_boundary::ingress::AcceptedIngress,
C,
BusinessConfig<B>,
crate::database_capability::DatabaseRequest,
) -> DispatchFuture,
DispatchFuture: Future<Output = Result<Vec<u8>>>,
{
serve_managed(
self.socket,
&self.adapter,
self.deployment.expect("single deployment input"),
self.business.expect("single business input"),
self.ingress_token,
&*self.dispatch,
&self.observer,
owner,
task,
self.admission.expect("legacy entry supplies its event"),
self.database,
self.diagnostic_handle,
)
.await
}
}
pub(super) fn boxed_normal_factory<B, C, Dispatch, DispatchFuture>(
factory: NormalFactory<B, C, Dispatch>,
) -> impl for<'a> FnOnce(
&'a mut EntryRequestOwner,
RequestTaskContext,
) -> RequestTaskBorrowedFuture<'a, (), std::io::Error>
+ Send
+ 'static
where
B: Send + Sync + 'static,
C: Send + 'static,
Dispatch: Fn(
saddle_boundary::ingress::AcceptedIngress,
C,
BusinessConfig<B>,
crate::database_capability::DatabaseRequest,
) -> DispatchFuture
+ Send
+ Sync
+ 'static,
DispatchFuture: Future<Output = Result<Vec<u8>>> + Send + 'static,
{
move |owner, context| Box::pin(factory.body(owner, context))
}
pub(super) struct RejectionFactory {
pub(super) socket: TcpStream,
pub(super) code: u16,
pub(super) retained: CancelledDelivery,
}
impl RejectionFactory {
pub(super) async fn body(
self,
context: RequestTaskContext,
) -> std::result::Result<
RejectionResult,
saddle_observability::FrameworkRequestFailure<std::io::Error>,
> {
let output = context.output();
let delivery = reject_required(
self.socket,
self.code,
context.scope().with_output(output.as_ref()),
self.retained,
output.clone(),
)
.await;
Ok(RejectionResult { delivery, output })
}
}
macro_rules! rejection_factory {
($factory:expr) => {{
let factory = $factory;
move |context| factory.body(context)
}};
}
pub(super) use rejection_factory;
fn output_layout<A, R>(_: impl FnOnce(A) -> R) -> Layout {
Layout::new::<R>()
}
#[derive(Clone, Copy, Debug)]
pub struct SharedLayout {
pub payload: Layout,
pub allocation: Layout,
}
pub(crate) fn shared_layout<T>() -> std::result::Result<SharedLayout, LayoutError> {
let payload = Layout::new::<T>();
let (allocation, _) = Layout::new::<[std::sync::atomic::AtomicUsize; 2]>().extend(payload)?;
Ok(SharedLayout {
payload,
allocation: allocation.pad_to_align(),
})
}
#[derive(Debug)]
pub struct EntryConsumerLayouts {
pub normal_runtime: saddle_runtime::request_task::storage::TaskLayouts,
pub rejection_runtime: saddle_runtime::request_task::storage::TaskLayouts,
pub normal_environment: Layout,
pub normal_factory: Layout,
pub normal_body: Layout,
pub normal_result: Layout,
pub normal_owner: Layout,
pub dispatch_future: Layout,
pub process_dispatch_cell: SharedLayout,
pub owner_cell: SharedLayout,
pub normal_ticket_entry: Layout,
pub rejection_environment: Layout,
pub rejection_factory: Layout,
pub rejection_body: Layout,
pub rejection_result: Layout,
pub rejection_ticket_entry: Layout,
pub cancellation_cell: SharedLayout,
pub delivery_guard: Layout,
pub database: DatabaseConsumerLayouts,
}
#[derive(Debug)]
pub struct DatabaseConsumerLayouts {
pub state: SharedLayout,
pub legacy_diagnostics: Layout,
pub cancellation_notify: SharedLayout,
pub outbound_retentions: SharedLayout,
pub outbound_retention_element: Layout,
pub request_handle: Layout,
pub completion_handle: Layout,
pub encoding_handle: Layout,
}
#[doc(hidden)]
pub fn entry_consumer_layouts<B, C, Dispatch, DispatchFuture>()
-> std::result::Result<EntryConsumerLayouts, LayoutError>
where
B: Send + Sync + 'static,
C: Send + 'static,
Dispatch: Fn(
saddle_boundary::ingress::AcceptedIngress,
C,
BusinessConfig<B>,
crate::database_capability::DatabaseRequest,
) -> DispatchFuture
+ Send
+ Sync
+ 'static,
DispatchFuture: Future<Output = Result<Vec<u8>>> + Send + 'static,
{
Ok(EntryConsumerLayouts {
normal_runtime: saddle_runtime::request_task::storage::owned_layouts::<EntryRequestOwner, (), std::io::Error, _, _>(boxed_normal_factory::<B, C, Dispatch, DispatchFuture>)?,
rejection_runtime: saddle_runtime::request_task::storage::pair_layouts(|factory: RejectionFactory| rejection_factory!(factory))?,
normal_environment: Layout::new::<NormalFactory<B, C, Dispatch>>(),
normal_factory: output_layout(boxed_normal_factory::<B, C, Dispatch, DispatchFuture>),
normal_body: output_layout(
|(factory, owner, context): (
NormalFactory<B, C, Dispatch>,
&'static mut EntryRequestOwner,
RequestTaskContext,
)| factory.body::<DispatchFuture>(owner, context),
),
normal_result: Layout::new::<
std::result::Result<(), saddle_observability::FrameworkRequestFailure<std::io::Error>>,
>(),
normal_owner: Layout::new::<EntryRequestOwner>(),
dispatch_future: Layout::new::<DispatchFuture>(),
process_dispatch_cell: shared_layout::<Dispatch>()?,
owner_cell: shared_layout::<tokio::sync::Mutex<EntryRequestOwner>>()?,
normal_ticket_entry: Layout::new::<(
tokio::task::Id,
saddle_runtime::request_task::RequestTaskOwnedJoin<EntryRequestOwner>,
)>(),
rejection_environment: Layout::new::<RejectionFactory>(),
rejection_factory: output_layout(|factory: RejectionFactory| rejection_factory!(factory)),
rejection_body: output_layout(
|(factory, context): (RejectionFactory, RequestTaskContext)| factory.body(context),
),
rejection_result: Layout::new::<
std::result::Result<
RejectionResult,
saddle_observability::FrameworkRequestFailure<std::io::Error>,
>,
>(),
rejection_ticket_entry: Layout::new::<(
tokio::task::Id,
(
saddle_runtime::request_task::RequestTaskJoin,
CancelledDelivery,
),
)>(),
cancellation_cell: shared_layout::<std::sync::Mutex<Option<RejectionResult>>>()?,
delivery_guard: Layout::new::<DeliveryGuard<'static>>(),
database: crate::database_capability::request_storage_layouts()?,
})
}
#[doc(hidden)]
pub fn entry_consumer_layouts_for<B, C, Dispatch, DispatchFuture>(
_: &Dispatch,
) -> std::result::Result<EntryConsumerLayouts, LayoutError>
where
B: Send + Sync + 'static,
C: Send + 'static,
Dispatch: Fn(
saddle_boundary::ingress::AcceptedIngress,
C,
BusinessConfig<B>,
crate::database_capability::DatabaseRequest,
) -> DispatchFuture
+ Send
+ Sync
+ 'static,
DispatchFuture: Future<Output = Result<Vec<u8>>> + Send + 'static,
{
entry_consumer_layouts::<B, C, Dispatch, DispatchFuture>()
}