async_proto/impls/
hematite_nbt.rs1use {
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 async_proto_derive::impl_protocol_for,
14 crate::{
15 ErrorContext,
16 LengthPrefixed,
17 Protocol,
18 ReadError,
19 ReadErrorKind,
20 WriteError,
21 WriteErrorKind,
22 },
23};
24
25#[cfg_attr(docsrs, doc(cfg(feature = "hematite-nbt")))]
27impl Protocol for nbt::Blob {
28 fn read<'a, R: AsyncRead + Unpin + Send + 'a>(stream: &'a mut R) -> Pin<Box<dyn Future<Output = Result<Self, ReadError>> + Send + 'a>> {
29 Self::read_length_prefixed(stream, u64::MAX)
30 }
31
32 fn write<'a, W: AsyncWrite + Unpin + Send + 'a>(&'a self, sink: &'a mut W) -> Pin<Box<dyn Future<Output = Result<(), WriteError>> + Send + 'a>> {
33 self.write_length_prefixed(sink, u64::MAX)
34 }
35
36 fn read_sync(stream: &mut impl Read) -> Result<Self, ReadError> {
37 Self::read_length_prefixed_sync(stream, u64::MAX)
38 }
39
40 fn write_sync(&self, sink: &mut impl Write) -> Result<(), WriteError> {
41 self.write_length_prefixed_sync(sink, u64::MAX)
42 }
43}
44
45#[cfg_attr(docsrs, doc(cfg(feature = "hematite-nbt")))]
46impl LengthPrefixed for nbt::Blob {
47 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>> {
48 Box::pin(async move {
49 let len = super::read_len(stream, max_len, || ErrorContext::BuiltIn { for_type: "nbt::Blob" }).await?;
50 let mut buf = Vec::default();
51 buf.try_resize(len, 0).map_err(|e| ReadError {
52 context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
53 kind: e.into(),
54 })?;
55 stream.read_exact(&mut buf).await.map_err(|e| ReadError {
56 context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
57 kind: e.into(),
58 })?;
59 Self::from_gzip_reader(&mut &*buf).map_err(|e| ReadError {
60 context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
61 kind: ReadErrorKind::Custom(e.to_string()),
62 })
63 })
64 }
65
66 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>> {
67 Box::pin(async move {
68 let mut buf = Vec::default();
69 self.to_gzip_writer(&mut buf).map_err(|e| WriteError {
70 context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
71 kind: WriteErrorKind::Custom(e.to_string()),
72 })?;
73 super::write_len(sink, buf.len(), max_len, || ErrorContext::BuiltIn { for_type: "nbt::Blob" }).await?;
74 sink.write_all(&buf).await.map_err(|e| WriteError {
75 context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
76 kind: e.into(),
77 })?;
78 Ok(())
79 })
80 }
81
82 fn read_length_prefixed_sync(stream: &mut impl Read, max_len: u64) -> Result<Self, ReadError> {
83 let len = super::read_len_sync(stream, max_len, || ErrorContext::BuiltIn { for_type: "nbt::Blob" })?;
84 let mut buf = Vec::default();
85 buf.try_resize(len, 0).map_err(|e| ReadError {
86 context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
87 kind: e.into(),
88 })?;
89 stream.read_exact(&mut buf).map_err(|e| ReadError {
90 context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
91 kind: e.into(),
92 })?;
93 Self::from_gzip_reader(&mut &*buf).map_err(|e| ReadError {
94 context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
95 kind: ReadErrorKind::Custom(e.to_string()),
96 })
97 }
98
99 fn write_length_prefixed_sync(&self, sink: &mut impl Write, max_len: u64) -> Result<(), WriteError> {
100 let mut buf = Vec::default();
101 self.to_gzip_writer(&mut buf).map_err(|e| WriteError {
102 context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
103 kind: WriteErrorKind::Custom(e.to_string()),
104 })?;
105 super::write_len_sync(sink, buf.len(), max_len, || ErrorContext::BuiltIn { for_type: "nbt::Blob" })?;
106 sink.write_all(&buf).map_err(|e| WriteError {
107 context: ErrorContext::BuiltIn { for_type: "nbt::Blob" },
108 kind: e.into(),
109 })?;
110 Ok(())
111 }
112}
113
114#[derive(Protocol)]
115#[async_proto(internal)]
116struct ValueProxy(nbt::Blob);
117
118impl TryFrom<ValueProxy> for nbt::Value {
119 type Error = ReadErrorKind;
120
121 fn try_from(ValueProxy(blob): ValueProxy) -> Result<Self, Self::Error> {
122 Ok(blob.get("").ok_or_else(|| ReadErrorKind::Custom(format!("NBT blob missing empty-string entry")))?.clone())
123 }
124}
125
126impl TryFrom<nbt::Value> for ValueProxy {
127 type Error = WriteErrorKind;
128
129 fn try_from(value: nbt::Value) -> Result<Self, Self::Error> {
130 let mut blob = nbt::Blob::default();
131 blob.insert("", value).map_err(|e| WriteErrorKind::Custom(e.to_string()))?;
132 Ok(Self(blob))
133 }
134}
135
136impl_protocol_for! {
137 #[async_proto(attr(cfg_attr(docsrs, doc(cfg(feature = "hematite-nbt")))))]
138 #[async_proto(attr(doc = "An [`nbt::Value`] is represented as an [`nbt::Blob`] with no name and a single entry with no name containing the original value."))]
139 #[async_proto(via = ValueProxy, clone)]
140 type nbt::Value;
141}