ring_buffer_macro/lib.rs
1//! A procedural macro for creating compile-time ring buffers (circular buffers).
2//!
3//! ## Usage
4//!
5//! ### Standard Mode (default)
6//!
7//! ```ignore
8//! use ring_buffer_macro::ring_buffer;
9//!
10//! #[ring_buffer(5)]
11//! struct IntBuffer(i32);
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//! ### SPSC Mode (lock-free, thread-safe)
20//!
21//! ```ignore
22//! use ring_buffer_macro::ring_buffer;
23//! use std::thread;
24//!
25//! #[ring_buffer(capacity = 1024, mode = "spsc")]
26//! struct SpscBuffer(i32);
27//!
28//! let buffer = SpscBuffer::new();
29//! let (producer, consumer) = buffer.split();
30//!
31//! // Producer and consumer can be sent to different threads
32//! ```
33//!
34//! ### MPSC Mode (multi-producer, single-consumer)
35//!
36//! ```ignore
37//! use ring_buffer_macro::ring_buffer;
38//!
39//! #[ring_buffer(capacity = 1024, mode = "mpsc")]
40//! struct MpscBuffer(i32);
41//!
42//! let buffer = MpscBuffer::new();
43//! let producer1 = buffer.producer();
44//! let producer2 = buffer.producer(); // Can clone for more producers
45//! let consumer = buffer.consumer();
46//! ```
47//!
48//! ### Blocking Mode
49//!
50//! ```ignore
51//! #[ring_buffer(capacity = 1024, mode = "mpsc", blocking = true)]
52//! struct BlockingQueue(Message);
53//!
54//! // Use enqueue_blocking() and dequeue_blocking() for blocking operations
55//! ```
56//!
57//! ## Generated Methods
58//!
59//! ### Standard Mode
60//! - `new()` - Create empty buffer
61//! - `enqueue(item: T) -> Result<(), T>` - Add item (returns `Err(item)` if full)
62//! - `dequeue() -> Option<T>` - Remove oldest item (requires `T: Clone`)
63//! - `is_full()`, `is_empty()`, `len()`, `capacity()`, `clear()`
64//!
65//! ### SPSC Mode
66//! - `new()` - Create empty buffer
67//! - `split()` - Get producer and consumer handles
68//! - `is_full()`, `is_empty()`, `len()`, `capacity()`
69//! - Producer: `try_enqueue(item: T) -> Result<(), T>`
70//! - Consumer: `try_dequeue() -> Option<T>`
71//!
72//! ### MPSC Mode
73//! - `new()` - Create empty buffer
74//! - `producer()` - Get clonable producer handle
75//! - `consumer()` - Get consumer handle
76//! - Producer: `try_enqueue(item: T) -> Result<(), T>`, `enqueue_blocking(item: T)` (if blocking)
77//! - Consumer: `try_dequeue() -> Option<T>`, `dequeue_blocking() -> T` (if blocking)
78//!
79//! ## Requirements
80//!
81//! - Tuple struct with one element type, e.g., `struct Buffer(i32);`
82//! - Standard mode: Element type `T` must implement `Clone`
83//! - SPSC/MPSC modes: Element type `T` must implement `Send`
84
85mod error;
86mod generator;
87mod parser;
88
89use proc_macro::TokenStream;
90use quote::quote;
91use syn::{parse_macro_input, DeriveInput};
92
93use error::Result;
94use generator::{
95 add_fields, add_mpsc_fields, add_spsc_fields, generate_impl, generate_mpsc_impl,
96 generate_spsc_impl,
97};
98use parser::{find_element_type, BufferMode, RingBufferArgs};
99
100/// Transforms a tuple struct into a fixed-size FIFO ring buffer.
101///
102/// # Example
103///
104/// ```ignore
105/// #[ring_buffer(10)]
106/// struct MyBuffer(String);
107/// ```
108///
109/// Generates a struct with fields: `data`, `capacity`, `head`, `tail`, `size`
110///
111/// Generates methods: `new()`, `enqueue()`, `dequeue()`, `is_full()`, `is_empty()`,
112/// `len()`, `capacity()`, `clear()`
113#[proc_macro_attribute]
114pub fn ring_buffer(args: TokenStream, input: TokenStream) -> TokenStream {
115 let args = parse_macro_input!(args as RingBufferArgs);
116 let mut input = parse_macro_input!(input as DeriveInput);
117
118 match expand_ring_buffer(args, &mut input) {
119 Ok(tokens) => tokens,
120 Err(e) => e.to_compile_error().into(),
121 }
122}
123
124fn expand_ring_buffer(args: RingBufferArgs, input: &mut DeriveInput) -> Result<TokenStream> {
125 let element_type = find_element_type(input)?;
126
127 let expanded = match args.mode {
128 BufferMode::Standard => {
129 add_fields(input, &element_type, args.cache_padded)?;
130 let implementation = generate_impl(input, &element_type, &args);
131 quote! {
132 #input
133 #implementation
134 }
135 }
136 BufferMode::Spsc => {
137 add_spsc_fields(input, &element_type, args.cache_padded, args.blocking)?;
138 let implementation = generate_spsc_impl(input, &element_type, &args);
139 quote! {
140 #input
141 #implementation
142 }
143 }
144 BufferMode::Mpsc => {
145 add_mpsc_fields(input, &element_type, args.blocking)?;
146 let implementation = generate_mpsc_impl(input, &element_type, &args);
147 quote! {
148 #input
149 #implementation
150 }
151 }
152 };
153
154 Ok(expanded.into())
155}