bilge_impl/lib.rs
1use manyhow::manyhow;
2use proc_macro2::TokenStream;
3
4mod bitsize;
5mod bitsize_internal;
6mod builder_bits;
7mod debug_bits;
8mod default_bits;
9mod fmt_bits;
10mod from_bits;
11#[cfg(feature = "schemars")]
12#[cfg_attr(docsrs, doc(cfg(feature = "schemars")))]
13mod schemars_bits;
14#[cfg(feature = "serde")]
15#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
16mod serde_bits;
17mod try_from_bits;
18
19mod shared;
20
21/// Defines the bitsize of a struct or an enum.
22///
23/// e.g. `#[bitsize(4)]` represents the item as a u4, which is UInt<u8, 4> underneath.
24/// The size of structs is currently limited to 128 bits.
25/// The size of enums is limited to 64 bits.
26/// Please open an issue if you have a usecase for bigger bitfields.
27///
28/// After the size, structs may take extra options:
29/// - `hide_value`: place the generated struct in a private module so the raw
30/// `value` field cannot be read or written. To write the whole value, use `From`/`TryFrom` instead, which is more type-safe.
31/// Relative visibility (`pub(super)`, `pub(self)`, inherited) is shifted one `super`
32/// so it works like you wrote it.
33/// - `new = <vis>`: visibility of `new` (private by default, like other Rust items).
34/// Examples: `new = pub`, `new = pub(crate)`.
35///
36/// Struct fields may use `#[at(n)]` or `#[at(n..=m)]` to place a field at backing-integer
37/// bit `n` (0 = LSB). Width comes from the field type; a range is checked against that width.
38/// Fields without `#[at]` fill sequentially from the end of the previous
39/// field. Skipped bits are implicit padding. Overlap or reordering is a compile error.
40///
41/// Enums may use `#[discriminant_at(n)]` or `#[discriminant_at(n..=m)]` when the tag sits in
42/// the same integer, and `#[discriminant(TagType)]` when the tag is a separate value.
43/// Variants look like `Variant(Payload) = tag`. Use `TryFromBits` when not every tag is used.
44///
45/// ```ignore
46/// #[bitsize(8, hide_value, new = pub(crate))]
47/// struct Register { ... }
48/// ```
49#[manyhow]
50#[proc_macro_attribute]
51pub fn bitsize(args: TokenStream, item: TokenStream) -> manyhow::Result {
52 bitsize::bitsize(args, item)
53}
54
55/// This is internally used, not to be used by anything besides `bitsize`.
56/// No guarantees are given.
57#[doc(hidden)]
58#[manyhow]
59#[proc_macro_attribute]
60pub fn bitsize_internal(args: TokenStream, item: TokenStream) -> manyhow::Result {
61 bitsize_internal::bitsize_internal(args, item)
62}
63
64/// Generate a compile-time builder (`typed-builder` style: each field exactly once).
65///
66/// Required fields have no `#[default]` and must be set before `build`.
67/// `#[default(expr)]` makes a field optional (same as in `DefaultBits`).
68/// `reserved` / `padding` are omitted, same as in `new`.
69#[manyhow]
70#[proc_macro_derive(BuilderBits, attributes(bitsize_internal, at, default))]
71pub fn derive_builder_bits(item: TokenStream) -> manyhow::Result {
72 builder_bits::builder_bits(item)
73}
74
75/// Generate an `impl TryFrom<uN>` for unfilled bitfields.
76///
77/// This should be used when your enum or enums nested in
78/// a struct don't fill their given `bitsize`.
79#[manyhow]
80#[proc_macro_derive(TryFromBits, attributes(bitsize_internal, fallback, at, discriminant_at, discriminant))]
81pub fn derive_try_from_bits(item: TokenStream) -> manyhow::Result {
82 try_from_bits::try_from_bits(item)
83}
84
85/// Generate an `impl From<uN>` for filled bitfields.
86///
87/// This should be used when your enum or enums nested in
88/// a struct fill their given `bitsize` or if you're not
89/// using enums.
90#[manyhow]
91#[proc_macro_derive(FromBits, attributes(bitsize_internal, fallback, at, discriminant_at, discriminant))]
92pub fn derive_from_bits(item: TokenStream) -> manyhow::Result {
93 from_bits::from_bits(item)
94}
95
96/// Generate an `impl core::fmt::Debug` for bitfield structs.
97///
98/// Please use normal #[derive(Debug)] for enums.
99#[manyhow]
100#[proc_macro_derive(DebugBits, attributes(bitsize_internal, at))]
101pub fn debug_bits(item: TokenStream) -> manyhow::Result {
102 debug_bits::debug_bits(item)
103}
104
105/// Generate an `impl core::fmt::Binary` for bitfields.
106#[manyhow]
107#[proc_macro_derive(BinaryBits, attributes(bitsize_internal, fallback, at, discriminant_at, discriminant))]
108pub fn derive_binary_bits(item: TokenStream) -> manyhow::Result {
109 fmt_bits::binary(item)
110}
111
112/// Generate an `impl core::default::Default` for bitfield structs.
113///
114/// Each field uses `T::default()` unless it has `#[default(expr)]`, same as in `BuilderBits`.
115#[manyhow]
116#[proc_macro_derive(DefaultBits, attributes(bitsize_internal, at, default))]
117pub fn derive_default_bits(item: TokenStream) -> manyhow::Result {
118 default_bits::default_bits(item)
119}
120
121/// Generate an `impl schemars::JsonSchema` for bitfield structs.
122///
123/// Please use normal #[derive(JsonSchema)] for enums.
124#[cfg(feature = "schemars")]
125#[manyhow]
126#[proc_macro_derive(JsonSchemaBits, attributes(bitsize_internal, at))]
127pub fn json_schema_bits(item: TokenStream) -> manyhow::Result {
128 schemars_bits::json_schema_bits(item)
129}
130
131/// Generate an `impl serde::Serialize` for bitfield structs.
132///
133/// Please use normal #[derive(Serialize)] for enums.
134#[cfg(feature = "serde")]
135#[manyhow]
136#[proc_macro_derive(SerializeBits, attributes(bitsize_internal, at, default))]
137pub fn serialize_bits(item: TokenStream) -> manyhow::Result {
138 serde_bits::serialize_bits(item)
139}
140
141/// Generate an `impl serde::Deserialize` for bitfield structs.
142///
143/// `#[default(expr)]` is optional and works like `#[serde(default = "...")]`.
144/// Please use normal #[derive(Deserialize)] for enums.
145#[cfg(feature = "serde")]
146#[manyhow]
147#[proc_macro_derive(DeserializeBits, attributes(bitsize_internal, at, default))]
148pub fn deserialize_bits(item: TokenStream) -> manyhow::Result {
149 serde_bits::deserialize_bits(item)
150}