1use core::{
2 hash::BuildHasher,
3 marker::PhantomData,
4 num::{
5 NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
6 NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
7 },
8};
9use std::{
10 borrow::Cow,
11 collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
12 ffi::{CStr, CString},
13 sync::Arc,
14};
15
16use crate::{
17 async_trait,
18 io::{Write, WriteExt},
19 Config, Endianness, Result,
20};
21
22#[async_trait]
23pub trait Encode {
25 fn size(&self) -> usize;
27
28 async fn encode_to<W>(&self, config: &Config, writer: W) -> Result<usize>
38 where
39 W: Write + Unpin + Send;
40}
41
42macro_rules! impl_primitive {
43 ($($type: tt),+) => {
44 $(
45 #[async_trait]
46 impl Encode for $type {
47 #[inline]
48 fn size(&self) -> usize {
49 core::mem::size_of::<Self>()
50 }
51
52 async fn encode_to<W>(&self, config: &Config, mut writer: W) -> Result<usize>
53 where
54 W: Write + Unpin + Send,
55 {
56 match config.endianness {
57 Endianness::LittleEndian => writer.write(&self.to_le_bytes()).await.map_err(Into::into),
58 Endianness::BigEndian => writer.write(&self.to_be_bytes()).await.map_err(Into::into)
59 }
60 }
61 }
62 )+
63 };
64}
65
66impl_primitive!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize, f32, f64);
67
68#[async_trait]
69impl Encode for bool {
70 #[inline]
71 fn size(&self) -> usize {
72 core::mem::size_of::<bool>()
73 }
74
75 #[allow(clippy::trivially_copy_pass_by_ref)]
76 async fn encode_to<W>(&self, config: &Config, writer: W) -> Result<usize>
77 where
78 W: Write + Unpin + Send,
79 {
80 (*self as u8).encode_to(config, writer).await
81 }
82}
83
84#[async_trait]
85impl Encode for char {
86 #[inline]
87 fn size(&self) -> usize {
88 core::mem::size_of::<char>()
89 }
90
91 #[allow(clippy::trivially_copy_pass_by_ref)]
92 async fn encode_to<W>(&self, config: &Config, writer: W) -> Result<usize>
93 where
94 W: Write + Unpin + Send,
95 {
96 (*self as u32).encode_to(config, writer).await
97 }
98}
99
100#[async_trait]
101impl<T> Encode for Option<T>
102where
103 T: Encode + Sync,
104{
105 fn size(&self) -> usize {
106 match self {
107 Some(ref value) => core::mem::size_of::<u8>() + value.size(),
108 None => core::mem::size_of::<u8>(),
109 }
110 }
111
112 async fn encode_to<W>(&self, config: &Config, mut writer: W) -> Result<usize>
113 where
114 W: Write + Unpin + Send,
115 {
116 match self {
117 None => 0u8.encode_to(config, &mut writer).await.map_err(Into::into),
118 Some(ref value) => Ok(1u8.encode_to(config, &mut writer).await?
119 + value.encode_to(config, &mut writer).await?),
120 }
121 }
122}
123
124#[async_trait]
125impl<T, E> Encode for core::result::Result<T, E>
126where
127 T: Encode + Sync,
128 E: Encode + Sync,
129{
130 fn size(&self) -> usize {
131 match self {
132 Ok(ref value) => core::mem::size_of::<u8>() + value.size(),
133 Err(ref err) => core::mem::size_of::<u8>() + err.size(),
134 }
135 }
136
137 async fn encode_to<W>(&self, config: &Config, mut writer: W) -> Result<usize>
138 where
139 W: Write + Unpin + Send,
140 {
141 match self {
142 Ok(ref value) => {
143 Ok(0u8.encode_to(config, &mut writer).await?
144 + value.encode_to(config, writer).await?)
145 }
146 Err(ref err) => {
147 Ok(1u8.encode_to(config, &mut writer).await?
148 + err.encode_to(config, writer).await?)
149 }
150 }
151 }
152}
153
154macro_rules! impl_seq {
155 ($ty: tt < T $(: $tbound1: tt $(+ $tbound2: ident)*)* $(, $typaram: tt : $bound1: tt $(+ $bound2: tt)*)* >) => {
156 #[async_trait]
157 impl<T $(, $typaram)*> Encode for $ty<T $(, $typaram)*>
158 where
159 T: Encode + Sync $(+ $tbound1 $(+ $tbound2)*)*,
160 $($typaram: $bound1 $(+ $bound2)*,)*
161 {
162 #[inline]
163 fn size(&self) -> usize {
164 core::mem::size_of::<u64>() + self.iter().map(Encode::size).sum::<usize>()
165 }
166
167 #[allow(clippy::ptr_arg)]
168 async fn encode_to<W>(&self, config: &Config, mut writer: W) -> Result<usize>
169 where
170 W: Write + Unpin + Send,
171 {
172 let mut encoded = 0;
173
174 encoded += (self.len() as u64).encode_to(config, &mut writer).await?;
175
176 for item in self.iter() {
177 encoded += item.encode_to(config, &mut writer).await?;
178 }
179
180 Ok(encoded)
181 }
182 }
183 };
184}
185
186impl_seq!(Vec<T>);
187impl_seq!(VecDeque<T>);
188impl_seq!(LinkedList<T>);
189impl_seq!(HashSet<T, S: BuildHasher + Sync>);
190impl_seq!(BTreeSet<T: 'static>);
191impl_seq!(BinaryHeap<T>);
192
193#[async_trait]
194impl<T> Encode for [T]
195where
196 T: Encode + Sync,
197{
198 #[inline]
199 fn size(&self) -> usize {
200 core::mem::size_of::<u64>() + self.iter().map(Encode::size).sum::<usize>()
201 }
202
203 async fn encode_to<W>(&self, config: &Config, mut writer: W) -> Result<usize>
204 where
205 W: Write + Unpin + Send,
206 {
207 let mut encoded = 0;
208
209 encoded += (self.len() as u64).encode_to(config, &mut writer).await?;
210
211 for item in self.iter() {
212 encoded += item.encode_to(config, &mut writer).await?;
213 }
214
215 Ok(encoded)
216 }
217}
218
219macro_rules! impl_as_bytes {
220 ($ty: tt, $as_bytes: tt) => {
221 #[async_trait]
222 impl Encode for $ty {
223 #[inline]
224 fn size(&self) -> usize {
225 Self::$as_bytes(self).size()
226 }
227
228 #[allow(clippy::ptr_arg)]
229 async fn encode_to<W>(&self, config: &Config, writer: W) -> Result<usize>
230 where
231 W: Write + Unpin + Send,
232 {
233 Self::$as_bytes(self).encode_to(config, writer).await
234 }
235 }
236 };
237}
238
239impl_as_bytes!(str, as_bytes);
240impl_as_bytes!(String, as_bytes);
241impl_as_bytes!(CStr, to_bytes);
242impl_as_bytes!(CString, as_bytes);
243
244macro_rules! impl_deref {
245 ($($desc: tt)+) => {
246 #[async_trait]
247 impl $($desc)+ {
248 #[inline]
249 fn size(&self) -> usize {
250 <T>::size(self)
251 }
252
253 async fn encode_to<W>(&self, config: &Config, writer: W) -> Result<usize>
254 where
255 W: Write + Unpin + Send,
256 {
257 <T>::encode_to(self, config, writer).await
258 }
259 }
260 }
261}
262
263impl_deref!(<T: ?Sized> Encode for &T where T: Encode + Sync);
264impl_deref!(<T: ?Sized> Encode for &mut T where T: Encode + Sync);
265impl_deref!(<T: ?Sized> Encode for Box<T> where T: Encode + Sync);
266impl_deref!(<T: ?Sized> Encode for Arc<T> where T: Encode + Sync + Send);
267
268#[async_trait]
269impl<T: ?Sized> Encode for Cow<'_, T>
270where
271 T: Encode + ToOwned + Sync,
272 <T as ToOwned>::Owned: Sync,
273{
274 #[inline]
275 fn size(&self) -> usize {
276 self.as_ref().size()
277 }
278
279 #[allow(clippy::ptr_arg)]
280 async fn encode_to<W>(&self, config: &Config, writer: W) -> Result<usize>
281 where
282 W: Write + Unpin + Send,
283 {
284 self.as_ref().encode_to(config, writer).await
285 }
286}
287
288macro_rules! impl_map {
289 ($ty: tt < K $(: $kbound1: tt $(+ $kbound2: tt)*)*, V $(: $vbound1: tt $(+ $vbound2: tt)*)* $(, $typaram: tt : $bound1: tt $(+ $bound2: tt)*)* >) => {
290 #[async_trait]
291 impl<K, V $(, $typaram)*> Encode for $ty<K, V $(, $typaram)*>
292 where
293 K: Encode + Sync $(+ $kbound1 $(+ $kbound2)*)*,
294 V: Encode + Sync $(+ $vbound1 $(+ $vbound2)*)*,
295 $($typaram: $bound1 $(+ $bound2)*,)*
296 {
297 #[inline]
298 fn size(&self) -> usize {
299 core::mem::size_of::<u64>() + self.iter().map(|entry| entry.size()).sum::<usize>()
300 }
301
302 async fn encode_to<W>(&self, config: &Config, mut writer: W) -> Result<usize>
303 where
304 W: Write + Unpin + Send,
305 {
306 let mut encoded = 0;
307
308 encoded += (self.len() as u64).encode_to(config, &mut writer).await?;
309
310 for item in self.iter() {
311 encoded += item.encode_to(config, &mut writer).await?;
312 }
313
314 Ok(encoded)
315 }
316 }
317 };
318}
319
320impl_map!(HashMap<K, V, S: BuildHasher + Sync>);
321impl_map!(BTreeMap<K: 'static, V: 'static>);
322
323macro_rules! impl_fixed_arr {
324 ($($len: tt),+) => {
325 $(
326 #[async_trait]
327 impl<T> Encode for [T; $len]
328 where
329 T: Encode + Sync,
330 {
331 #[inline]
332 fn size(&self) -> usize {
333 self.iter().map(Encode::size).sum::<usize>()
334 }
335
336 async fn encode_to<W>(&self, config: &Config, mut writer: W) -> Result<usize>
337 where
338 W: Write + Unpin + Send,
339 {
340 let mut encoded = 0;
341
342 for item in self.iter() {
343 encoded += item.encode_to(config, &mut writer).await?;
344 }
345
346 Ok(encoded)
347 }
348 }
349 )+
350 };
351}
352
353impl_fixed_arr!(
354 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
355 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
356 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 128, 256, 512, 1024
357);
358
359#[async_trait]
360impl Encode for () {
361 #[inline]
362 fn size(&self) -> usize {
363 0
364 }
365
366 #[allow(clippy::trivially_copy_pass_by_ref)]
367 async fn encode_to<W>(&self, _config: &Config, _writer: W) -> Result<usize>
368 where
369 W: Write + Unpin + Send,
370 {
371 Ok(0)
372 }
373}
374
375macro_rules! impl_tuple {
376 ($(($($n:tt $name:tt)+))+) => {
377 $(
378 #[async_trait]
379 impl<$($name),+> Encode for ($($name,)+)
380 where
381 $($name: Encode + Send + Sync,)+
382 {
383 #[inline]
384 fn size(&self) -> usize {
385 0 $(+ self.$n.size())+
386 }
387
388 async fn encode_to<W>(&self, config: &Config, mut writer: W) -> Result<usize>
389 where
390 W: Write + Unpin + Send,
391 {
392 let mut encoded = 0;
393
394 $(
395 encoded += self.$n.encode_to(config, &mut writer).await?;
396 )+
397
398 Ok(encoded)
399 }
400 }
401 )+
402 }
403}
404
405impl_tuple! {
406 (0 T0)
407 (0 T0 1 T1)
408 (0 T0 1 T1 2 T2)
409 (0 T0 1 T1 2 T2 3 T3)
410 (0 T0 1 T1 2 T2 3 T3 4 T4)
411 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
412 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
413 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
414 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
415 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
416 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
417 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
418 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
419 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
420 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
421 (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
422}
423
424#[async_trait]
425impl<T> Encode for PhantomData<T>
426where
427 T: Send + Sync + ?Sized,
428{
429 #[inline]
430 fn size(&self) -> usize {
431 0
432 }
433
434 #[allow(clippy::trivially_copy_pass_by_ref)]
435 async fn encode_to<W>(&self, _config: &Config, _writer: W) -> Result<usize>
436 where
437 W: Write + Unpin + Send,
438 {
439 Ok(0)
440 }
441}
442
443macro_rules! impl_non_zero_primitives {
444 ($($type: tt),+) => {
445 $(
446 #[async_trait]
447 impl Encode for $type {
448 #[inline]
449 fn size(&self) -> usize {
450 core::mem::size_of::<Self>()
451 }
452
453 async fn encode_to<W>(&self, config: &Config, writer: W) -> Result<usize>
454 where
455 W: Write + Unpin + Send,
456 {
457 self.get().encode_to(config, writer).await
458 }
459 }
460 )+
461 };
462}
463
464impl_non_zero_primitives!(
465 NonZeroU8,
466 NonZeroU16,
467 NonZeroU32,
468 NonZeroU64,
469 NonZeroU128,
470 NonZeroI8,
471 NonZeroI16,
472 NonZeroI32,
473 NonZeroI64,
474 NonZeroI128,
475 NonZeroUsize,
476 NonZeroIsize
477);