use std::task::{Context, Poll};
use super::{Message, Version};
use crate::{
Error,
coding::{Decode, DecodeError, Stream},
};
pub(super) fn with_stats<S: crate::transport::poll::Session>(
stream: Stream<S, Version>,
stats: &crate::stats::Session,
version: Version,
) -> Stream<S, Version> {
let mut stream = stream.with_stats(stats);
if matches!(version, Version::Draft14 | Version::Draft15 | Version::Draft16) {
stream.reader = stream.reader.with_stats(&Default::default());
}
stream
}
pub(super) fn fin_cancels(version: Version) -> bool {
matches!(
version,
Version::Draft14 | Version::Draft15 | Version::Draft16 | Version::Draft17 | Version::Draft18
)
}
pub(super) fn poll_cancel<S: crate::transport::poll::Session>(
stream: &mut Stream<S, Version>,
finished: &mut bool,
version: Version,
cx: &mut Context<'_>,
) -> Poll<Result<(), Error>> {
if !*finished {
match stream.reader.poll_closed(cx) {
Poll::Ready(Ok(())) if !fin_cancels(version) => *finished = true,
Poll::Ready(result) => return Poll::Ready(result),
Poll::Pending => {}
}
}
if !matches!(version, Version::Draft14 | Version::Draft15 | Version::Draft16) {
return stream.writer.poll_closed(cx);
}
Poll::Pending
}
#[derive(Debug)]
pub(super) struct Update {
pub(super) priority: Option<u8>,
pub(super) unsupported: bool,
selector: usize,
}
impl Decode<Version> for Update {
fn decode<R: bytes::Buf>(r: &mut R, version: Version) -> Result<Self, DecodeError> {
let start = r.remaining();
if u64::decode(r, version)? != super::SubscribeUpdate::ID {
return Err(DecodeError::InvalidValue);
}
let selector = start - r.remaining();
let size = u16::decode(r, version)? as usize;
if r.remaining() < size {
return Err(DecodeError::Short);
}
let mut data = r.copy_to_bytes(size);
let update = Self::decode_body(&mut data, version).map_err(DecodeError::complete)?;
Ok(Self { selector, ..update })
}
fn control(&self, version: Version) -> Option<crate::stats::Control> {
Some(super::message::control(super::SubscribeUpdate::ID, version))
}
fn uncounted(&self) -> usize {
self.selector
}
}
impl Update {
fn decode_body(data: &mut bytes::Bytes, version: Version) -> Result<Self, DecodeError> {
use super::{Fill, Filter, Opaque, RequestId};
use bytes::Buf;
RequestId::decode(data, version)?;
if version == Version::Draft17 {
u64::decode(data, version)?;
}
decode_params!(data, version,
0x02 => object_timeout: Option<u64>,
0x03 => token: Vec<Opaque>,
0x06 => subgroup_timeout: Option<u64>,
0x10 => forward: Option<bool>,
0x20 => priority: Option<u8>,
0x21 => filter: Option<Filter>,
0x23 => fill: Option<Fill>,
0x25 => subgroup_filter: Vec<Opaque>,
0x26 => object_filter: Vec<Opaque>,
0x27 => priority_filter: Vec<Opaque>,
0x28 => property_filter: Vec<Opaque>,
0x29 => track_filter: Vec<Opaque>,
0x32 => new_group: Option<u64>,
);
if data.has_remaining() {
return Err(DecodeError::Long);
}
Ok(Self {
selector: 0,
priority,
unsupported: forward == Some(false)
|| filter.is_some()
|| fill.is_some()
|| object_timeout.is_some()
|| subgroup_timeout.is_some()
|| !token.is_empty()
|| !subgroup_filter.is_empty()
|| !object_filter.is_empty()
|| !priority_filter.is_empty()
|| !property_filter.is_empty()
|| !track_filter.is_empty()
|| new_group.is_some(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn request_stream_messages_count_without_their_type() {
use crate::lite::test_transport::ScriptedSession;
use crate::stats::{Control, Registry, Tier};
let registry = Registry::new(Default::default());
let stats = registry.tier(Tier::default()).session("");
let version = Version::Draft22;
let mut session = ScriptedSession::new(vec![0x10, 0, 2, 0, 0, 0x07, 0, 0, 0x02, 0, 2, 0, 0]);
let mut stream = with_stats(Stream::open(&mut session, version).await.unwrap(), &stats, version);
for expected in [super::super::GoAway::ID, super::super::RequestOk::ID] {
let id: u64 = stream.reader.decode().await.unwrap();
assert_eq!(id, expected);
stream.reader.read_message(id).await.unwrap();
}
stream.reader.decode::<Update>().await.unwrap();
let rx = |class| {
let rows = registry.snapshot().control();
rows.into_iter().find(|row| row.1 == class).map(|row| row.2.rx)
};
assert_eq!(rx(Control::Goaway), Some(4));
assert_eq!(rx(Control::Other), Some(2 + 4));
}
}