async_proto/impls/
hematite_nbt.rs

1use {
2    std::{
3        io::prelude::*,
4        pin::Pin,
5    },
6    fallible_collections::FallibleVec as _,
7    tokio::io::{
8        AsyncRead,
9        AsyncReadExt as _,
10        AsyncWrite,
11        AsyncWriteExt as _,
12    },
13    crate::{
14        ErrorContext,
15        LengthPrefixed,
16        Protocol,
17        ReadError,
18        ReadErrorKind,
19        WriteError,
20        WriteErrorKind,
21    },
22};
23
24/// An [`nbt::Blob`] is Gzip-compressed and prefixed with the length of the blob after compression as a [`u64`].
25#[cfg_attr(docsrs, doc(cfg(feature = "hematite-nbt")))]
26impl Protocol for nbt::Blob {
27    fn read<'a, R: AsyncRead + Unpin + Send + 'a>(stream: &'a mut R) -> Pin<Box<dyn Future<Output = Result<Self, ReadError>> + Send + 'a>> {
28        Self::read_length_prefixed(stream, u64::MAX)
29    }
30
31    fn write<'a, W: AsyncWrite + Unpin + Send + 'a>(&'a self, sink: &'a mut W) -> Pin<Box<dyn Future<Output = Result<(), WriteError>> + Send + 'a>> {
32        self.write_length_prefixed(sink, u64::MAX)
33    }
34
35    fn read_sync(stream: &mut impl Read) -> Result<Self, ReadError> {
36        Self::read_length_prefixed_sync(stream, u64::MAX)
37    }
38
39    fn write_sync(&self, sink: &mut impl Write) -> Result<(), WriteError> {
40        self.write_length_prefixed_sync(sink, u64::MAX)
41    }
42}
43
44#[cfg_attr(docsrs, doc(cfg(feature = "hematite-nbt")))]
45impl LengthPrefixed for nbt::Blob {
46    fn read_length_prefixed<'a, R: AsyncRead + Unpin + Send + 'a>(stream: &'a mut R, max_len: u64) -> Pin<Box<dyn Future<Output = Result<Self, ReadError>> + Send + 'a>> {
47        Box::pin(async move {
48            let len = super::read_len(stream, max_len, || ErrorContext::BuiltIn { for_type: "nbt::Blob" }).await?;
49            let mut buf = Vec::default();
50            buf.try_resize(len, 0).map_err(|e| ReadError {
51                context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
52                kind: e.into(),
53            })?;
54            stream.read_exact(&mut buf).await.map_err(|e| ReadError {
55                context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
56                kind: e.into(),
57            })?;
58            Self::from_gzip_reader(&mut &*buf).map_err(|e| ReadError {
59                context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
60                kind: ReadErrorKind::Custom(e.to_string()),
61            })
62        })
63    }
64
65    fn write_length_prefixed<'a, W: AsyncWrite + Unpin + Send + 'a>(&'a self, sink: &'a mut W, max_len: u64) -> Pin<Box<dyn Future<Output = Result<(), WriteError>> + Send + 'a>> {
66        Box::pin(async move {
67            let mut buf = Vec::default();
68            self.to_gzip_writer(&mut buf).map_err(|e| WriteError {
69                context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
70                kind: WriteErrorKind::Custom(e.to_string()),
71            })?;
72            super::write_len(sink, buf.len(), max_len, || ErrorContext::BuiltIn { for_type: "nbt::Blob" }).await?;
73            sink.write_all(&buf).await.map_err(|e| WriteError {
74                context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
75                kind: e.into(),
76            })?;
77            Ok(())
78        })
79    }
80
81    fn read_length_prefixed_sync(stream: &mut impl Read, max_len: u64) -> Result<Self, ReadError> {
82        let len = super::read_len_sync(stream, max_len, || ErrorContext::BuiltIn { for_type: "nbt::Blob" })?;
83        let mut buf = Vec::default();
84        buf.try_resize(len, 0).map_err(|e| ReadError {
85            context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
86            kind: e.into(),
87        })?;
88        stream.read_exact(&mut buf).map_err(|e| ReadError {
89            context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
90            kind: e.into(),
91        })?;
92        Self::from_gzip_reader(&mut &*buf).map_err(|e| ReadError {
93            context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
94            kind: ReadErrorKind::Custom(e.to_string()),
95        })
96    }
97
98    fn write_length_prefixed_sync(&self, sink: &mut impl Write, max_len: u64) -> Result<(), WriteError> {
99        let mut buf = Vec::default();
100        self.to_gzip_writer(&mut buf).map_err(|e| WriteError {
101            context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
102            kind: WriteErrorKind::Custom(e.to_string()),
103        })?;
104        super::write_len_sync(sink, buf.len(), max_len, || ErrorContext::BuiltIn { for_type: "nbt::Blob" })?;
105        sink.write_all(&buf).map_err(|e| WriteError {
106            context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
107            kind: e.into(),
108        })?;
109        Ok(())
110    }
111}