Skip to content

Commit

Permalink
swap out std hashmap with the hashbrown one
Browse files Browse the repository at this point in the history
  • Loading branch information
GlenDC committed Apr 5, 2024
1 parent 13920c1 commit b5f7d9e
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 109 deletions.
10 changes: 3 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = [".", "venndb-usage"]
members = [".", "venndb-macros", "venndb-usage"]

[package]
description = "an in-memory database in Rust for rows queried using bit (flag) columns"
Expand All @@ -20,9 +20,5 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = "2.0"

[lib]
proc-macro = true
hashbrown = "0.14.3"
venndb-macros = { version = "0.1.0", path = "venndb-macros" }
98 changes: 6 additions & 92 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,95 +1,9 @@
#![forbid(unsafe_code)]
pub use venndb_macros::VennDB;

mod errors;
mod field;
mod generate_db;
mod parse_attrs;
#[doc(hidden)]
pub mod internal {
//! Hidden thirdparty dependencies for venndb,
//! not to be relied upon directly, as they may change at any time.

use errors::Errors;
use field::StructField;
use parse_attrs::{FieldAttrs, TypeAttrs};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};

/// Derive macro generating VennDB functionality for this struct.
#[proc_macro_derive(VennDB, attributes(venndb))]
pub fn venndb(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse_macro_input!(input as syn::DeriveInput);
let gen = impl_from_args(&ast);
gen.into()
}

/// Transform the input into a token stream containing any generated implementations,
/// as well as all errors that occurred.
fn impl_from_args(input: &syn::DeriveInput) -> TokenStream {
let errors = &Errors::default();
let type_attrs = &TypeAttrs::parse(errors, input);
let mut output_tokens = match &input.data {
syn::Data::Struct(ds) => impl_from_args_struct(
errors,
&input.vis,
&input.ident,
type_attrs,
&input.generics,
ds,
),
syn::Data::Enum(_) => {
errors.err(input, "`#[derive(VennDB)]` cannot be applied to enums");
TokenStream::new()
}
syn::Data::Union(_) => {
errors.err(input, "`#[derive(VennDB)]` cannot be applied to unions");
TokenStream::new()
}
};
errors.to_tokens(&mut output_tokens);
output_tokens
}

/// Implements `VennDB` for a `#[derive(VennDB)]` struct.
fn impl_from_args_struct(
errors: &Errors,
vis: &syn::Visibility,
name: &syn::Ident,
type_attrs: &TypeAttrs,
_generic_args: &syn::Generics,
ds: &syn::DataStruct,
) -> TokenStream {
let fields = match &ds.fields {
syn::Fields::Named(fields) => fields,
syn::Fields::Unnamed(_) => {
errors.err(
&ds.struct_token,
"`#![derive(VennDB)]` is not currently supported on tuple structs",
);
return TokenStream::new();
}
syn::Fields::Unit => {
errors.err(
&ds.struct_token,
"#![derive(VennDB)]` cannot be applied to unit structs",
);
return TokenStream::new();
}
};

let fields: Vec<_> = fields
.named
.iter()
.filter_map(|field| {
let attrs = FieldAttrs::parse(errors, field);
StructField::new(errors, field, attrs)
})
.collect();

let name_db = match &type_attrs.name {
Some(name) => format_ident!("{}", name.value()),
None => format_ident!("{}DB", name),
};

let db_code = generate_db::generate_db(name, &name_db, vis, &fields[..]);

quote! {
#db_code
}
pub use hashbrown::HashMap;
}
25 changes: 25 additions & 0 deletions venndb-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
description = "macros for venndb, cannot be used directly"
edition = "2021"
homepage = "https://venndb.rs"
license = "MIT OR Apache-2.0"
name = "venndb-macros"
readme = "README.md"
repository = "https://github.com/plabayo/venndb"
keywords = ["database", "db", "memory", "bits"]
categories = ["database", "db"]
authors = ["Glen De Cauwsemaecker <glen@plabayo.tech>"]
version = "0.1.0"
rust-version = "1.75.0"

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = "2.0"

