| Crates.io | i24 |
| lib.rs | i24 |
| version | 2.2.7 |
| created_at | 2024-07-31 10:40:50.331165+00 |
| updated_at | 2025-12-16 16:35:00.898866+00 |
| description | A Rust library for working with 24-bit integers. |
| homepage | |
| repository | https://github.com/jmg049/i24 |
| max_upload_size | |
| id | 1320813 |
| size | 1,413,241 |
The i24 crate provides specialized integer types for Rust: i24 (24-bit signed) and u24 (24-bit unsigned). These types fill precision gaps in Rust's integer types and are particularly useful in audio processing, embedded systems, network protocols, and other scenarios where specific bit-width precision is required.
i24!() and u24!() for checked constructionDebug, Display, PartialEq, Eq, PartialOrd, Ord, HashThis crate came about as a part of the Wavers project, which is a Wav file reader and writer for Rust.
All integer types have Python bindings available via the pyo3 feature.
Add this to your`` Cargo.toml`:
[dependencies]
i24 = "2.2.4"
or just run
cargo add i24
to get the latest version.
use i24::{i24, u24};
// Using macros for compile-time checked construction
let signed_24 = i24!(1000);
let unsigned_24 = u24!(2000);
// Arithmetic operations
let sum_24 = signed_24 + i24!(500);
assert_eq!(sum_24.to_i32(), 1500);
// Conversions
let as_i32: i32 = signed_24.into();
let as_u32: u32 = unsigned_24.into();
The i24!() and u24!() macros allow you to create values at compile time, ensuring they're within the valid range.
For working with binary data, all types support reading/writing from byte arrays:
use i24::{i24, u24};
// Reading from bytes (little-endian, big-endian, native)
let bytes_le = [0x00, 0x01, 0x02]; // 3-byte representation
let value = i24::from_le_bytes(bytes_le);
// Writing to bytes
let bytes: [u8; 3] = value.to_be_bytes();
// Bulk operations for slices
let raw_data: &[u8] = &[0x00, 0x01, 0x02, 0x00, 0x01, 0xFF];
let values: Vec<i24> = i24::read_i24s_be(raw_data).expect("valid buffer");
let encoded: Vec<u8> = i24::write_i24s_be(&values);
For binary protocols and serialization, use the PackedStruct trait:
use i24::{i24, packed::PackedStruct};
#[derive(Debug, Clone, PartialEq)]
struct WireFormat {
header: u32,
samples: [i24; 5],
}
impl PackedStruct for WireFormat {
const PACKED_SIZE: usize = 4 + 5 * 3; // u32 + 5 * i24 = 19 bytes
fn from_packed_bytes(bytes: &[u8]) -> Option<Self> {
// Implementation for deserializing from bytes
// ...
}
fn to_packed_bytes(&self) -> Vec<u8> {
// Implementation for serializing to bytes
// ...
}
}
All integer types strive to behave similarly to Rust's built-in integer types, with some important considerations:
All types align with bytemuck safety requirements (NoUninit, Zeroable, AnyBitPattern), ensuring safe byte-to-value conversions. The bulk I/O operations use bytemuck::cast_slice internally for efficient, safe conversions.
Serialize and Deserialize traits for all integer typesPackedStruct functionalityContributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under MIT - see the LICENSE file for details.
The crate was tested using the code found in the i24_benches directory of the repo. Unsurprisingly, the performance of both types matches the performance of the underlying 32-bit type.