wtx 0.47.9

A collection of different transport implementations and related tools focused primarily on web technologies.
Documentation
use crate::{
  collection::{ArrayVectorU8, Vector},
  http::{
    AutoStream, ManualStream, Matcher, OperationMode, Response, StatusCode,
    server_framework::{Endpoint, EndpointNode, Middleware, RouteMatch},
  },
};
use core::{marker::PhantomData, ops::ControlFlow};

/// Redirects requests to specific asynchronous functions based on the set of inner URIs.
#[derive(Debug)]
pub struct Router<CA, E, EN, M, S, SA> {
  pub(crate) en: EN,
  pub(crate) _matcher: Matcher<(ArrayVectorU8<RouteMatch, 4>, OperationMode)>,
  pub(crate) middlewares: M,
  pub(crate) phantom: PhantomData<(CA, E, S, SA)>,
}

impl<CA, E, EN, M, S, SA> Router<CA, E, EN, M, S, SA>
where
  E: From<crate::Error>,
  EN: EndpointNode<CA, E, S, SA>,
{
  /// Creates a new instance with generic paths and middlewares.
  #[inline]
  pub fn new(en: EN, middlewares: M) -> crate::Result<Self> {
    let _matcher = Self::matcher(&en)?;
    Ok(Self { _matcher, middlewares, en, phantom: PhantomData })
  }

  fn matcher(en: &EN) -> crate::Result<Matcher<(ArrayVectorU8<RouteMatch, 4>, OperationMode)>> {
    let mut vec = Vector::new();
    en.paths_indices(ArrayVectorU8::new(), &mut vec)?;
    let mut matcher = Matcher::new();
    let mut builder = matcher.builder();
    for array in vec {
      let [initials @ .., last] = array.as_slice() else {
        continue;
      };
      let mut key = alloc::string::String::new();
      for elem in initials {
        key.push_str(&elem.path);
      }
      key.push_str(&last.path);
      let om = last.om;
      let _ = builder.add(&key.try_into()?, (array, om))?;
    }
    drop(builder);
    Ok(matcher)
  }
}

impl<CA, E, EN, S, SA> Router<CA, E, EN, (), S, SA>
where
  E: From<crate::Error>,
  EN: EndpointNode<CA, E, S, SA>,
{
  /// Creates a new instance with automatic paths and middlewares.
  #[inline]
  pub fn paths(en: EN) -> crate::Result<Self> {
    let _matcher = Self::matcher(&en)?;
    Ok(Self { en, _matcher, middlewares: (), phantom: PhantomData })
  }
}

impl<CA, E, EN, M, S, SA> Endpoint<CA, E, S, SA> for Router<CA, E, EN, M, S, SA>
where
  E: From<crate::Error>,
  EN: EndpointNode<CA, E, S, SA>,
  M: Middleware<CA, E, SA>,
{
  const OM: OperationMode = OperationMode::Auto;

  #[inline]
  async fn auto(
    &self,
    auto_stream: &mut AutoStream<CA, SA>,
    path_defs: (u8, &[RouteMatch]),
  ) -> Result<StatusCode, E> {
    let mw_aux = &mut self.middlewares.aux();
    if let ControlFlow::Break(el) = self
      .middlewares
      .req(&mut auto_stream.conn_aux, mw_aux, &mut auto_stream.req, &mut auto_stream.stream_aux)
      .await?
    {
      return Ok(el);
    }
    let status_code = self.en.auto(auto_stream, path_defs).await?;
    if let ControlFlow::Break(el) = self
      .middlewares
      .res(
        &mut auto_stream.conn_aux,
        mw_aux,
        Response { msg_data: &mut auto_stream.req.msg_data, status_code },
        &mut auto_stream.stream_aux,
      )
      .await?
    {
      return Ok(el);
    }
    Ok(status_code)
  }

  #[inline]
  async fn manual(
    &self,
    mut manual_stream: ManualStream<CA, S, SA>,
    path_defs: (u8, &[RouteMatch]),
  ) -> Result<(), E> {
    let mw_aux = &mut self.middlewares.aux();
    if let ControlFlow::Break(_) = self
      .middlewares
      .req(
        &mut manual_stream.conn_aux,
        mw_aux,
        &mut manual_stream.req,
        &mut manual_stream.stream_aux,
      )
      .await?
    {
      return Ok(());
    }
    self.en.manual(manual_stream, path_defs).await?;
    Ok(())
  }
}

impl<CA, E, EN, M, S, SA> EndpointNode<CA, E, S, SA> for Router<CA, E, EN, M, S, SA>
where
  E: From<crate::Error>,
  EN: EndpointNode<CA, E, S, SA>,
  M: Middleware<CA, E, SA>,
{
  const IS_ROUTER: bool = true;

  #[inline]
  fn paths_indices(
    &self,
    prev: ArrayVectorU8<RouteMatch, 4>,
    vec: &mut Vector<ArrayVectorU8<RouteMatch, 4>>,
  ) -> crate::Result<()> {
    self.en.paths_indices(prev, vec)
  }
}

impl<CA, E, EN, M, S, SA> Clone for Router<CA, E, EN, M, S, SA>
where
  EN: Clone,
  M: Clone,
{
  fn clone(&self) -> Self {
    Self {
      en: self.en.clone(),
      _matcher: self._matcher.clone(),
      middlewares: self.middlewares.clone(),
      phantom: self.phantom,
    }
  }
}