use crate::error::Result;
use crate::parser::RingBufferArgs;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{Data, DeriveInput, Fields, FieldsNamed, Type};
pub fn add_fields(input: &mut DeriveInput, element_type: &Type, cache_padded: bool) -> Result<()> {
let struct_name = &input.ident;
let cache_padded_type_name = format_ident!("{}CachePadded", struct_name);
if let Data::Struct(data_struct) = &mut input.data {
let data_field: syn::Field = syn::parse_quote! { data: Vec<#element_type> };
let capacity_field: syn::Field = syn::parse_quote! { capacity: usize };
let size_field: syn::Field = syn::parse_quote! { size: usize };
let (head_field, tail_field): (syn::Field, syn::Field) = if cache_padded {
(
syn::parse_quote! { head: #cache_padded_type_name },
syn::parse_quote! { tail: #cache_padded_type_name },
)
} else {
(
syn::parse_quote! { head: usize },
syn::parse_quote! { tail: usize },
)
};
let named_fields: FieldsNamed = syn::parse_quote! { { } };
let mut fields = named_fields;
fields.named.push(data_field);
fields.named.push(capacity_field);
fields.named.push(head_field);
fields.named.push(tail_field);
fields.named.push(size_field);
data_struct.fields = Fields::Named(fields);
}
Ok(())
}
pub fn generate_impl(
input: &DeriveInput,
element_type: &Type,
args: &RingBufferArgs,
) -> TokenStream {
let struct_name = &input.ident;
let vis = &input.vis;
let generics = &input.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let capacity = args.capacity;
let mask = args.index_mask();
let cache_padded = args.cache_padded;
let clone_bound = quote! { where #element_type: Clone };
let drain_name = format_ident!("{}Drain", struct_name);
let cache_padded_type_name = format_ident!("{}CachePadded", struct_name);
let (head_get, tail_get, head_set, tail_set, head_init, tail_init) = if cache_padded {
(
quote! { self.head.0 },
quote! { self.tail.0 },
quote! { self.head.0 = },
quote! { self.tail.0 = },
quote! { #cache_padded_type_name(0) },
quote! { #cache_padded_type_name(0) },
)
} else {
(
quote! { self.head },
quote! { self.tail },
quote! { self.head = },
quote! { self.tail = },
quote! { 0 },
quote! { 0 },
)
};
let next_head = if args.power_of_two {
quote! { (#head_get + 1) & #mask }
} else {
quote! { (#head_get + 1) % self.capacity }
};
let next_tail = if args.power_of_two {
quote! { (#tail_get + 1) & #mask }
} else {
quote! { (#tail_get + 1) % self.capacity }
};
let cache_padded_type = if cache_padded {
quote! {
#[repr(C, align(64))]
#[derive(Debug, Clone, Copy, Default)]
#vis struct #cache_padded_type_name(usize);
}
} else {
quote! {}
};
quote! {
#cache_padded_type
impl #impl_generics #struct_name #ty_generics #where_clause {
#vis fn new() -> Self {
Self {
data: Vec::with_capacity(#capacity),
capacity: #capacity,
head: #head_init,
tail: #tail_init,
size: 0,
}
}
#vis fn enqueue(&mut self, item: #element_type) -> Result<(), #element_type> {
if self.is_full() {
return Err(item);
}
let tail = #tail_get;
if self.data.len() <= tail {
self.data.push(item);
} else {
self.data[tail] = item;
}
#tail_set #next_tail;
self.size += 1;
Ok(())
}
#vis fn dequeue(&mut self) -> Option<#element_type>
#clone_bound
{
if self.is_empty() {
return None;
}
let head = #head_get;
let item = self.data[head].clone();
#head_set #next_head;
self.size -= 1;
Some(item)
}
#[inline]
#vis fn peek(&self) -> Option<&#element_type> {
if self.is_empty() { None } else { Some(&self.data[#head_get]) }
}
#[inline]
#vis fn peek_mut(&mut self) -> Option<&mut #element_type> {
if self.is_empty() { None } else { let h = #head_get; Some(&mut self.data[h]) }
}
#[inline]
#vis fn peek_back(&self) -> Option<&#element_type> {
if self.is_empty() {
None
} else {
let tail = #tail_get;
let idx = if tail == 0 { self.capacity - 1 } else { tail - 1 };
if idx < self.data.len() { Some(&self.data[idx]) } else { None }
}
}
#[inline]
#vis fn is_full(&self) -> bool { self.size == self.capacity }
#[inline]
#vis fn is_empty(&self) -> bool { self.size == 0 }
#[inline]
#vis fn len(&self) -> usize { self.size }
#[inline]
#vis fn capacity(&self) -> usize { self.capacity }
#vis fn clear(&mut self) {
#head_set 0;
#tail_set 0;
self.size = 0;
}
#vis fn iter(&self) -> impl Iterator<Item = &#element_type> {
let head = #head_get;
let size = self.size;
let cap = self.capacity;
(0..size).map(move |i| &self.data[(head + i) % cap])
}
#vis fn drain(&mut self) -> #drain_name #ty_generics
#clone_bound
{
#drain_name { buffer: self }
}
}
#vis struct #drain_name #generics {
buffer: *mut #struct_name #ty_generics,
}
impl #impl_generics Iterator for #drain_name #ty_generics
#clone_bound
{
type Item = #element_type;
fn next(&mut self) -> Option<Self::Item> {
unsafe { (*self.buffer).dequeue() }
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = unsafe { (*self.buffer).len() };
(len, Some(len))
}
}
impl #impl_generics ExactSizeIterator for #drain_name #ty_generics
#clone_bound
{}
impl #impl_generics Drop for #drain_name #ty_generics
#clone_bound
{
fn drop(&mut self) {
unsafe { while (*self.buffer).dequeue().is_some() {} }
}
}
}
}