1use bytes::{Buf, Bytes, BufMut, BytesMut};
2use std::{io::{self, ErrorKind}, collections::HashSet, hash::Hash};
3
4pub fn get_bool(src: &mut Bytes, name: &str) -> Result<bool, std::io::Error> {
6 if src.len() < 1 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}'", name))) }
7 Ok(src.get_u8() != 0)
8}
9
10pub fn get_u8(src: &mut Bytes, name: &str) -> Result<u8, std::io::Error> {
12 if src.len() < 1 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}'", name))) }
13 Ok(src.get_u8())
14}
15
16pub fn get_u16(src: &mut Bytes, name: &str) -> Result<u16, std::io::Error> {
18 if src.len() < 2 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}'", name))) }
19 Ok(src.get_u16())
20}
21
22pub fn get_u32(src: &mut Bytes, name: &str) -> Result<u32, std::io::Error> {
24 if src.len() < 4 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}'", name))) }
25 Ok(src.get_u32())
26}
27
28pub fn get_u64(src: &mut Bytes, name: &str) -> Result<u64, std::io::Error> {
30 if src.len() < 8 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}'", name))) }
31 Ok(src.get_u64())
32}
33
34pub fn get_i8(src: &mut Bytes, name: &str) -> Result<i8, std::io::Error> {
36 if src.len() < 1 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}'", name))) }
37 Ok(src.get_i8())
38}
39
40pub fn get_i16(src: &mut Bytes, name: &str) -> Result<i16, std::io::Error> {
42 if src.len() < 2 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}'", name))) }
43 Ok(src.get_i16())
44}
45
46pub fn get_i32(src: &mut Bytes, name: &str) -> Result<i32, std::io::Error> {
48 if src.len() < 4 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}'", name))) }
49 Ok(src.get_i32())
50}
51
52pub fn get_i64(src: &mut Bytes, name: &str) -> Result<i64, std::io::Error> {
54 if src.len() < 8 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}'", name))) }
55 Ok(src.get_i64())
56}
57
58pub fn get_string(src: &mut Bytes, name: &str) -> Result<String, std::io::Error> {
60 if src.len() < 4 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}' string size", name))) }
61 let len = src.get_u32() as usize;
62 if src.len() < len { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}' string", name))) }
63 let s = src.copy_to_bytes(len);
64 let s = String::from_utf8(s.to_vec())
65 .map_err(|_| io::Error::new(ErrorKind::InvalidInput, format!("'{}' is not a valid UTF-8 string", name)))?;
66
67 Ok(s)
68}
69
70pub fn get_option<T>(src: &mut Bytes, name: &str, get: impl Fn(&mut Bytes) -> Result<T, std::io::Error>) -> Result<Option<T>, std::io::Error> {
72 const NO_VALUE: u8 = 0;
73 const HAS_VALUE: u8 = 1;
74
75 if src.len() < 1 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}' option tag", name))) }
76 let tag = src.get_u8();
77
78 match tag {
79 NO_VALUE => Ok(None),
80 HAS_VALUE => {
81 let val = get(src)?;
82 Ok(Some(val))
83 },
84 _ => Err(io::Error::new(ErrorKind::InvalidInput, "invalid option tag")),
85 }
86}
87
88pub fn get_option_array<T>(src: &mut Bytes, name: &str, get: impl Fn(&mut Bytes) -> Result<T, std::io::Error>) -> Result<Vec<Option<T>>, std::io::Error> {
90 const NO_VALUE: u8 = 0;
91 const HAS_VALUE: u8 = 1;
92
93 if src.len() < 4 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}' option array size", name))) }
94 let len = src.get_u32() as usize;
95
96 let mut arr = Vec::default();
97 for i in 0..len {
98 if src.len() < 1 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}' at {}. option tag", name, i))) }
99 let tag = src.get_u8();
100
101 match tag {
102 NO_VALUE => arr.push(None),
103 HAS_VALUE => {
104 let val = get(src)?;
105 arr.push(Some(val));
106 },
107 _ => return Err(io::Error::new(ErrorKind::InvalidInput, format!("invalid option tag at {}", i))),
108 }
109 }
110
111 Ok(arr)
112}
113
114pub fn get_array<T>(src: &mut Bytes, name: &str, get: impl Fn(&mut Bytes) -> Result<T, std::io::Error>) -> Result<Vec<T>, std::io::Error> {
116 if src.len() < 4 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}' array size", name))) }
117 let len = src.get_u32() as usize;
118
119 let mut arr = Vec::default();
120 for _ in 0..len {
121 let val = get(src)?;
122 arr.push(val);
123 }
124
125 Ok(arr)
126}
127
128pub fn get_hashset<T: PartialEq + Eq + Hash>(src: &mut Bytes, name: &str, get: impl Fn(&mut Bytes) -> Result<T, std::io::Error>) -> Result<HashSet<T>, std::io::Error> {
130 if src.len() < 4 { return Err(io::Error::new(ErrorKind::InvalidInput, format!("expected '{}' hashset size", name))) }
131 let len = src.get_u32() as usize;
132
133 let mut hashset = HashSet::default();
134 for _ in 0..len {
135 let val = get(src)?;
136 hashset.insert(val);
137 }
138
139 Ok(hashset)
140}
141
142pub fn put_str(dst: &mut BytesMut, s: &str) {
144 dst.put_u32(s.len() as u32);
145 dst.put_slice(s.as_bytes());
146}
147
148pub fn put_option<T>(dst: &mut BytesMut, opt: &Option<T>, put: impl Fn(&mut BytesMut, &T)) {
150 const NO_VALUE: u8 = 0;
151 const HAS_VALUE: u8 = 1;
152
153 match opt {
154 Some(val) => {
155 dst.put_u8(HAS_VALUE);
156 put(dst, &val);
157 },
158 None => dst.put_u8(NO_VALUE),
159 }
160}
161
162pub fn put_array<T>(dst: &mut BytesMut, arr: &[T], put: impl Fn(&mut BytesMut, &T)) {
164 dst.put_u32(arr.len() as u32);
165 for val in arr {
166 put(dst, val);
167 }
168}
169
170pub fn put_hashset<T: PartialEq + Eq + Hash>(dst: &mut BytesMut, hashset: &HashSet<T>, put: impl Fn(&mut BytesMut, &T)) {
172 dst.put_u32(hashset.len() as u32);
173 for val in hashset {
174 put(dst, val);
175 }
176}
177
178pub fn put_option_array<T>(dst: &mut BytesMut, arr: &[Option<T>], put: impl Fn(&mut BytesMut, &T)) {
180 const NO_VALUE: u8 = 0;
181 const HAS_VALUE: u8 = 1;
182
183 dst.put_u32(arr.len() as u32);
184 for opt in arr {
185 match opt {
186 Some(val) => {
187 dst.put_u8(HAS_VALUE);
188 put(dst, val);
189 },
190 None => dst.put_u8(NO_VALUE),
191 }
192 }
193}