1use ntex_bytes::BufMut;
2
3use crate::frame::{Frame, FrameError, Head, Kind, StreamId};
4
5const ACK_FLAG: u8 = 0x1;
6
7pub type Payload = [u8; 8];
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct Ping {
11 ack: bool,
12 payload: Payload,
13}
14
15impl Ping {
16 pub fn new(payload: Payload) -> Ping {
17 Ping {
18 ack: false,
19 payload,
20 }
21 }
22
23 pub fn pong(payload: Payload) -> Ping {
24 Ping { ack: true, payload }
25 }
26
27 pub fn is_ack(&self) -> bool {
28 self.ack
29 }
30
31 pub fn payload(&self) -> &Payload {
32 &self.payload
33 }
34
35 pub fn into_payload(self) -> Payload {
36 self.payload
37 }
38
39 pub fn load(head: Head, bytes: &[u8]) -> Result<Ping, FrameError> {
41 debug_assert_eq!(head.kind(), crate::frame::Kind::Ping);
42
43 if !head.stream_id().is_zero() {
48 return Err(FrameError::InvalidStreamId);
49 }
50
51 if bytes.len() != 8 {
54 return Err(FrameError::BadFrameSize);
55 }
56
57 let mut payload = [0; 8];
58 payload.copy_from_slice(bytes);
59
60 let ack = head.flag() & ACK_FLAG != 0;
66
67 Ok(Ping { ack, payload })
68 }
69
70 pub fn encode<B: BufMut>(&self, dst: &mut B) {
71 let sz = self.payload.len();
72 log::trace!("encoding PING; ack={} len={}", self.ack, sz);
73
74 let flags = if self.ack { ACK_FLAG } else { 0 };
75 let head = Head::new(Kind::Ping, flags, StreamId::zero());
76
77 head.encode(sz, dst);
78 dst.put_slice(&self.payload);
79 }
80}
81
82impl From<Ping> for Frame {
83 fn from(src: Ping) -> Frame {
84 Frame::Ping(src)
85 }
86}