chunkedge_binary/lib.rs
1use std::io::Write;
2
3pub mod array;
4pub mod bit_set;
5mod bounded;
6pub mod byte_angle;
7mod id_or;
8mod id_set;
9mod impls;
10mod raw;
11mod text_component;
12mod var_int;
13mod var_long;
14
15pub use bounded::Bounded;
16pub use id_or::IdOr;
17pub use id_set::IDSet;
18pub use impls::cautious_capacity;
19pub use raw::RawBytes;
20pub use text_component::{IntoTextComponent, TextComponent};
21pub use var_int::{VarInt, VarIntDecodeError};
22pub use var_long::VarLong;
23
24#[doc(hidden)]
25pub mod __private {
26 pub use anyhow::{anyhow, bail, ensure, Context, Result};
27
28 pub use crate::{Decode, Encode, VarInt};
29}
30
31pub use chunkedge_protocol_macros::{Decode, Encode};
32
33/// The `Encode` trait allows objects to be written to the Minecraft protocol.
34/// It is the inverse of [`Decode`].
35///
36/// # Deriving
37///
38/// This trait can be implemented automatically for structs and enums by using
39/// the [`Encode`][macro] derive macro. All components of the type must
40/// implement `Encode`. Components are encoded in the order they appear in the
41/// type definition.
42///
43/// For enums, the variant to encode is marked by a leading [`VarInt`]
44/// discriminant (tag). The discriminant value can be changed using the
45/// `#[packet(tag = ...)]` attribute on the variant in question. Discriminant
46/// values are assigned to variants using rules similar to regular enum
47/// discriminants.
48///
49/// ```
50/// use chunkedge_binary::Encode;
51///
52/// #[derive(Encode)]
53/// struct MyStruct<'a> {
54/// first: i32,
55/// second: &'a str,
56/// third: [f64; 3],
57/// }
58///
59/// #[derive(Encode)]
60/// enum MyEnum {
61/// First, // tag = 0
62/// Second, // tag = 1
63/// #[packet(tag = 25)]
64/// Third, // tag = 25
65/// Fourth, // tag = 26
66/// }
67///
68/// let value = MyStruct {
69/// first: 10,
70/// second: "hello",
71/// third: [1.5, 3.14, 2.718],
72/// };
73///
74/// let mut buf = vec![];
75/// value.encode(&mut buf).unwrap();
76///
77/// println!("{buf:?}");
78/// ```
79///
80/// [macro]: chunkedge_protocol_macros::Encode
81/// [`VarInt`]: var_int::VarInt
82pub trait Encode {
83 /// Writes this object to the provided writer.
84 ///
85 /// If this type also implements [`Decode`] then successful calls to this
86 /// function returning `Ok(())` must always successfully [`decode`] using
87 /// the data that was written to the writer. The exact number of bytes
88 /// that were originally written must be consumed during the decoding.
89 ///
90 /// [`decode`]: Decode::decode
91 fn encode(&self, w: impl Write) -> anyhow::Result<()>;
92
93 /// Like [`Encode::encode`], except that a whole slice of values is encoded.
94 ///
95 /// This method must be semantically equivalent to encoding every element of
96 /// the slice in sequence with no leading length prefix (which is exactly
97 /// what the default implementation does), but a more efficient
98 /// implementation may be used.
99 ///
100 /// This method is important for some types like `u8` where the entire slice
101 /// can be encoded in a single call to [`write_all`]. Because impl
102 /// specialization is unavailable in stable Rust at the time of writing,
103 /// we must make the slice specialization part of this trait.
104 ///
105 /// [`write_all`]: Write::write_all
106 fn encode_slice(slice: &[Self], mut w: impl Write) -> anyhow::Result<()>
107 where
108 Self: Sized,
109 {
110 for value in slice {
111 value.encode(&mut w)?;
112 }
113
114 Ok(())
115 }
116}
117
118/// The `Decode` trait allows objects to be read from the Minecraft protocol. It
119/// is the inverse of [`Encode`].
120///
121/// `Decode` is parameterized by a lifetime. This allows the decoded value to
122/// borrow data from the byte slice it was read from.
123///
124/// # Deriving
125///
126/// This trait can be implemented automatically for structs and enums by using
127/// the [`Decode`][macro] derive macro. All components of the type must
128/// implement `Decode`. Components are decoded in the order they appear in the
129/// type definition.
130///
131/// For enums, the variant to decode is determined by a leading [`VarInt`]
132/// discriminant (tag). The discriminant value can be changed using the
133/// `#[packet(tag = ...)]` attribute on the variant in question. Discriminant
134/// values are assigned to variants using rules similar to regular enum
135/// discriminants.
136///
137/// ```
138/// use chunkedge_binary::Decode;
139///
140/// #[derive(PartialEq, Debug, Decode)]
141/// struct MyStruct {
142/// first: i32,
143/// second: MyEnum,
144/// }
145///
146/// #[derive(PartialEq, Debug, Decode)]
147/// enum MyEnum {
148/// First, // tag = 0
149/// Second, // tag = 1
150/// #[packet(tag = 25)]
151/// Third, // tag = 25
152/// Fourth, // tag = 26
153/// }
154///
155/// let mut r: &[u8] = &[0, 0, 0, 0, 26];
156///
157/// let value = MyStruct::decode(&mut r).unwrap();
158/// let expected = MyStruct {
159/// first: 0,
160/// second: MyEnum::Fourth,
161/// };
162///
163/// assert_eq!(value, expected);
164/// assert!(r.is_empty());
165/// ```
166///
167/// [macro]: chunkedge_protocol_macros::Decode
168/// [`VarInt`]: var_int::VarInt
169pub trait Decode<'a>: Sized {
170 /// Reads this object from the provided byte slice.
171 ///
172 /// Implementations of `Decode` are expected to shrink the slice from the
173 /// front as bytes are read.
174 fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self>;
175}