wire_framed_core/
utils.rs

1use bytes::{Buf, Bytes, BufMut, BytesMut};
2use std::{io::{self, ErrorKind}, collections::HashSet, hash::Hash};
3
4/// A utility function to get a [`bool`] from a [`Bytes`].
5pub 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
10/// A utility function to get a [`u8`] from a [`Bytes`].
11pub 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
16/// A utility function to get a [`u16`] from a [`Bytes`].
17pub 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
22/// A utility function to get a [`u32`] from a [`Bytes`].
23pub 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
28/// A utility function to get a [`u64`] from a [`Bytes`].
29pub 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
34/// A utility function to get a [`i8`] from a [`Bytes`].
35pub 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
40/// A utility function to get a [`i16`] from a [`Bytes`].
41pub 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
46/// A utility function to get a [`i32`] from a [`Bytes`].
47pub 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
52/// A utility function to get a [`i64`] from a [`Bytes`].
53pub 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
58/// A utility function to get a [`String`] from a [`Bytes`].
59pub 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
70/// A utility function to get an [`Option`] from a [`Bytes`].
71pub 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
88/// A utility function to get an [`Vec<Option>`] from a [`Bytes`].
89pub 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
114/// A utility function to get a [`Vec`] from a [`Bytes`].
115pub 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
128/// A utility function to get a [`HashSet`] from a [`Bytes`].
129pub 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
142/// A utility function to put a [`&str`] into a [`BytesMut`].
143pub 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
148/// A utility function to put an [`Option`] into a [`BytesMut`].
149pub 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
162/// A utility function to put a [`Vec`] into a [`BytesMut`].
163pub 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
170/// A utility function to put a [`HashSet`] into a [`BytesMut`].
171pub 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
178/// A utility function to put a [`Vec<Option>`] into a [`BytesMut`].
179pub 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}