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}