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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#![deny(missing_docs)]
//! This create provides important functions for reading and writing data
use std::future::Future;
use std::io::{Read, Write};

use tokio::io::{AsyncWrite, AsyncRead};

use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};

/// Reads a single byte asyncronously from the provided reader
///
/// # Arguments
///
/// `reader` - A mutable reference to a type implemnting `AsyncRead` and `Unpin`
/// `line` - A line number, where the function is called
/// `file` - A static string slice containing the name of the file, where the function was called
///
/// # Returns
///
/// Returns an `binary_utils::Result` containing the byte or an error if the reading failed
///
/// # Errors
///
/// This function can fail, if there is no data in the provided `reader` to read.
pub async fn read_byte(reader: &mut (impl AsyncRead + Unpin), line: u32, file: &'static str) -> Result<u8> {
    let mut data = [0u8; 1];
    match reader.read_exact(&mut data).await {
        Ok(_) => Ok(data[0]),
        Err(_) => Error::NotEnoughtBytes(format!("{}:{}", file, line)).into(),
    }
}
/// Consumes a single utf16be character asyncronously from the provided reader
///
/// This is intended to be used to move the cursor over an utf16be string.
///
/// # Arguments
///
/// `reader` - A mutable reference to a type implemnting `AsyncRead` and `Unpin`
/// `line` - A line number, where the function is called
/// `file` - A static string slice containing the name of the file, where the function was called
///
/// # Returns
///
/// Returns an `binary_utils::Result` containing `Ok(())` or an error if the reading failed
///
/// # Errors
///
/// This function can fail, if there is no data in the provided `reader` to read.
pub async fn consume_utf16be_char(reader: &mut (impl AsyncRead + Unpin), line: u32, file: &'static str) -> Result<()> {
    read_byte(reader, line, file).await?;
    read_byte(reader, line, file).await?;
    Ok(())
}
/// A function to asyncronously write data to the provided `writer`.
///
/// # Arguments
///
/// `writer` - A mutable reference to a type implementing `AsyncWrite` and `Unpin`
/// `bytes` - A reference to a slice of bytes that gets written into the provided `writer`
///
/// # Returns
///
/// Returns `Ok(())` or an error, if the write operation fails.
pub async fn write_bytes(writer: &mut (impl AsyncWrite + Unpin), bytes: &[u8]) -> Result<()> {
    match writer.write_all(bytes).await {
        Ok(_) => Ok(()),
        Err(_) => Error::FailedToWrite.into(),
    }
}
/// Reads a single UTF-8 character asyncronously from the provided reader
///
/// # Arguments
///
/// `reader` - A mutable reference to a type implemnting `AsyncRead` and `Unpin`
/// `line` - A line number, where the function is called
/// `file` - A static string slice containing the name of the file, where the function was called
///
/// # Returns
///
/// Returns an `binary_utils::Result` containing the UTF-8 `char` or an error if the reading failed
///
/// # Errors
///
/// This function can fail, if there is no data in the provided `reader` to read.
pub async fn read_utf8_char(reader: &mut (impl AsyncRead + Unpin), line: u32, file: &'static str) -> Result<char> {
    let current = read_byte(reader, line, file).await? as u8;
    match current {
        0b0000_0000..=0b0111_1111 => 
            match char::from_u32(current as u32) 
                { Some(v) => Ok(v), None => Error::InvalidStructure.into()},
        0b1100_0000..=0b1101_1111 => 
            match char::from_u32(((current as u32) << 8) + read_byte(reader, line, file).await? as u32) 
                { Some(v) => Ok(v), None => Error::InvalidStructure.into()},
        0b1110_0000..=0b1110_1111 => 
            match char::from_u32(((current as u32) << 16) + ((read_byte(reader, line, file).await? as u32) << 8) + read_byte(reader, line, file).await? as u32) 
                { Some(v) => Ok(v), None => Error::InvalidStructure.into()},
        0b1111_0000..=0b1111_0111 => 
            match char::from_u32(((current as u32) << 24) + ((read_byte(reader, line, file).await? as u32) << 16) + ((read_byte(reader, line, file).await? as u32) << 8) + read_byte(reader, line, file).await? as u32) 
                { Some(v) => Ok(v), None => Error::InvalidStructure.into()},
        _ => Error::InvalidStructure.into()
    }
}
/// A trait for types that need to be read from a binary stream
///
/// Implementations of this trait provide a way to write their data 
/// asyncronously to a type that implements `AsyncRead` and `Unpin`
///
/// # Notes
///
/// This trait is intended to be implemented for types that represent structured data and provide
/// a method to asynchronously read that data from an input source. Implementations should handle
/// error conditions appropriately and return a `Result` indicating success or failure.
///
pub trait DataReader: Sized {
    // Reads data from the provided reader asynchronously and constructs an instance of `Self`.
    ///
    /// # Arguments
    ///
    /// * `reader` - A mutable reference to a type implementing `AsyncRead` and `Unpin` traits,
    ///              from which the data will be read.
    ///
    /// # Returns
    ///
    /// Returns a future representing the asynchronous reading operation. The future resolves to
    /// a `Result` containing an instance of `Self` if the operation is successful, or an error
    /// indicating failure.
    fn read(reader: &mut (impl AsyncRead + Unpin)) -> impl Future<Output = Result<Self>>;
}

