Skip to content

Commit c791c30

Browse files
committed
v0.3.0 (Writer Impl. and Traitification)
- Added writer - Adapted tests to use writer - Converted FastByteReader methods into public trait functions - Added those traits for each endianness for both writers and readers - Updated README.md - Updated dependencies (half 2.4.1 -> 2.5.0)
1 parent 19e2242 commit c791c30

File tree

10 files changed

+3074
-2597
lines changed

10 files changed

+3074
-2597
lines changed

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "hyper_byte"
3-
version = "0.2.1"
3+
version = "0.3.0"
44
license = "MIT"
55
authors = ["EasternGamer"]
66
edition = "2021"
@@ -20,10 +20,10 @@ codegen-units = 1
2020
debug = true
2121

2222
[dependencies]
23-
half = { version = "2.4.1", optional = true }
23+
half = { version = "2.5.0", optional = true }
2424

2525
[features]
2626
half = ["dep:half"]
2727

2828
[dev-dependencies]
29-
half = "2.4.1"
29+
half = "2.5.0"

README.md

Lines changed: 102 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Hyper Byte
2-
An unsafe byte slice transmuter and very fast iterator-like reader for Rust's numeric types, for all three endianness'.<br/>
3-
Additionally included is a simple-to-use byte reader.<br/>
2+
An unsafe byte slice transmuter and very fast iterator-like reader and writer for Rust's numeric types, for all three endianness'.<br/>
3+
<br/>
44
**Supported types:**
55
* `u8`
66
* `u16`
@@ -17,6 +17,7 @@ Additionally included is a simple-to-use byte reader.<br/>
1717
* `f64`
1818
* `usize`
1919
* `isize`
20+
* `&[u8]` (a binary slice for any generic size)
2021

2122
## Why?
2223
What a great question. There are plenty of ways to do what this crate does, and there are plenty of crates which already do something similar.
@@ -45,20 +46,36 @@ pub unsafe fn read_f64_ne(bytes: &[u8]) -> f64 {
4546
}
4647
```
4748
Benchmarking it is rather difficult since the compiler will do anything to optimize the call out completely (not run the code, I don't mean make it faster).
48-
However, instructions don't lie, and I did manage to create a benchmark, present around line 2256 in [lib.rs](src/lib.rs#L2286-L2314).<br/>
49+
However, instructions don't lie, and I did manage to create a benchmark, present around line 2322 in [lib.rs](src/lib.rs#L2322-L2351).<br/>
4950
In [Compiler Explorer](https://rust.godbolt.org/z/PfhWzGnnG), you can also see for yourself the instructions for each function.
5051

5152
Running it on my machine, in debug mode, it is around 150% to 200% faster than `try_into`. In release mode, it is closer to only 20% faster.
5253
> [!NOTE]
5354
> While I am very confident that this micro-optimization is faster than the existing solutions, I stand by this only until I'm otherwise corrected.
5455
5556
## Usage
57+
There are several-prebuilt readers/writers available, driven by traits.<br/>For reader traits it is:
58+
- [NativeEndianByteReader](src/readers/traits.rs#L140-L444)
59+
- [LittleEndianByteReader](src/readers/traits.rs#L446-L750)
60+
- [BigEndianByteReader](src/readers/traits.rs#L752-L1056)
61+
- For reader implementations, there is [FastByteReader](src/reader.rs#L4-L51), [NetworkReader](src/reader.rs#L53-L98), [LittleReader](src/reader.rs#L100-L145), and [NativeReader](src/reader.rs#L147-L193).
62+
63+
For writer traits it is:
64+
- [NativeEndianByteWriter](src/writers/traits.rs#L72-L475)
65+
- [LittleEndianByteWriter](src/writers/traits.rs#L477-L880)
66+
- [BigEndianByteWriter](src/writers/traits.rs#L882-L1285)
67+
- For writer implementations, there is [FastByteWriter](src/writer.rs#L3-L71), [NetworkWriter](src/writer.rs#L73-L139), [LittleWriter](src/writer.rs#L141-L207), and [NativeWriter](src/writer.rs#L209-L275).
68+
69+
You might be wondering... why does FastByteReader and FastByteWriter exist? Well, it is to enable cursed functionality such as switching between different endianness.
70+
At the heart of it, all these implementations are incredibly simple to re-implement in your own structs, you can even do a hybrid reader/writer.
71+
5672
### Fast Byte Reader
5773
If you want the fastest possible reader without going into completely unsafe territory, then you should use the FastByteReader.<br/>
5874
Simply, it is an iterator-like reader where reading a type will result in consuming up the reader.<br/>
5975
There are no results/options here, it will simply panic if you attempt to read bytes that don't exist. Thus, using this reader means the expected input has a very predictable content.
6076
```rust
61-
use hyper_byte::reader::FastReader;
77+
use hyper_byte::reader::FastByteReader;
78+
use hyper_byte::readers::traits::BigEndianByteReader;
6279

