Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split the cache table from the record table #29

Merged
merged 10 commits into from
Dec 15, 2024
93 changes: 55 additions & 38 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ rand = "0.8.5"
ratatui = { version = "0.29.0", optional = true }
rusqlite = { version = "0.30.0", features = ["bundled"] }
shellexpand = "3.1.0"
simple-macros = { path = "simple-macros" }
tabled = "0.17.0"
yaml-rust = "0.4"

[features]
default = ["log_info", "log_warn", "log_error"]
log_info = []
log_debug = []
log_warn = []
default = ["log_info"]
witchofthewires marked this conversation as resolved.
Show resolved Hide resolved
log_debug = ["log_info"]
log_info = ["log_warn"]
log_warn = ["log_error"]
log_error = []
tui = ["dep:ratatui"]
14 changes: 14 additions & 0 deletions simple-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "simple-macros"
version = "0.1.0"
edition = "2021"

[lib]
name = "simple_macros"
path = "src/lib.rs"
proc-macro = true

[dependencies]
quote = "*"
syn = { version = "2.0.55", features = ["full", "extra-traits"] }
proc-macro2 = "1.0.78"
75 changes: 75 additions & 0 deletions simple-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{Attribute, Meta, ReturnType};

// TODO this shouldn't require the from type to derive clone
// TODO I want this to take an attr argument to control whether we generate FromIterator or not
#[proc_macro_attribute]
pub fn from(_attr: TokenStream, item: TokenStream) -> TokenStream {
let ast = syn::parse::<syn::ItemFn>(item).expect("The #[from] macro can only be applied to free-standing functions");

if ast.sig.inputs.len() != 1 || ast.sig.output == ReturnType::Default {
panic!("#[from] requires annotated function to have form fn (X) -> Y where X is any type and Y is a non-void type.");
}

let attributes = ast.attrs.into_iter()
.filter(|attr| match &attr.meta {
Meta::Path(path) if path.is_ident("from") => false,
Meta::Path(path) if path.segments.len() == 1 => match path.segments.last() {
Some(segment) if segment.ident.to_string() == "from" => false,
_ => true
}
Meta::List(list) if list.path.is_ident("from") => false,
Meta::List(list) if list.path.segments.len() == 1 => match list.path.segments.last() {
Some(segment) if segment.ident.to_string() == "from" => false,
_ => true
}
_ => true
})
.collect::<Vec<Attribute>>();

let to_type = match ast.sig.output {
ReturnType::Type(_, return_type) => return_type,
ReturnType::Default => panic!("We need a return type :(")
};
let (from_arg_name, from_type) = match ast.sig.inputs.get(0) {
Some(syn::FnArg::Typed(base_arg)) => {
(base_arg.pat.clone(), base_arg.ty.clone())
}
_ => panic!("Bad function argument!! Must be 1 non-receiver argument")
};

let function_body = ast.block.stmts;

let generated = quote! {
#(#attributes)*
impl From<#from_type> for #to_type {
fn from(#from_arg_name: #from_type) -> Self {
#(#function_body)*
}
}

#(#attributes)*
impl From<&#from_type> for #to_type {
fn from(#from_arg_name: &#from_type) -> Self {
#from_arg_name.clone().into()
}
}

#(#attributes)*
impl FromIterator<#from_type> for Vec<#to_type> {
fn from_iter<T: IntoIterator<Item = #from_type>>(iter: T) -> Self {
iter.into_iter().collect()
}
}

#(#attributes)*
impl<'from_iterator_lifetime> FromIterator<&'from_iterator_lifetime #from_type> for Vec<#to_type> {
fn from_iter<T: IntoIterator<Item = &'from_iterator_lifetime #from_type>>(iter: T) -> Self {
iter.into_iter().map(|x| <#from_type as Into<#to_type>>::into(x.clone())).collect()
}
}
};
generated.into()
}
Loading