use std::ops::{Deref, DerefMut};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use shared_ids::ClientId;
use tracing::trace;
use crate::RequestPayload;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub(crate) struct ClientRequest<P> {
pub(crate) client: ClientId,
pub(crate) payload: P,
}
impl<P> Deref for ClientRequest<P> {
type Target = P;
fn deref(&self) -> &Self::Target {
&self.payload
}
}
impl<P> DerefMut for ClientRequest<P> {
fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
&mut self.payload
}
}
impl<P: RequestPayload> ClientRequest<P> {
pub(crate) fn validate(&self) -> Result<()> {
self.verify(self.client)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[repr(transparent)]
#[serde(transparent)]
pub(crate) struct RequestBatch<P> {
pub(crate) batch: Box<[ClientRequest<P>]>,
}
impl<P: RequestPayload> RequestBatch<P> {
pub(crate) fn new(batch: Box<[ClientRequest<P>]>) -> Self {
Self { batch }
}
pub(crate) fn validate(&self) -> Result<()> {
trace!("Validating batch of requests ...");
for request in self.batch.iter() {
trace!(
"Validating client request (ID: {:?}, client ID: {:?}) contained in batch ...",
request.id(),
request.client
);
request.validate()?;
trace!("Successfully validated client request (ID: {:?}, client ID: {:?}) contained in batch.", request.id(), request.client);
}
trace!("Successfully validated batch of requests.");
Ok(())
}
}
impl<P> IntoIterator for RequestBatch<P> {
type Item = ClientRequest<P>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
let batch = Vec::from(self.batch); batch.into_iter()
}
}
#[cfg(test)]
pub(crate) mod test {
use rand::{rngs::ThreadRng, Rng};
use shared_ids::ClientId;
use crate::tests::DummyPayload;
use super::{ClientRequest, RequestBatch};
pub(crate) fn create_invalid_client_req(rng: &mut ThreadRng) -> ClientRequest<DummyPayload> {
let rand_client_id = rng.gen::<u64>();
let rand_req_id = rng.gen::<u64>();
ClientRequest {
client: ClientId::from_u64(rand_client_id),
payload: DummyPayload(rand_req_id, false),
}
}
pub(crate) fn create_batch() -> RequestBatch<DummyPayload> {
let mut batch = Vec::new();
for i in 0..10 {
let client_req = ClientRequest {
client: ClientId::from_u64(i),
payload: DummyPayload(i, true),
};
batch.push(client_req);
}
let batch: [ClientRequest<DummyPayload>; 10] = batch.try_into().unwrap();
let batch = Box::new(batch);
RequestBatch { batch }
}
}