diff options
Diffstat (limited to 'third_party/rust/neqo-transport/src/stream_id.rs')
-rw-r--r-- | third_party/rust/neqo-transport/src/stream_id.rs | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/third_party/rust/neqo-transport/src/stream_id.rs b/third_party/rust/neqo-transport/src/stream_id.rs new file mode 100644 index 0000000000..486bfb937c --- /dev/null +++ b/third_party/rust/neqo-transport/src/stream_id.rs @@ -0,0 +1,205 @@ +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Stream ID and stream index handling. + +use std::ops::AddAssign; + +use neqo_common::Role; + +use crate::connection::{LOCAL_STREAM_LIMIT_BIDI, LOCAL_STREAM_LIMIT_UNI}; +use crate::frame::StreamType; + +pub struct StreamIndexes { + pub local_max_stream_uni: StreamIndex, + pub local_max_stream_bidi: StreamIndex, + pub local_next_stream_uni: StreamIndex, + pub local_next_stream_bidi: StreamIndex, + pub remote_max_stream_uni: StreamIndex, + pub remote_max_stream_bidi: StreamIndex, + pub remote_next_stream_uni: StreamIndex, + pub remote_next_stream_bidi: StreamIndex, +} + +impl StreamIndexes { + pub fn new() -> Self { + Self { + local_max_stream_bidi: StreamIndex::new(LOCAL_STREAM_LIMIT_BIDI), + local_max_stream_uni: StreamIndex::new(LOCAL_STREAM_LIMIT_UNI), + local_next_stream_uni: StreamIndex::new(0), + local_next_stream_bidi: StreamIndex::new(0), + remote_max_stream_bidi: StreamIndex::new(0), + remote_max_stream_uni: StreamIndex::new(0), + remote_next_stream_uni: StreamIndex::new(0), + remote_next_stream_bidi: StreamIndex::new(0), + } + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Ord, PartialOrd, Hash)] +pub struct StreamId(u64); + +impl StreamId { + pub const fn new(id: u64) -> Self { + Self(id) + } + + pub fn as_u64(self) -> u64 { + self.0 + } + + pub fn is_bidi(self) -> bool { + self.as_u64() & 0x02 == 0 + } + + pub fn is_uni(self) -> bool { + !self.is_bidi() + } + + pub fn stream_type(self) -> StreamType { + if self.is_bidi() { + StreamType::BiDi + } else { + StreamType::UniDi + } + } + + pub fn is_client_initiated(self) -> bool { + self.as_u64() & 0x01 == 0 + } + + pub fn is_server_initiated(self) -> bool { + !self.is_client_initiated() + } + + pub fn role(self) -> Role { + if self.is_client_initiated() { + Role::Client + } else { + Role::Server + } + } + + pub fn is_self_initiated(self, my_role: Role) -> bool { + match my_role { + Role::Client if self.is_client_initiated() => true, + Role::Server if self.is_server_initiated() => true, + _ => false, + } + } + + pub fn is_remote_initiated(self, my_role: Role) -> bool { + !self.is_self_initiated(my_role) + } + + pub fn is_send_only(self, my_role: Role) -> bool { + self.is_uni() && self.is_self_initiated(my_role) + } + + pub fn is_recv_only(self, my_role: Role) -> bool { + self.is_uni() && self.is_remote_initiated(my_role) + } +} + +impl From<u64> for StreamId { + fn from(val: u64) -> Self { + Self::new(val) + } +} + +impl PartialEq<u64> for StreamId { + fn eq(&self, other: &u64) -> bool { + self.as_u64() == *other + } +} + +impl ::std::fmt::Display for StreamId { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{}", self.as_u64()) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Ord, PartialOrd, Hash)] +pub struct StreamIndex(u64); + +impl StreamIndex { + pub fn new(val: u64) -> Self { + Self(val) + } + + pub fn to_stream_id(self, stream_type: StreamType, role: Role) -> StreamId { + let type_val = match stream_type { + StreamType::BiDi => 0, + StreamType::UniDi => 2, + }; + let role_val = match role { + Role::Server => 1, + Role::Client => 0, + }; + + StreamId::from((self.0 << 2) + type_val + role_val) + } + + pub fn as_u64(self) -> u64 { + self.0 + } +} + +impl From<StreamId> for StreamIndex { + fn from(val: StreamId) -> Self { + Self(val.as_u64() >> 2) + } +} + +impl AddAssign<u64> for StreamIndex { + fn add_assign(&mut self, other: u64) { + *self = Self::new(self.as_u64() + other) + } +} + +#[cfg(test)] +mod test { + use super::{StreamIndex, StreamType}; + use neqo_common::Role; + + #[test] + fn bidi_stream_properties() { + let id1 = StreamIndex::new(4).to_stream_id(StreamType::BiDi, Role::Client); + assert_eq!(id1.is_bidi(), true); + assert_eq!(id1.is_uni(), false); + assert_eq!(id1.is_client_initiated(), true); + assert_eq!(id1.is_server_initiated(), false); + assert_eq!(id1.role(), Role::Client); + assert_eq!(id1.is_self_initiated(Role::Client), true); + assert_eq!(id1.is_self_initiated(Role::Server), false); + assert_eq!(id1.is_remote_initiated(Role::Client), false); + assert_eq!(id1.is_remote_initiated(Role::Server), true); + assert_eq!(id1.is_send_only(Role::Server), false); + assert_eq!(id1.is_send_only(Role::Client), false); + assert_eq!(id1.is_recv_only(Role::Server), false); + assert_eq!(id1.is_recv_only(Role::Client), false); + assert_eq!(id1.as_u64(), 16); + } + + #[test] + fn uni_stream_properties() { + let id2 = StreamIndex::new(8).to_stream_id(StreamType::UniDi, Role::Server); + assert_eq!(id2.is_bidi(), false); + assert_eq!(id2.is_uni(), true); + assert_eq!(id2.is_client_initiated(), false); + assert_eq!(id2.is_server_initiated(), true); + assert_eq!(id2.role(), Role::Server); + assert_eq!(id2.is_self_initiated(Role::Client), false); + assert_eq!(id2.is_self_initiated(Role::Server), true); + assert_eq!(id2.is_remote_initiated(Role::Client), true); + assert_eq!(id2.is_remote_initiated(Role::Server), false); + assert_eq!(id2.is_send_only(Role::Server), true); + assert_eq!(id2.is_send_only(Role::Client), false); + assert_eq!(id2.is_recv_only(Role::Server), false); + assert_eq!(id2.is_recv_only(Role::Client), true); + assert_eq!(id2.as_u64(), 35); + } +} |