[lib]
proc-macro = true
File renamed without changes.
File renamed without changes.
12 changes: 6 additions & 6 deletions src/generate_db.rs → venndb-macros/src/generate_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn generate_db_struct(
let field_name = field.map_name();
let ty: &syn::Type = field.ty();
quote! {
#field_name: std::collections::HashMap<#ty, usize>,
#field_name: ::venndb::internal::HashMap<#ty, usize>,
}
}
})
Expand Down Expand Up @@ -124,7 +124,7 @@ pub fn generate_db_struct_method_new(
FieldInfo::Key(field) => {
let name = field.map_name();
quote! {
#name: std::collections::HashMap::new(),
#name: ::venndb::internal::HashMap::new(),
}
}
})
Expand Down Expand Up @@ -196,7 +196,7 @@ pub fn generate_db_struct_method_with_capacity(
FieldInfo::Key(field) => {
let name = field.map_name();
quote! {
#name: std::collections::HashMap::with_capacity(capacity),
#name: ::venndb::internal::HashMap::with_capacity(capacity),
}
}
})
Expand Down Expand Up @@ -227,10 +227,10 @@ pub fn generate_db_struct_methods_key(
let ty = field.ty();
let method_name = field.method_name();
quote! {
#vis fn #method_name<Q>(&self, key: &Q) -> std::option::Option<&#name>
#vis fn #method_name<Q>(&self, key: &Q) -> ::std::option::Option<&#name>
where
#ty: std::borrow::Borrow<Q>,
Q: std::hash::Hash + std::cmp::Eq + ?std::marker::Sized,
#ty: ::std::borrow::Borrow<Q>,
Q: ::std::hash::Hash + ::std::cmp::Eq + ?::std::marker::Sized,
{
self.#map_name.get(key).and_then(|index| self.rows.get(*index))
}
Expand Down
95 changes: 95 additions & 0 deletions venndb-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#![forbid(unsafe_code)]

mod errors;
mod field;
mod generate_db;
mod parse_attrs;

use errors::Errors;
use field::StructField;
use parse_attrs::{FieldAttrs, TypeAttrs};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};

/// Derive macro generating VennDB functionality for this struct.
#[proc_macro_derive(VennDB, attributes(venndb))]
pub fn venndb(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse_macro_input!(input as syn::DeriveInput);
let gen: TokenStream = impl_from_args(&ast);
gen.into()
}

/// Transform the input into a token stream containing any generated implementations,
/// as well as all errors that occurred.
fn impl_from_args(input: &syn::DeriveInput) -> TokenStream {
let errors = &Errors::default();
let type_attrs = &TypeAttrs::parse(errors, input);
let mut output_tokens = match &input.data {
syn::Data::Struct(ds) => impl_from_args_struct(
errors,
&input.vis,
&input.ident,
type_attrs,
&input.generics,
ds,
),
syn::Data::Enum(_) => {
errors.err(input, "`#[derive(VennDB)]` cannot be applied to enums");
TokenStream::new()
}
syn::Data::Union(_) => {
errors.err(input, "`#[derive(VennDB)]` cannot be applied to unions");
TokenStream::new()
}
};
errors.to_tokens(&mut output_tokens);
output_tokens
}

/// Implements `VennDB` for a `#[derive(VennDB)]` struct.
fn impl_from_args_struct(
errors: &Errors,
vis: &syn::Visibility,
name: &syn::Ident,
type_attrs: &TypeAttrs,
_generic_args: &syn::Generics,
ds: &syn::DataStruct,
) -> TokenStream {
let fields = match &ds.fields {
syn::Fields::Named(fields) => fields,
syn::Fields::Unnamed(_) => {
errors.err(
&ds.struct_token,
"`#![derive(VennDB)]` is not currently supported on tuple structs",
);
return TokenStream::new();
}
syn::Fields::Unit => {
errors.err(
&ds.struct_token,
"#![derive(VennDB)]` cannot be applied to unit structs",
);
return TokenStream::new();
}
};

let fields: Vec<_> = fields
.named
.iter()
.filter_map(|field| {
let attrs = FieldAttrs::parse(errors, field);
StructField::new(errors, field, attrs)
})
.collect();

let name_db = match &type_attrs.name {
Some(name) => format_ident!("{}", name.value()),
None => format_ident!("{}DB", name),
};

let db_code = generate_db::generate_db(name, &name_db, vis, &fields[..]);

quote! {
#db_code
}
}
19 changes: 15 additions & 4 deletions src/parse_attrs.rs → venndb-macros/src/parse_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,31 @@ impl FieldAttrs {
continue;
};

let mut skipped = false;
let mut is_key = false;

for meta in ml {
let name = meta.path();
if name.is_ident("key") {
this.kind = Some(FieldKind::Key);
is_key = true;
} else if name.is_ident("skip") {
skipped = true;
} else {
errors.err(
&meta,
concat!(
"Invalid field-level `argh` attribute\n",
"Invalid field-level `venndb` attribute\n",
"Expected one of: `key`",
),
);
}
}

if skipped {
this.kind = None;
} else if is_key {
this.kind = Some(FieldKind::Key);
}
}

this
Expand Down Expand Up @@ -86,7 +97,7 @@ fn venndb_attr_to_meta_list(
errors: &Errors,
attr: &syn::Attribute,
) -> Option<impl IntoIterator<Item = syn::Meta>> {
if !is_argh_attr(attr) {
if !is_venndb_attr(attr) {
return None;
}
let ml = errors.expect_meta_list(&attr.meta)?;
Expand All @@ -101,6 +112,6 @@ fn is_matching_attr(name: &str, attr: &syn::Attribute) -> bool {
}

/// Checks for `#[venndb ...]`
fn is_argh_attr(attr: &syn::Attribute) -> bool {
fn is_venndb_attr(attr: &syn::Attribute) -> bool {
is_matching_attr("venndb", attr)
}

0 comments on commit b5f7d9e

Please sign in to comment.