ring_buffer_macro/
lib.rs

1//! A procedural macro for creating compile-time ring buffers (circular buffers).
2//!
3//! ## Usage
4//!
5//! ```ignore
6//! use ring_buffer_macro::ring_buffer;
7//!
8//! #[ring_buffer(5)]
9//! struct IntBuffer {
10//!     data: Vec<i32>,
11//! }
12//!
13//! let mut buf = IntBuffer::new();
14//! buf.enqueue(1).unwrap();
15//! buf.enqueue(2).unwrap();
16//! assert_eq!(buf.dequeue(), Some(1));
17//! ```
18//!
19//! ## Generated Methods
20//!
21//! - `new()` - Create empty buffer
22//! - `enqueue(item: T) -> Result<(), T>` - Add item (returns `Err(item)` if full)
23//! - `dequeue() -> Option<T>` - Remove oldest item (requires `T: Clone`)
24//! - `is_full()`, `is_empty()`, `len()`, `capacity()`, `clear()`
25//!
26//! ## Requirements
27//!
28//! - Struct must have a field named `data` of type `Vec<T>`
29//! - Element type `T` must implement `Clone`
30
31mod error;
32mod generator;
33mod parser;
34
35use proc_macro::TokenStream;
36use quote::quote;
37use syn::{parse_macro_input, DeriveInput};
38
39use error::Result;
40use generator::{add_fields, generate_impl};
41use parser::{find_data_field, RingBufferArgs};
42
43/// Transforms a struct with a `Vec<T>` field into a fixed-size FIFO ring buffer.
44///
45/// # Example
46///
47/// ```ignore
48/// #[ring_buffer(10)]
49/// struct MyBuffer {
50///     data: Vec<String>,
51/// }
52/// ```
53///
54/// Adds fields: `capacity`, `head`, `tail`, `size`
55///
56/// Generates methods: `new()`, `enqueue()`, `dequeue()`, `is_full()`, `is_empty()`,
57/// `len()`, `capacity()`, `clear()`
58#[proc_macro_attribute]
59pub fn ring_buffer(args: TokenStream, input: TokenStream) -> TokenStream {
60    let args = parse_macro_input!(args as RingBufferArgs);
61    let mut input = parse_macro_input!(input as DeriveInput);
62
63    match expand_ring_buffer(args, &mut input) {
64        Ok(tokens) => tokens,
65        Err(e) => e.to_compile_error().into(),
66    }
67}
68
69fn expand_ring_buffer(args: RingBufferArgs, input: &mut DeriveInput) -> Result<TokenStream> {
70    let capacity = args.capacity;
71
72    // Find and validate the data field
73    let element_type = find_data_field(input)?;
74
75    // Add the additional fields
76    add_fields(input)?;
77
78    // Generate the implementation
79    let implementation = generate_impl(input, &element_type, capacity);
80
81    let expanded = quote! {
82        #input
83
84        #implementation
85    };
86
87    Ok(expanded.into())
88}