{"id":50785094,"url":"https://github.com/malt03/bitcram","last_synced_at":"2026-06-12T07:04:43.233Z","repository":{"id":354189590,"uuid":"1221751385","full_name":"malt03/bitcram","owner":"malt03","description":"A small, derive-based bit packing library for Rust. Pack structured data into compact integer buffers with sub-byte field granularity.","archived":false,"fork":false,"pushed_at":"2026-04-29T02:32:37.000Z","size":91,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-30T20:05:12.733Z","etag":null,"topics":["bit-packing","bitfield","compact","derive","encoding"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/malt03.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-26T16:28:12.000Z","updated_at":"2026-04-29T02:32:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/malt03/bitcram","commit_stats":null,"previous_names":["malt03/bitpacker","malt03/bitcram"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/malt03/bitcram","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malt03%2Fbitcram","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malt03%2Fbitcram/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malt03%2Fbitcram/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malt03%2Fbitcram/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/malt03","download_url":"https://codeload.github.com/malt03/bitcram/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malt03%2Fbitcram/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34232825,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-12T02:00:06.859Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bit-packing","bitfield","compact","derive","encoding"],"created_at":"2026-06-12T07:04:42.311Z","updated_at":"2026-06-12T07:04:43.220Z","avatar_url":"https://github.com/malt03.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bitcram\n\n[![Crates.io Version](https://img.shields.io/crates/v/bitcram)](https://crates.io/crates/bitcram)\n[![docs.rs](https://img.shields.io/docsrs/bitcram)](https://docs.rs/bitcram)\n[![Test](https://github.com/malt03/bitcram/actions/workflows/test.yml/badge.svg?event=release)](https://github.com/malt03/bitcram/actions/workflows/test.yml)\n\nA small, derive-based bit packing library for Rust. Pack structured data into compact integer buffers with sub-byte field granularity.\n\n## Features\n\n- `#[packable(B)]` attribute macro for automatic `Packable` implementations\n- Buffer types: `u8`, `u16`, `u32`, `u64`, `u128`\n- Supports structs (unit, tuple, named) and enums with mixed variant kinds\n- Generics with type parameters (bounds auto-applied)\n- Debug-mode safety checks with zero release-build overhead\n- Performance comparable to established bit-packing crates\n\n## Quick Start\n\nEncode a mini-chess move (5×6 board, 6 piece types, with promotion) into 16 bits:\n\n```rust\nuse bitcram::{Packable, packable};\n\n/// A coordinate on a 5×6 board.\n///\n/// 30 distinct (x, y) pairs fit in 5 bits. A naive \"3 bits for x + 3 bits for y\"\n/// layout would use 6 bits — implementing `Packable` directly lets us collapse\n/// the two fields into a single 5-bit index and reclaim that bit.\n#[derive(Debug, PartialEq, Eq)]\nstruct Coord {\n    x: u8, // 0..5\n    y: u8, // 0..6\n}\n\nimpl Packable\u003cu16\u003e for Coord {\n    const SIZE: u32 = 5;\n    fn pack(\u0026self) -\u003e u16 {\n        (self.y * 5 + self.x) as u16\n    }\n    fn unpack(buffer: u16) -\u003e Self {\n        let i = buffer as u8;\n        Self { x: i % 5, y: i / 5 }\n    }\n}\n\n#[packable(u16)]\n#[derive(Debug, PartialEq, Eq)]\nenum Piece {\n    King, Queen, Rook, Bishop, Knight, Pawn,\n} // 6 variants → 3 bits\n\n#[packable(u16)]\n#[derive(Debug, PartialEq, Eq)]\nenum Promotion {\n    None, Queen, Rook, Bishop, Knight,\n} // 5 variants → 3 bits\n\n#[packable(u16)]\n#[derive(Debug, PartialEq, Eq)]\nstruct Move {\n    from: Coord,          // 5 bits\n    to: Coord,            // 5 bits\n    piece: Piece,         // 3 bits\n    promotion: Promotion, // 3 bits\n} // 16 bits total — fits exactly in u16\n\nlet m = Move {\n    from: Coord { x: 0, y: 1 },\n    to: Coord { x: 0, y: 3 },\n    piece: Piece::Pawn,\n    promotion: Promotion::None,\n};\nlet packed: u16 = m.pack(); // 2 bytes\nassert_eq!(Move::unpack(packed), m);\n```\n\nEach move serializes to 2 bytes. A naive byte-aligned encoding of the same data would take 4 bytes or more.\n\n## Supported types\n\n`#[packable(B)]` can derive `Packable\u003cB\u003e` for:\n\n- **Unit structs** (`struct Foo;`) — `SIZE = 0`\n- **Tuple structs** (`struct Foo(X, Y);`)\n- **Named structs** (`struct Foo { x: X, y: Y }`)\n- **Enums** with any combination of variant kinds:\n  - Unit variants (`Bar`)\n  - Empty tuple variants (`Bar()`)\n  - Tuple variants (`Bar(X, Y)`)\n  - Named variants (`Bar { x: X, y: Y }`)\n- **Generic types** — `Packable\u003cB\u003e` bounds are auto-applied to type parameters\n\nMultiple buffer types can be specified to generate one impl per type:\n\n```ignore\n#[packable(u16, u32, u64)]\nstruct Foo { #[bits(5)] x: u8, #[bits(5)] y: u8 }\n```\n\nBuilt-in `Packable` implementations are provided for:\n\n| Type | `SIZE` |\n|---|---|\n| `bool` | `1` |\n| `Option\u003cT\u003e` | `1 + T::SIZE` |\n| `(T1, T2, ..., Tn)` (up to 12-tuples) | `T1::SIZE + T2::SIZE + ... + Tn::SIZE` |\n| `[T; N]` | `N * T::SIZE` |\n\nFor primitive types or custom encodings (like `Coord` above), implement `Packable\u003cB\u003e` manually — or annotate fields with `#[bits(N)]` to specify the bit width directly:\n\n```rust\nuse bitcram::{Packable, packable};\n\n#[packable(u16)]\n#[derive(Debug, PartialEq, Eq)]\nstruct Foo {\n    #[bits(5)] x: u8,\n    #[bits(6)] y: u8,\n    #[bits(5)] z: u8,\n}\n\nlet foo = Foo { x: 31, y: 63, z: 31 };\nassert_eq!(Foo::unpack(foo.pack()), foo);\n```\n\nWithout `#[bits]`, the field type must implement `Packable\u003cB\u003e` — there is no automatic width inference from primitive types. This makes the requirement explicit at the cost of a small annotation. The field type must be cast-compatible with the buffer type in both directions; all primitive unsigned integers (`u8`, `u16`, `u32`, `u64`, `u128`) qualify.\n\nThe field type must be cast-compatible with the buffer type in both directions (`*field as B` and `B as FieldType`). All primitive unsigned integers (`u8`, `u16`, `u32`, `u64`, `u128`) qualify.\n\n## Conventions\n\nThe library trades runtime checks for performance, with a few rules the caller is expected to follow:\n\n- **`Packable::pack()` must return a value that fits in `SIZE` bits.** Debug builds verify this with `assert!`; release builds silently mask oversized values to prevent buffer corruption.\n- **Total packed size must not exceed `B::BITS`.** Debug builds track cumulative bits; release builds rely on this convention.\n- **A single `raw_pack`/`raw_unpack` call must use `size \u003c B::BITS`.** Compose multiple smaller calls if you need to fill the buffer exactly. (Shifting by the full type width is undefined behavior in Rust.)\n- **Empty enums are silently skipped** by the derive macro. This allows incremental development without compile errors on placeholder types.\n- **The `Unpacker` trusts its input.** Decoding malformed data may produce garbage but will not panic on its own.\n\n## Benchmarks\n\nCompared against similar crates packing 4 fields (4-bit + 4-bit + 8-bit + 16-bit = 32 bits total):\n\n| Crate | Pack | Unpack | Round-trip | Output size |\n|---|---:|---:|---:|---:|\n| **bitcram** | 934 ps | 1.61 ns | 2.00 ns | 4 bytes |\n| modular-bitfield | 967 ps | 1.54 ns | 1.99 ns | 4 bytes |\n| bitfield-struct | 970 ps | 1.55 ns | 2.00 ns | 4 bytes |\n| bincode 2.x | 3.82 ns | 4.33 ns | 8.09 ns | ~6 bytes |\n| postcard | 6.32 ns | 2.98 ns | 9.16 ns | ~6 bytes |\n\nThe three bit-packers are essentially equivalent. Byte-level serializers are ~4× slower on round-trip and produce ~50% larger output for this kind of small, fixed-shape data.\n\nNumbers were measured on a single machine and will vary by hardware; reproduce locally with:\n\n```sh\ncargo bench -p bitcram_bench\n```\n\n## Workspace structure\n\n- `bitcram/` — runtime crate (`Packable`, `Buffer`, `Packer`, `Unpacker`)\n- `bitcram_derive/` — proc-macro crate (`#[packable]`)\n- `bitcram_bench/` — comparison benchmarks (not published)\n\n## Requirements\n\n- Rust 1.85+ (edition 2024)\n\n## License\n\nLicensed under either of [MIT](LICENSE-MIT) or [Apache License 2.0](LICENSE-APACHE) at your option.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalt03%2Fbitcram","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmalt03%2Fbitcram","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalt03%2Fbitcram/lists"}