6380
#[derive(PartialOrd, PartialEq, Debug)]
6481
struct MyTestStruct {
@@ -77,6 +94,7 @@ struct MyTestStruct {
7794
float16: f16, // if `half` is enabled
7895
float32: f32,
7996
float64: f64,
97+
raw_data: vec![82u8, 38u8, 10u8, 2u8, 31u8, 165u8],
8098
}
8199

82100
fn main() {
@@ -100,13 +118,15 @@ fn main() {
100118
float16: fast_reader.read_f16_be(),
101119
float32: fast_reader.read_f32_be(),
102120
float64: fast_reader.read_f64_be(),
121+
raw_data: fast_reader.read_n_be(6)
103122
};
104123
}
105124
```
106-
### Basic Reader
107-
If you want a more "hands on" reader implementation with a bit more protection and nicer panic messages, this is the reader for you. It is slower than the fast reader (it has 13 instructions vs 9 instructions for the fast reader) because it has an index and additional bound check.
125+
### Fast Byte Writer
126+
If you want the fast writer with no particular endian-ness, without going into completely unsafe territory, then you should use the FastByteWriter.<br/>
108127
```rust
109-
use hyper_byte::reader;
128+
use hyper_byte::writer::FastByteWriter;
129+
use hyper_byte::writers::traits::*;
110130

111131
#[derive(PartialOrd, PartialEq, Debug)]
112132
struct MyTestStruct {
@@ -125,29 +145,84 @@ struct MyTestStruct {
125145
float16: f16, // if `half` is enabled
126146
float32: f32,
127147
float64: f64,
148+
raw_data: vec![82u8, 38u8, 10u8, 2u8, 31u8, 165u8],
128149
}
129150

130-
fn main() {
131-
let some_byte_stream : Vec<u8> = Vec::new();
132-
let mut index = 0;
151+
impl MyTestStruct {
152+
pub fn to_be_bytes(&self) -> Vec<u8> {
153+
let mut writer = FastByteWriter::new();
154+
writer.write_u8_be(self.unsigned8);
155+
writer.write_u16_be(self.unsigned16);
156+
writer.write_u32_be(self.unsigned32);
157+
writer.write_u64_be(self.unsigned64);
158+
writer.write_u128_be(self.unsigned128);
159+
writer.write_usize_be(self.unsigned_size);
133160

134-
let parsed_struct = MyTestStruct {
135-
unsigned8: reader::read_u8_le(&vector_data, &mut index),
136-
unsigned16: reader::read_u16_le(&vector_data, &mut index),
137-
unsigned32: reader::read_u32_le(&vector_data, &mut index),
138-
unsigned64: reader::read_u64_le(&vector_data, &mut index),
139-
unsigned128: reader::read_u128_le(&vector_data, &mut index),
140-
unsigned_size: reader::read_usize_le(&vector_data, &mut index),
141-
signed8: reader::read_i8_le(&vector_data, &mut index),
142-
signed16: reader::read_i16_le(&vector_data, &mut index), // if `half` is enabled
143-
signed32: reader::read_i32_le(&vector_data, &mut index),
144-
signed64: reader::read_i64_le(&vector_data, &mut index),
145-
signed128: reader::read_i128_le(&vector_data, &mut index),
146-
signed_size: reader::read_isize_le(&vector_data, &mut index),
147-
float16: reader_read_f16_le(&vector_data, &mut index),
148-
float32: reader::read_f32_le(&vector_data, &mut index),
149-
float64: reader::read_f64_le(&vector_data, &mut index),
150-
};
161+
writer.write_i8_be(self.signed8);
162+
writer.write_i16_be(self.signed16);
163+
writer.write_i32_be(self.signed32);
164+
writer.write_i64_be(self.signed64);
165+
writer.write_i128_be(self.signed128);
166+
writer.write_isize_be(self.signed_size);
167+
168+
writer.write_f16_be(self.float16);
169+
writer.write_f32_be(self.float32);
170+
writer.write_f64_be(self.float64);
171+
172+
writer.write_bytes_be(&self.raw_data);
173+
174+
writer.to_vec()
175+
}
176+
177+
pub fn to_le_bytes(&self) -> Vec<u8> {
178+
let mut writer = FastByteWriter::new();
179+
writer.write_u8_le(self.unsigned8);
180+
writer.write_u16_le(self.unsigned16);
181+
writer.write_u32_le(self.unsigned32);
182+
writer.write_u64_le(self.unsigned64);
183+
writer.write_u128_le(self.unsigned128);
184+
writer.write_usize_le(self.unsigned_size);
185+
186+
writer.write_i8_le(self.signed8);
187+
writer.write_i16_le(self.signed16);
188+
writer.write_i32_le(self.signed32);
189+
writer.write_i64_le(self.signed64);
190+
writer.write_i128_le(self.signed128);
191+
writer.write_isize_le(self.signed_size);
192+
193+
writer.write_f16_le(self.float16);
194+
writer.write_f32_le(self.float32);
195+
writer.write_f64_le(self.float64);
196+
197+
writer.write_bytes_le(&self.raw_data);
198+
199+
writer.to_vec()
200+
}
201+
202+
pub fn to_ne_bytes(&self) -> Vec<u8> {
203+
let mut writer = FastByteWriter::new();
204+
writer.write_u8_ne(self.unsigned8);
205+
writer.write_u16_ne(self.unsigned16);
206+
writer.write_u32_ne(self.unsigned32);
207+
writer.write_u64_ne(self.unsigned64);
208+
writer.write_u128_ne(self.unsigned128);
209+
writer.write_usize_ne(self.unsigned_size);
210+
211+
writer.write_i8_ne(self.signed8);
212+
writer.write_i16_ne(self.signed16);
213+
writer.write_i32_ne(self.signed32);
214+
writer.write_i64_ne(self.signed64);
215+
writer.write_i128_ne(self.signed128);
216+
writer.write_isize_ne(self.signed_size);
217+
218+
writer.write_f16_ne(self.float16);
219+
writer.write_f32_ne(self.float32);
220+
writer.write_f64_ne(self.float64);
221+
222+
writer.write_bytes_ne(&self.raw_data);
223+
224+
writer.to_vec()
225+
}
151226
}
152227
```
153228
### Unsafe Functions

0 commit comments

Comments
 (0)