Skip to content

Commit

Permalink
Merge pull request #51 from hit-box/feat/container
Browse files Browse the repository at this point in the history
feat/container
  • Loading branch information
singulared authored Jan 31, 2023
2 parents edf3046 + 8dbd549 commit 83e5076
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 48 deletions.
22 changes: 10 additions & 12 deletions hitbox-derive/src/cacheable_macro.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use proc_macro::TokenStream;

use proc_macro2::TokenStream;
use quote::quote;

use crate::macro_attributes::find_attribute;

use crate::container::Container;
/// Implementing Cacheable trait.
///
/// Uses `serde_qs` crate to create a unique cache key.
/// Default implementation of methods `cache_ttl`, `cache_stale_ttl` and `cache_version`
/// are used if macros of the same name are not used.
pub fn impl_macro(ast: &syn::DeriveInput) -> TokenStream {
pub fn impl_macro(ast: &syn::DeriveInput) -> syn::Result<TokenStream> {
let name = &ast.ident;
let message_type = format!("{}", name);
let message_type = format!("{name}");
let attrs = Container::from_ast(ast)?;

let cache_key_implement = quote! {
fn cache_key(&self) -> Result<String, CacheError> {
Expand All @@ -27,7 +26,7 @@ pub fn impl_macro(ast: &syn::DeriveInput) -> TokenStream {
}
};

let cache_ttl_implement = match find_attribute(ast, "cache_ttl") {
let cache_ttl_implement = match attrs.cache_ttl {
Some(cache_ttl) => quote! {
fn cache_ttl(&self) -> u32 {
#cache_ttl
Expand All @@ -36,7 +35,7 @@ pub fn impl_macro(ast: &syn::DeriveInput) -> TokenStream {
None => proc_macro2::TokenStream::new(),
};

let cache_stale_ttl_implement = match find_attribute(ast, "cache_stale_ttl") {
let cache_stale_ttl_implement = match attrs.cache_stale_ttl {
Some(cache_stale_ttl) => quote! {
fn cache_stale_ttl(&self) -> u32 {
#cache_stale_ttl
Expand All @@ -45,7 +44,7 @@ pub fn impl_macro(ast: &syn::DeriveInput) -> TokenStream {
None => proc_macro2::TokenStream::new(),
};

let cache_version_implement = match find_attribute(ast, "cache_version") {
let cache_version_implement = match attrs.cache_version {
Some(cache_version) => quote! {
fn cache_version(&self) -> u32 {
#cache_version
Expand All @@ -54,14 +53,13 @@ pub fn impl_macro(ast: &syn::DeriveInput) -> TokenStream {
None => proc_macro2::TokenStream::new(),
};

let gen = quote! {
Ok(quote! {
impl Cacheable for #name {
#cache_key_implement
#cache_key_prefix_implement
#cache_ttl_implement
#cache_stale_ttl_implement
#cache_version_implement
}
};
gen.into()
})
}
94 changes: 94 additions & 0 deletions hitbox-derive/src/container.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use quote::ToTokens;

const CACHE_TTL: &str = "cache_ttl";
const CACHE_STALE_TTL: &str = "cache_stale_ttl";
const CACHE_VERSION: &str = "cache_version";

fn parse_lit_to_u32(lit: &syn::Lit, attr_name: &str) -> syn::Result<u32> {
match lit {
syn::Lit::Int(lit) => lit
.base10_parse::<u32>()
.map_err(|e| syn::Error::new_spanned(lit, e)),
_ => Err(syn::Error::new_spanned(
lit,
format!("Expected hitbox {attr_name} attribute should be u32"),
)),
}
}

pub struct Container {
pub cache_ttl: Option<u32>,
pub cache_stale_ttl: Option<u32>,
pub cache_version: Option<u32>,
}

impl Container {
pub fn from_ast(input: &syn::DeriveInput) -> syn::Result<Self> {
let mut ttl = None;
let mut stale_ttl = None;
let mut version = None;

let items = input
.attrs
.iter()
.map(|attr| {
if !attr.path.is_ident("hitbox") {
return Ok(Vec::new());
}
match attr.parse_meta() {
Ok(syn::Meta::List(meta)) => Ok(meta.nested.into_iter().collect()),
Ok(other) => Err(syn::Error::new_spanned(other, "expected #[hitbox(...)]")),
Err(err) => Err(err),
}
})
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.flatten();

for meta_item in items {
match &meta_item {
// Parse `#[hitbox(cache_ttl = 42)]`
syn::NestedMeta::Meta(syn::Meta::NameValue(m)) if m.path.is_ident(CACHE_TTL) => {
ttl = Some(parse_lit_to_u32(&m.lit, CACHE_TTL)?);
}

// Parse `#[hitbox(cache_stale_ttl = 42)]`
syn::NestedMeta::Meta(syn::Meta::NameValue(m))
if m.path.is_ident(CACHE_STALE_TTL) =>
{
stale_ttl = Some(parse_lit_to_u32(&m.lit, CACHE_STALE_TTL)?);
}

// Parse `#[hitbox(cache_version = 42)]`
syn::NestedMeta::Meta(syn::Meta::NameValue(m))
if m.path.is_ident(CACHE_VERSION) =>
{
version = Some(parse_lit_to_u32(&m.lit, CACHE_VERSION)?);
}

// Throw error on unknown attribute
syn::NestedMeta::Meta(m) => {
let path = m.path().into_token_stream().to_string().replace(' ', "");
return Err(syn::Error::new_spanned(
m.path(),
format!("Unknown hitbox container attribute `{path}`"),
));
}

// Throw error on other lit types
lit => {
return Err(syn::Error::new_spanned(
lit,
"Unexpected literal in hitbox container attribute",
));
}
}
}

Ok(Container {
cache_ttl: ttl,
cache_stale_ttl: stale_ttl,
cache_version: version,
})
}
}
14 changes: 7 additions & 7 deletions hitbox-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
//! use serde::Serialize;
//!
//! #[derive(Cacheable, Serialize)]
//! #[cache_ttl(120)]
//! #[cache_stale_ttl(100)]
//! #[cache_version(100)]
//! #[hitbox(cache_ttl=120, cache_stale_ttl=100, cache_version=100)]
//! struct Message {
//! field: i32,
//! };
Expand All @@ -33,18 +31,20 @@ use proc_macro::TokenStream;

mod cacheable_macro;
mod cacheable_response_macro;
mod macro_attributes;
mod container;

/// Derive Cacheable macro implementation.
#[proc_macro_derive(Cacheable, attributes(cache_ttl, cache_stale_ttl, cache_version))]
#[proc_macro_derive(Cacheable, attributes(hitbox))]
pub fn cacheable_macro_derive(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
let ast = syn::parse_macro_input!(input as syn::DeriveInput);
cacheable_macro::impl_macro(&ast)
.unwrap_or_else(|err| err.to_compile_error())
.into()
}

/// Derive CacheableResponse macro implementation.
#[proc_macro_derive(CacheableResponse)]
pub fn cacheable_response_macro_derive(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
let ast = syn::parse_macro_input!(input as syn::DeriveInput);
cacheable_response_macro::impl_macro(&ast)
}
25 changes: 0 additions & 25 deletions hitbox-derive/src/macro_attributes.rs

This file was deleted.

2 changes: 1 addition & 1 deletion hitbox/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub enum CachePolicy<T, U> {
NonCacheable(U),
}

/// Thit is one of the basic trait which determines should data store in cache backend or not.
/// This is one of the basic trait which determines should data store in cache backend or not.
///
/// For primitive types and for user-defined types (with derive macro)
/// cache_policy returns CachePolicy::Cached variant.
Expand Down
4 changes: 1 addition & 3 deletions hitbox/tests/cacheable_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,7 @@ fn test_tuple_returns_error() {
}

#[derive(Cacheable, Serialize)]
#[cache_ttl(42)]
#[cache_stale_ttl(30)]
#[cache_version(1)]
#[hitbox(cache_ttl=42, cache_stale_ttl=30, cache_version=1)]
struct MacroHelpersMessage {
message_type: i32,
}
Expand Down

0 comments on commit 83e5076

Please sign in to comment.