Skip to content

Commit 9a2d74e

Browse files
committed
Improvements
- Added reader.rs - Added isize primitive type - Added tests for additions - Fixed up the README.md
1 parent 73decc3 commit 9a2d74e

File tree

3 files changed

+2076
-55
lines changed

3 files changed

+2076
-55
lines changed

README.md

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Hyper Byte
2-
An unsafe byte slice transmuter for Rust's numeric types, for both endianness.<br/>
2+
An unsafe byte slice transmuter for Rust's numeric types, for all three endianness'.<br/>
33
**Supported types:**
44
* `u8`
55
* `u16`
@@ -15,5 +15,100 @@ An unsafe byte slice transmuter for Rust's numeric types, for both endianness.<b
1515
* `f32`
1616
* `f64`
1717
* `usize`
18+
* `isize`
19+
20+
## Why?
21+
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.
22+
### For example
23+
```rust
24+
// Has bound checks for every indexing operation
25+
#[no_mangle]
26+
#[inline(always)]
27+
pub fn read_f64_ne(bytes: &[u8]) -> f64 {
28+
f64::from_ne_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]])
29+
}
30+
31+
// Has more branching and operations involved, and ultimately should be slower
32+
#[no_mangle]
33+
#[inline(always)]
34+
pub fn read_f64_ne(bytes: &[u8]) -> f64 {
35+
f64::from_ne_bytes(bytes.try_into().expect("Error!"))
36+
}
37+
38+
// My version of this, taking what try_into does and removing the branching,
39+
// thus making it unsafe, but can easily be made safe
40+
#[no_mangle]
41+
#[inline(always)]
42+
pub unsafe fn read_f64_ne(bytes: &[u8]) -> f64 {
43+
unsafe { f64::from_ne_bytes(*(bytes.as_ptr() as *const [u8; 8])) }
44+
}
45+
```
46+
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).
47+
However, instructions don't lie, and I did manage to create a benchmark, present around line 2256 in [lib.rs](src/lib.rs#L2256-L2284).<br/>
48+
In [Compiler Explorer](https://rust.godbolt.org/z/PfhWzGnnG), you can also see for yourself the instructions for each function.
49+
50+
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.
51+
> [!NOTE]
52+
> 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.
1853
1954
## Usage
55+
So how do you use this? Either you use the safe, simple reader implemented, or you use the unsafe functions.
56+
### Safe Reader
57+
```rust
58+
use hyper_byte::reader;
59+
60+
#[derive(PartialOrd, PartialEq, Debug)]
61+
struct MyTestStruct {
62+
unsigned8: u8,
63+
unsigned16: u16,
64+
unsigned32: u32,
65+
unsigned64: u64,
66+
unsigned128: u128,
67+
unsigned_size: usize,
68+
signed8: i8,
69+
signed16: i16,
70+
signed32: i32,
71+
signed64: i64,
72+
signed128: i128,
73+
signed_size: isize,
74+
float16: f16, // if `half` is enabled
75+
float32: f32,
76+
float64: f64,
77+
}
78+
79+
fn main() {
80+
let some_byte_stream : Vec<u8> = Vec::new();
81+
let mut index = 0;
82+
83+
let parsed_struct = MyTestStruct {
84+
unsigned8: reader::read_u8_le(&vector_data, &mut index),
85+
unsigned16: reader::read_u16_le(&vector_data, &mut index),
86+
unsigned32: reader::read_u32_le(&vector_data, &mut index),
87+
unsigned64: reader::read_u64_le(&vector_data, &mut index),
88+
unsigned128: reader::read_u128_le(&vector_data, &mut index),
89+
unsigned_size: reader::read_usize_le(&vector_data, &mut index),
90+
signed8: reader::read_i8_le(&vector_data, &mut index),
91+
signed16: reader::read_i16_le(&vector_data, &mut index), // if `half` is enabled
92+
signed32: reader::read_i32_le(&vector_data, &mut index),
93+
signed64: reader::read_i64_le(&vector_data, &mut index),
94+
signed128: reader::read_i128_le(&vector_data, &mut index),
95+
signed_size: reader::read_isize_le(&vector_data, &mut index),
96+
float16: reader_read_f16_le(&vector_data, &mut index),
97+
float32: reader::read_f32_le(&vector_data, &mut index),
98+
float64: reader::read_f64_le(&vector_data, &mut index),
99+
};
100+
}
101+
```
102+
### Unsafe Functions
103+
```rust
104+
pub fn read_u16_be(array : &[u8], index: &mut usize) -> u16 {
105+
let current_index = *index;
106+
let new_index = current_index + size_of::<u16>();
107+
let ranged_array = &array[current_index..new_index];
108+
*index = new_index;
109+
// SAFETY: Ranged array will not allow this function to proceed to unsafe code if there aren't enough bytes to read
110+
unsafe {
111+
hyper_byte::read_u16_be(ranged_array)
112+
}
113+
}
114+
```

0 commit comments

Comments
 (0)