use std::ops::Range;
use nom::Parser;
use crate::{
frame::{GetFrameType, io::WriteFrameType},
util::{ContinuousData, WriteData},
varint::{VARINT_MAX, VarInt, WriteVarInt, be_varint},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CryptoFrame {
offset: VarInt,
length: VarInt,
}
impl super::GetFrameType for CryptoFrame {
fn frame_type(&self) -> super::FrameType {
super::FrameType::Crypto
}
}
impl super::EncodeSize for CryptoFrame {
fn max_encoding_size(&self) -> usize {
1 + 8 + 8
}
fn encoding_size(&self) -> usize {
1 + self.offset.encoding_size() + self.length.encoding_size()
}
}
impl CryptoFrame {
pub fn new(offset: VarInt, length: VarInt) -> Self {
Self { offset, length }
}
pub fn offset(&self) -> u64 {
self.offset.into_inner()
}
pub fn len(&self) -> u64 {
self.length.into_inner()
}
pub fn estimate_max_capacity(capacity: usize, offset: u64) -> Option<usize> {
assert!(offset <= VARINT_MAX);
capacity
.checked_sub(1 + VarInt::from_u64(offset).unwrap().encoding_size() + 2)
.map(|remaining| match remaining {
value @ 0..=62 => value + 1,
value @ 0x3F..=0x3F_FF => value,
0x40_00..=0x40_01 => 0x3FFF,
value @ 0x40_02..=0x40_00_00_01 => value - 2,
_ => unreachable!("crypto frame length could not be too large"),
})
}
pub fn range(&self) -> Range<u64> {
let start = self.offset.into_inner();
let end = start + self.length.into_inner();
start..end
}
}
pub fn be_crypto_frame(input: &[u8]) -> nom::IResult<&[u8], CryptoFrame> {
let (remain, (offset, length)) = (be_varint, be_varint).parse(input)?;
if offset.into_inner() + offset.into_inner() > VARINT_MAX {
return Err(nom::Err::Error(nom::error::make_error(
input,
nom::error::ErrorKind::TooLarge,
)));
}
Ok((remain, CryptoFrame { offset, length }))
}
impl<T, D> super::io::WriteDataFrame<CryptoFrame, D> for T
where
T: bytes::BufMut + WriteData<D>,
D: ContinuousData,
{
fn put_data_frame(&mut self, frame: &CryptoFrame, data: &D) {
assert_eq!(frame.length.into_inner(), data.len() as u64);
self.put_frame_type(frame.frame_type());
self.put_varint(&frame.offset);
self.put_varint(&frame.length);
self.put_data(data);
}
}
#[cfg(test)]
mod tests {
use super::CryptoFrame;
use crate::{
frame::{
EncodeSize, FrameType, GetFrameType,
io::{WriteDataFrame, WriteFrameType},
},
varint::VarInt,
};
#[test]
fn test_crypto_frame() {
let frame = CryptoFrame::new(VarInt::from_u32(0), VarInt::from_u32(500));
assert_eq!(frame.frame_type(), super::super::FrameType::Crypto);
assert_eq!(frame.max_encoding_size(), 1 + 8 + 8);
assert_eq!(frame.encoding_size(), 1 + 1 + 2);
assert_eq!(frame.offset(), 0);
assert_eq!(frame.len(), 500);
assert_eq!(frame.range(), 0..500);
}
#[test]
fn test_read_crypto_frame() {
use super::be_crypto_frame;
let buf = vec![0x52, 0x34, 0x80, 0x00, 0x56, 0x78];
let (remain, frame) = be_crypto_frame(&buf).unwrap();
assert_eq!(remain, &[]);
assert_eq!(
frame,
CryptoFrame::new(VarInt::from_u32(0x1234), VarInt::from_u32(0x5678))
);
}
#[test]
fn test_write_crypto_frame() {
let mut buf = bytes::BytesMut::new();
let frame = CryptoFrame::new(VarInt::from_u32(0x1234), VarInt::from_u32(0x5));
buf.put_data_frame(&frame, b"hello");
let mut expected = Vec::new();
expected.put_frame_type(FrameType::Crypto);
expected.extend_from_slice(&[0x52, 0x34, 0x05]);
expected.extend_from_slice(b"hello");
assert_eq!(buf, bytes::Bytes::from(expected));
}
#[test]
fn test_encoding_capacity_estimate() {
assert_eq!(CryptoFrame::estimate_max_capacity(1, 0), None);
assert_eq!(CryptoFrame::estimate_max_capacity(4, 0), Some(1));
assert_eq!(CryptoFrame::estimate_max_capacity(4, 64), None);
assert_eq!(CryptoFrame::estimate_max_capacity(5, 65), Some(1));
assert_eq!(CryptoFrame::estimate_max_capacity(67, 65), Some(63));
assert_eq!(CryptoFrame::estimate_max_capacity(68, 65), Some(63));
assert_eq!(CryptoFrame::estimate_max_capacity(69, 65), Some(64));
assert_eq!(CryptoFrame::estimate_max_capacity(16387, 65), Some(16382));
assert_eq!(CryptoFrame::estimate_max_capacity(16388, 65), Some(16383));
assert_eq!(CryptoFrame::estimate_max_capacity(16389, 65), Some(16383));
assert_eq!(CryptoFrame::estimate_max_capacity(16390, 65), Some(16383));
assert_eq!(CryptoFrame::estimate_max_capacity(16391, 65), Some(16384));
}
#[test]
#[should_panic]
fn test_encoding_with_offset_exceeded() {
CryptoFrame::estimate_max_capacity(60, 1 << 62);
}
#[test]
#[should_panic]
fn test_encoding_with_length_too_large() {
CryptoFrame::estimate_max_capacity(1 << 31, 20);
}
}