pipe_chain/parser/
pktline.rs1use crate::{
3 byte::{take, TagByteError, TagBytesError},
4 tag, Incomplete, MapExt, Pipe, Result,
5};
6use fatal_error::FatalError;
7use std::str::from_utf8_unchecked;
8
9#[derive(Debug)]
11pub enum PktLineError {
12 Incomplete(Incomplete),
14 InvalidSize,
16 TagByte(TagByteError),
18 TagBytes(TagBytesError),
20}
21
22impl From<Incomplete> for PktLineError {
23 fn from(value: Incomplete) -> Self { PktLineError::Incomplete(value) }
24}
25
26impl From<TagByteError> for PktLineError {
27 fn from(value: TagByteError) -> Self { PktLineError::TagByte(value) }
28}
29
30impl From<TagBytesError> for PktLineError {
31 fn from(value: TagBytesError) -> Self { PktLineError::TagBytes(value) }
32}
33
34impl std::fmt::Display for PktLineError {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 PktLineError::Incomplete(x) => write!(f, "{x}"),
38 PktLineError::InvalidSize => write!(f, "invalid size"),
39 PktLineError::TagByte(x) => write!(f, "PktLine Error: {x}"),
40 PktLineError::TagBytes(x) => write!(f, "PktLine Error: {x}"),
41 }
42 }
43}
44
45impl std::error::Error for PktLineError {
46 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
47 match self {
48 PktLineError::Incomplete(x) => Some(x),
49 PktLineError::TagByte(x) => Some(x),
50 PktLineError::TagBytes(x) => Some(x),
51 _ => None,
52 }
53 }
54}
55
56#[derive(Debug, PartialEq, Eq)]
58pub enum PktLine {
59 Flush,
61 Delim,
63 End,
65 Data(Vec<u8>),
67}
68
69impl PktLine {
70 pub fn as_string(&self) -> String {
72 match self {
73 PktLine::Flush => "0000".to_string(),
74 PktLine::Delim => "0001".to_string(),
75 PktLine::End => "0002".to_string(),
76 PktLine::Data(x) => String::from_utf8_lossy(x).to_string(),
77 }
78 }
79
80 pub fn into_bytes(self) -> Vec<u8> {
82 match self {
83 PktLine::Flush => b"0000".to_vec(),
84 PktLine::Delim => b"0001".to_vec(),
85 PktLine::End => b"0002".to_vec(),
86 PktLine::Data(x) => {
87 format!("{:04x}", x.len() + 4).into_bytes().into_iter().chain(x).collect()
88 }
89 }
90 }
91}
92
93pub fn pkt_line<'a>(data: &'a [u8]) -> Result<&'a [u8], (PktLine,), PktLineError> {
95 if data.len() < 4 {
96 return Err(FatalError::Error(Incomplete::Size(4 - data.len()).into()));
97 }
98 let (size, data) = data.split_at(4);
99 let size = match (size[0], size[1], size[2], size[3]) {
100 (
101 b'0'..=b'9' | b'a'..=b'f',
102 b'0'..=b'9' | b'a'..=b'f',
103 b'0'..=b'9' | b'a'..=b'f',
104 b'0'..=b'9' | b'a'..=b'f',
105 ) => Ok(unsafe {
106 u16::from_str_radix(from_utf8_unchecked(size), 16).unwrap_unchecked()
107 }),
108 _ => Err(FatalError::Fatal(PktLineError::InvalidSize)),
109 }?;
110 match size {
111 0 => Ok((data, (PktLine::Flush,))),
112 1 => Ok((data, (PktLine::Delim,))),
113 2 => Ok((data, (PktLine::End,))),
114 x @ 5..=65520 => take((x - 4) as usize)
115 .map1(|x: &'a [u8]| PktLine::Data(x.to_vec()))
116 .apply(data),
117 _ => Err(FatalError::Fatal(PktLineError::InvalidSize)),
118 }
119}
120
121pub fn pkt_flush(data: &'_ [u8]) -> Result<&'_ [u8], (PktLine,), PktLineError> {
123 tag(b"0000").map1(|_| PktLine::Flush).apply(data)
124}
125
126pub fn pkt_delim(data: &'_ [u8]) -> Result<&'_ [u8], (PktLine,), PktLineError> {
128 tag(b"0001").map1(|_| PktLine::Delim).apply(data)
129}
130
131pub fn pkt_end(data: &'_ [u8]) -> Result<&'_ [u8], (PktLine,), PktLineError> {
133 tag(b"0002").map1(|_| PktLine::End).apply(data)
134}