/// A trait for types that need to be read from a binary stream synchronously
///
/// Implementations of this trait provide a way to read their data 
/// synchronously from a type that implements `Read`
pub trait SyncDataReader: Sized {
    /// Reads data from the provided reader synchronously and constructs an instance of `Self`.
    ///
    /// # Arguments
    ///
    /// * `reader` - A mutable reference to a type implementing `Read` trait,
    ///              from which the data will be read.
    ///
    /// # Returns
    ///
    /// Returns a result containing an instance of `Self` if the operation is successful, or an error
    /// indicating failure.
    fn read(reader: &mut impl Read) -> Result<Self>;
}

/// A trait for types that have to read Packet data
pub trait PacketReader: Sized {
    /// Reads a packet from the provided stream `reader` using the specified `id` and `length`
    ///
    /// # Arguments
    ///
    /// `reader` - A mutable reference to a type implementing `AsyncRead` and `Unpin`
    /// `length` - the length of the packet (be careful, could be userdefined)
    /// `packet_id` - the id of the packet (packet type)
    fn read(
        reader: &mut (impl AsyncRead + Unpin),
        length: i32,
        packet_id: i32,
    ) -> impl Future<Output = Result<Self>>;
}

/// A trait for types that have to be writen to an asyncronous stream
///
/// # Notes
///
/// This trait is intended to be implemented for types that represent structured data and provide
/// a method to asynchronously write that data into an output source. Implementations should handle
/// error conditions appropriately and return a `Result` indicating success or failure.
///
pub trait DataWriter {
    /// Writes the data of the object into the defined `writer`
    ///
    /// # Arguments
    ///
    /// `writer` - A mutable reference to a type implementing `AsyncRead` and `Unpin`
    /// 
    /// # Returns
    ///
    /// Returns a future representing the asynchronous writing operation. The future resolves to
    /// a `Result` containing an instance of `()` if the operation is successful, or an error
    /// indicating failure.
    fn write(&self, writer: &mut (impl AsyncWrite + Unpin)) -> impl Future<Output = Result<()>>;
}

/// A trait for types that have to be written to a synchronous stream
///
/// # Notes
///
/// This trait is intended to be implemented for types that represent structured data and provide
/// a method to synchronously write that data into an output source. Implementations should handle
/// error conditions appropriately and return a `Result` indicating success or failure.
pub trait SyncDataWriter {
    /// Writes the data of the object into the defined `writer`.
    ///
    /// # Arguments
    ///
    /// * `writer` - A mutable reference to a type implementing `Write` trait,
    ///              into which the data will be written.
    ///
    /// # Returns
    ///
    /// Returns a result indicating success or failure of the writing operation.
    fn write(&self, writer: &mut impl Write) -> Result<()>;
}

/// A trait for types that need to be read from a binary stream but have an context based size
///
/// Implementations of this trait provide a way to write their data 
/// asyncronously to a type that implements `AsyncRead` and `Unpin`
///
/// # Notes
///
/// This trait is intended to be implemented for types that represent structured data and provide
/// a method to asynchronously read that data from an input source. Implementations should handle
/// error conditions appropriately and return a `Result` indicating success or failure.
///
pub trait ListDataReader: Sized {
    // Reads data from the provided reader asynchronously and constructs an instance of `Self`.
    ///
    /// # Arguments
    ///
    /// * `reader` - A mutable reference to a type implementing `AsyncRead` and `Unpin` traits,
    ///              from which the data will be read.
    /// * `length` - A length, how much data is contained, because the size is context based
    ///
    /// # Returns
    ///
    /// Returns a future representing the asynchronous reading operation. The future resolves to
    /// a `Result` containing an instance of `Self` if the operation is successful, or an error
    /// indicating failure.
    fn read_list(reader: &mut (impl AsyncRead + Unpin), length: usize) -> impl Future<Output = Result<Self>>;
}
/// A trait implemented by every Packet to make them Storeable and recogniseable
pub trait Packet: Sized {}
/// An enum containing the different variants, why the read and write functions could fail
#[derive(Debug)]
pub enum Error {
    /// Used if an id was read that was not expected
    InvalidId,
    /// Used if the read structure dooes not fit the expected one
    InvalidStructure,
    /// Used if there are not enough bytes in the stream to read the expected data
    NotEnoughtBytes(String),
    /// Used if the Write Operation failed
    FailedToWrite,
}
/// A type alias for `std::result::Result` with the error type set to `Error`.
///
/// This type is commonly used throughout the codebase to represent the result of operations
/// that may fail, where `T` represents the success value and `Error` represents the type of error.
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
    /// Converts the `Error` into a `Result` with an error value.
    ///
    /// This method is useful for converting an `Error` into a `Result` for functions
    /// or operations that return a `Result`.
    pub fn to_result<T>(self) -> Result<T> {
        Err(self)
    }
}
impl<T> Into<Result<T>> for Error {
    fn into(self) -> Result<T> {
        Err(self)
    }
}