Skip to content

Commit d3f0a5f

Browse files
Update lib.rs
1 parent f263dba commit d3f0a5f

File tree

1 file changed

+35
-12
lines changed

1 file changed

+35
-12
lines changed

macros/src/lib.rs

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,34 @@ pub fn bitmap(input: TokenStream) -> TokenStream {
129129
}
130130
}
131131

132+
/// Generates a packed bitmap newtype struct with field-level bit access.
133+
///
134+
/// This attribute macro works exactly like the `bitmap!` macro but uses attribute syntax.
135+
///
136+
/// ### Usage Example
137+
/// ```
138+
/// use bitmap::bitmap_attr;
139+
///
140+
/// #[bitmap_attr]
141+
/// struct Player {
142+
/// imposter: u1,
143+
/// finished_tasks: u3,
144+
/// kills: u3,
145+
/// }
146+
///
147+
/// let mut player = Player(0);
148+
/// assert_eq!(std::mem::size_of::<Player>(), 1);
149+
///
150+
/// player.set_imposter(1);
151+
/// player.set_finished_tasks(5);
152+
/// player.set_kills(3);
153+
///
154+
/// assert_eq!(player.imposter(), 1);
155+
/// assert_eq!(player.finished_tasks(), 5);
156+
/// assert_eq!(player.kills(), 3);
157+
/// assert_eq!(*player, 0b01101011);
158+
/// ```
159+
132160
#[proc_macro_attribute]
133161
pub fn bitmap_attr(_args: TokenStream, input: TokenStream) -> TokenStream {
134162
let input = parse_macro_input!(input as DeriveInput);
@@ -142,7 +170,7 @@ pub fn bitmap_attr(_args: TokenStream, input: TokenStream) -> TokenStream {
142170
}
143171

144172
fn convert_derive_to_bitmap_input(input: DeriveInput) -> parser::BitmapInput {
145-
let name = input.ident;
173+
let name = input.ident;
146174

147175
let syn::Data::Struct(data_struct) = input.data else {
148176
panic!("#[bitmap_attr] can only be used on structs");
@@ -156,17 +184,12 @@ fn convert_derive_to_bitmap_input(input: DeriveInput) -> parser::BitmapInput {
156184
let field_name = field.ident.expect("Field must have a name");
157185
let field_type = field.ty;
158186

159-
let type_str = field_type.to_token_stream().to_string();
160-
161-
if !type_str.starts_with("u") {
162-
panic!("Field type must be unsigned integer like u1, u2, etc.");
163-
}
187+
let syn::Type::Path(type_path) = field_type else {
188+
panic!("Field type must be a path like u1, u7, etc.");
189+
};
164190

165-
let size: u8 = type_str[1..].parse().expect("Invalid bit width");
166-
167-
if size == 0 || size > 128 {
168-
panic!("Invalid size for {}, expected u{{1..128}}", type_str);
169-
}
191+
let segment = type_path.path.segments.last().expect("Type path must have a segment");
192+
let size = parser::parse_bit_width(&segment.ident).expect("Invalid bit width");
170193

171194
parser::FieldDef {
172195
name: field_name,
@@ -175,7 +198,7 @@ fn convert_derive_to_bitmap_input(input: DeriveInput) -> parser::BitmapInput {
175198
}).collect();
176199

177200
parser::BitmapInput {
178-
name,
201+
name,
179202
fields,
180203
}
181204
}

0 commit comments

Comments
 (0)