diff --git a/proc-macros/easy-default/Cargo.toml b/proc-macros/easy-default/Cargo.toml deleted file mode 100644 index 6446261..0000000 --- a/proc-macros/easy-default/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "e-easy-default" -version = "1.0.0" -edition = "2021" - -[dependencies] -proc-macro-error = { workspace = true } -proc-macro2 = { workspace = true } -syn = { workspace = true } -quote = { workspace = true } - -e-easy-default-core = { path = "./core" } - -[lib] -proc-macro = true \ No newline at end of file diff --git a/proc-macros/easy-default/core/Cargo.toml b/proc-macros/easy-default/core/Cargo.toml deleted file mode 100644 index 46cb1ad..0000000 --- a/proc-macros/easy-default/core/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "e-easy-default-core" -version = "1.0.0" -edition = "2021" - -[dependencies] -proc-macro-error = { workspace = true } -proc-macro2 = { workspace = true } -syn = { workspace = true } -quote = { workspace = true } diff --git a/proc-macros/easy-default/core/src/lib.rs b/proc-macros/easy-default/core/src/lib.rs deleted file mode 100644 index bc2e7fc..0000000 --- a/proc-macros/easy-default/core/src/lib.rs +++ /dev/null @@ -1,213 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::{Fields, ItemStruct, Meta}; - -pub fn easy_default_core(input: TokenStream) -> TokenStream { - let input: ItemStruct = match syn::parse2(input) { - Ok(i) => i, - Err(e) => return e.to_compile_error(), - }; - - let struct_name = input.ident; - let (ipl, ty, _) = input.generics.split_for_impl(); - - match input.fields { - Fields::Named(n) => { - let mut exprs = Vec::new(); - - for field in n.named { - let default_expr = field.attrs.iter().find_map(|a| { - let default_expr = match &a.meta { - Meta::List(list) => match list.path.get_ident() { - Some(i) if i == "default" => &list.tokens, - _ => return None, - }, - _ => return None, - }; - - Some(default_expr) - }); - - let ident = field.ident.expect("named field should have name"); - match default_expr { - Some(expr) => exprs.push(quote! { - #ident: #expr, - }), - None => exprs.push(quote! { - #ident: ::core::default::Default::default(), - }), - } - } - - let output = quote! { - impl #ipl ::core::default::Default for #struct_name #ty { - fn default() -> Self { - Self { - #(#exprs)* - } - } - } - }; - - output - }, - Fields::Unnamed(u) => { - let mut exprs = Vec::new(); - - for field in u.unnamed { - let default_expr = field.attrs.iter().find_map(|a| { - let default_expr = match &a.meta { - Meta::List(list) => match list.path.get_ident() { - Some(i) if i == "default" => &list.tokens, - _ => return None, - }, - _ => return None, - }; - - Some(default_expr) - }); - - match default_expr { - Some(expr) => exprs.push(quote! { - #expr - }), - None => exprs.push(quote! { - ::core::default::Default::default() - }), - } - } - - let output = quote! { - impl #ipl ::core::default::Default for #struct_name #ty { - fn default() -> Self { - Self(#(#exprs),*) - } - } - }; - - output - }, - Fields::Unit => quote! { - impl #ipl ::core::default::Default for #struct_name #ty { - fn default() -> Self { - Self - } - } - }, - } -} - -#[cfg(test)] -mod test { - use proc_macro2::TokenStream; - use quote::quote; - - use crate::easy_default_core; - - #[test] - fn named_fields_struct() { - let before = quote! { - #[derive(EasyDefault)] - struct Test { - #[default("Test".to_string())] - foo: String, - bar: String, - } - }; - - let after = easy_default_core(before); - assert_eq!( - after.to_string(), - quote! { - impl ::core::default::Default for Test { - fn default() -> Self { - Self { - foo: "Test".to_string(), - bar: ::core::default::Default::default(), - } - } - } - } - .to_string() - ); - } - - #[test] - fn tuple_struct() { - let before = quote! { - #[derive(EasyDefault)] - struct Test(#[default(5)] u64); - }; - - let after = easy_default_core(before); - assert_eq!( - after.to_string(), - quote! { - impl ::core::default::Default for Test { - fn default() -> Self { - Self(5) - } - } - } - .to_string() - ); - } - - #[test] - fn unit_struct() { - let before = quote! { - #[derive(EasyDefault)] - struct Test; - }; - - let after = easy_default_core(before); - assert_eq!( - after.to_string(), - quote! { - impl ::core::default::Default for Test { - fn default() -> Self { - Self - } - } - } - .to_string(), - ); - } - - fn assert_output(input: TokenStream, expected: TokenStream) { - let after = easy_default_core(input); - assert_eq!(after.to_string(), expected.to_string(),) - } - - #[test] - fn other1() { - assert_output( - quote! { - pub struct ObjectMeta { - #[default(ObjectKind::Orphan)] - pub kind: ObjectKind, - #[default(OffsetDateTime::now_utc())] - pub created_at: OffsetDateTime, - #[default(OffsetDateTime::now_utc())] - pub updated_at: OffsetDateTime, - pub name: String, - pub description: String, - } - }, - quote! { - impl ::core::default::Default for ObjectMeta { - fn default() -> Self { - Self { - kind: ObjectKind::Orphan, - created_at: OffsetDateTime::now_utc(), - updated_at: OffsetDateTime::now_utc(), - name: ::core::default::Default::default(), - description: ::core::default::Default::default(), - } - } - } - - }, - ) - } -} diff --git a/proc-macros/easy-default/src/lib.rs b/proc-macros/easy-default/src/lib.rs deleted file mode 100644 index eb4f3f1..0000000 --- a/proc-macros/easy-default/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -use e_easy_default_core::easy_default_core; -use proc_macro::TokenStream; -use proc_macro_error::proc_macro_error; - -#[proc_macro_error] -#[proc_macro_derive(EasyDefault, attributes(default))] -pub fn easy_default(input: TokenStream) -> TokenStream { - easy_default_core(input.into()).into() -} diff --git a/proc-macros/easy-from/Cargo.toml b/proc-macros/easy-from/Cargo.toml deleted file mode 100644 index af7a27b..0000000 --- a/proc-macros/easy-from/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "e-easy-from" -version = "1.0.0" -edition = "2021" - -[dependencies] -proc-macro-error = { workspace = true } -proc-macro2 = { workspace = true } -syn = { workspace = true } -quote = { workspace = true } - -e-easy-from-core = { path = "./core" } - -[lib] -proc-macro = true \ No newline at end of file diff --git a/proc-macros/easy-from/core/Cargo.toml b/proc-macros/easy-from/core/Cargo.toml deleted file mode 100644 index 24ee3f5..0000000 --- a/proc-macros/easy-from/core/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "e-easy-from-core" -version = "1.0.0" -edition = "2021" - -[dependencies] -proc-macro-error = { workspace = true } -proc-macro2 = { workspace = true } -syn = { workspace = true } -quote = { workspace = true } diff --git a/proc-macros/easy-from/core/src/lib.rs b/proc-macros/easy-from/core/src/lib.rs deleted file mode 100644 index 244a76c..0000000 --- a/proc-macros/easy-from/core/src/lib.rs +++ /dev/null @@ -1,214 +0,0 @@ -use proc_macro2::TokenStream; -use quote::{quote, TokenStreamExt}; -use syn::{spanned::Spanned, Fields, Ident, ItemEnum, ItemStruct, Meta}; - -fn handle_enum(e: ItemEnum) -> TokenStream { - let name = &e.ident; - - let mut stream: TokenStream = e - .variants - .iter() - .filter_map(|variant| { - let variant_name = &variant.ident; - - let has_from_attr = variant.attrs.iter().any(|a| { - let path = match &a.meta { - Meta::Path(p) => p, - _ => return false, - }; - - path.get_ident().is_some_and(|i| *i == "from") - }); - - if !has_from_attr { - return None; - } - - match &variant.fields { - Fields::Named(_n) => todo!(), - Fields::Unnamed(u) => { - match u.unnamed.iter().collect::>().as_slice() { - &[] => todo!(), - &[field] => { - let ty = &field.ty; - Some(quote! { - impl ::core::convert::From<#ty> for #name { - fn from(value: #ty) -> Self { - Self::#variant_name(value) - } - } - }) - }, - _sl => todo!(), - } - }, - Fields::Unit => todo!(), - } - }) - .collect(); - - let has_convert_infallible = e.attrs.iter().any(|a| match &a.meta { - Meta::List(list) => { - if list.path.get_ident().is_some_and(|i| *i == "from") { - let ident: Ident = match syn::parse2(list.tokens.clone()) { - Ok(i) => i, - _ => return false, - }; - - ident == "infallible" - } else { - false - } - }, - _ => false, - }); - - if has_convert_infallible { - stream.append_all(quote! { - impl ::core::convert::From<::core::convert::Infallible> for #name { - fn from(value: ::core::convert::Infallible) -> Self { - unreachable!() - } - } - }); - } - - stream -} - -fn handle_struct(s: ItemStruct) -> TokenStream { - match &s.fields { - Fields::Unnamed(u) => { - if u.unnamed.len() != 1 { - proc_macro_error::abort!( - s.span(), - "Tuple struct must have single field" - ); - } - - let field = u.unnamed.first().expect("Should be len 1"); - let ty = &field.ty; - let name = &s.ident; - let generics = &s.generics; - - quote! { - impl #generics ::core::convert::From<#ty> for #name #generics { - fn from(value: #ty) -> Self { - Self(value) - } - } - } - }, - _ => todo!(), - } -} - -pub fn easy_from_core(input: TokenStream) -> TokenStream { - match syn::parse2(input.clone()) { - Ok(e) => handle_enum(e), - Err(_) => match syn::parse2(input) { - Ok(s) => handle_struct(s), - Err(e) => e.to_compile_error(), - }, - } -} - -#[cfg(test)] -mod test { - use quote::quote; - - use crate::easy_from_core; - - #[test] - fn test_enum_all_fields_covered() { - let input = quote! { - #[derive(EasyFrom)] - enum Foo { - #[from] - Bar(u64), - - #[from] - Baz(String), - } - }; - let output = easy_from_core(input).to_string(); - let expected = quote! { - impl ::core::convert::From for Foo { - fn from(value: u64) -> Self { - Self::Bar(value) - } - } - - impl ::core::convert::From for Foo { - fn from(value: String) -> Self { - Self::Baz(value) - } - } - } - .to_string(); - - assert_eq!(output, expected) - } - - #[test] - fn test_enum_some_fields_covered() { - let input = quote! { - #[derive(EasyFrom)] - enum Foo { - #[from] - Bar(u64), - Baz(String), - } - }; - let output = easy_from_core(input).to_string(); - let expected = quote! { - impl ::core::convert::From for Foo { - fn from(value: u64) -> Self { - Self::Bar(value) - } - } - } - .to_string(); - - assert_eq!(output, expected) - } - - #[test] - fn test_enum_from_infallible() { - let input = quote! { - #[derive(EasyFrom)] - #[from(infallible)] - enum Never {} - }; - let output = easy_from_core(input).to_string(); - let expected = quote! { - impl ::core::convert::From<::core::convert::Infallible> for Never { - fn from(value: ::core::convert::Infallible) -> Self { - unreachable!() - } - } - } - .to_string(); - - assert_eq!(output, expected) - } - - #[test] - fn test_newtype_struct() { - let input = quote! { - #[derive(EasyFrom)] - struct NewType(#[from] T); - }; - let output = easy_from_core(input).to_string(); - let expected = quote! { - impl ::core::convert::From for NewType { - fn from(value: T) -> Self { - Self(value) - } - } - } - .to_string(); - - assert_eq!(output, expected) - } -} diff --git a/proc-macros/easy-from/src/lib.rs b/proc-macros/easy-from/src/lib.rs deleted file mode 100644 index 9bb3439..0000000 --- a/proc-macros/easy-from/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -use e_easy_from_core::easy_from_core; -use proc_macro::TokenStream; -use proc_macro_error::proc_macro_error; - -#[proc_macro_error] -#[proc_macro_derive(EasyFrom, attributes(from))] -pub fn easy_from(input: TokenStream) -> TokenStream { - easy_from_core(input.into()).into() -} diff --git a/proc-macros/easy-get/Cargo.toml b/proc-macros/easy-get/Cargo.toml deleted file mode 100644 index 3f3f18b..0000000 --- a/proc-macros/easy-get/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "e-easy-get" -version = "1.0.0" -edition = "2021" - -[dependencies] -proc-macro-error = { workspace = true } -proc-macro2 = { workspace = true } -syn = { workspace = true } -quote = { workspace = true } - -e-easy-get-core = { path = "./core" } - -[lib] -proc-macro = true \ No newline at end of file diff --git a/proc-macros/easy-get/core/Cargo.toml b/proc-macros/easy-get/core/Cargo.toml deleted file mode 100644 index 6919ab7..0000000 --- a/proc-macros/easy-get/core/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "e-easy-get-core" -version = "1.0.0" -edition = "2021" - -[dependencies] -proc-macro-error = { workspace = true } -proc-macro2 = { workspace = true } -syn = { workspace = true } -quote = { workspace = true } - -e-easy-default = { path = "../../easy-default" } diff --git a/proc-macros/easy-get/core/src/lib.rs b/proc-macros/easy-get/core/src/lib.rs deleted file mode 100644 index b0208e7..0000000 --- a/proc-macros/easy-get/core/src/lib.rs +++ /dev/null @@ -1,280 +0,0 @@ -use proc_macro2::TokenStream; -use quote::{format_ident, quote, ToTokens, TokenStreamExt}; -use syn::{ - Attribute, Field, Fields, FieldsNamed, Generics, Ident, ItemStruct, LitStr, - Meta, -}; - -#[derive(Default)] -enum Visibility { - #[default] - Inherited, - Pub, -} - -impl ToTokens for Visibility { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - Visibility::Pub => tokens.append_all(quote! { pub }), - Visibility::Inherited => (), - } - } -} - -#[derive(Default)] -struct GetOptions { - visibility: Visibility, - rename: Option, -} -impl GetOptions { - fn from_attr(attr: &Attribute) -> syn::Result { - let mut out = Self::default(); - attr.parse_nested_meta(|nm| { - if nm.path.is_ident("pub") { - out.visibility = Visibility::Pub; - } - - if nm.path.is_ident("rename") { - let name = nm.value()?; - let name: LitStr = name.parse()?; - - out.rename = Some(name.value()); - } - - Ok(()) - })?; - - Ok(out) - } -} - -fn named_fields( - name: Ident, - generics: Generics, - n: FieldsNamed, -) -> TokenStream { - let (ipl, ty, _) = generics.split_for_impl(); - - n.named - .into_iter() - .flat_map(|field| { - let field_name = - field.ident.as_ref().expect("named should have ident"); - let field_ty = &field.ty; - - fn options_for( - attr_name: &str, - field: &Field, - ) -> Option> { - field.attrs.iter().find_map(|a| match &a.meta { - Meta::List(list) => list - .path - .get_ident() - .filter(|i| *i == attr_name) - .map(|_| GetOptions::from_attr(a)), - Meta::Path(p) => p - .get_ident() - .filter(|i| *i == attr_name) - .map(|_| Ok(GetOptions::default())), - _ => None, - }) - } - - let get = options_for("get", &field); - - fn output_for( - options: Option>, - field_name: &Ident, - f: impl FnOnce(Ident, Visibility) -> TokenStream, - ) -> Option { - match options { - Some(Ok(get)) => { - let GetOptions { - visibility, rename, .. - } = get; - - let fn_name = if let Some(rename) = rename { - format_ident!("{}", rename) - } else { - field_name.clone() - }; - - Some(f(fn_name, visibility)) - }, - Some(Err(e)) => Some(e.into_compile_error()), - _ => None, - } - } - - let get_out = output_for(get, field_name, |fn_name, vis| { - quote! { - impl #ipl #name #ty { - #vis fn #fn_name(&self) -> #field_ty { - self.#field_name - } - } - } - }); - - let get_ref = options_for("get_ref", &field); - - let get_ref_out = - output_for(get_ref, field_name, |fn_name, vis| { - quote! { - impl #ipl #name #ty { - #vis fn #fn_name(&self) -> &#field_ty { - &self.#field_name - } - } - } - }); - - let get_mut = options_for("get_mut", &field); - let get_mut_renamed = get_mut - .as_ref() - .is_some_and(|r| r.as_ref().is_ok_and(|o| o.rename.is_some())); - let get_mut_out = - output_for(get_mut, field_name, |fn_name, vis| { - let fn_name = if get_mut_renamed { - fn_name - } else { - format_ident!("{}_mut", fn_name) - }; - - quote! { - impl #ipl #name #ty { - #vis fn #fn_name(&mut self) -> &mut #field_ty { - &mut self.#field_name - } - } - } - }); - - get_out.into_iter().chain(get_ref_out).chain(get_mut_out) - }) - .collect() -} - -pub fn e_easy_get_core(input: TokenStream) -> TokenStream { - let item: ItemStruct = match syn::parse2(input) { - Ok(i) => i, - Err(e) => return e.into_compile_error(), - }; - - match item.fields { - Fields::Named(n) => named_fields(item.ident, item.generics, n), - _ => todo!("aaaaaa"), - } -} - -#[cfg(test)] -mod test { - use proc_macro2::TokenStream; - use quote::quote; - - use crate::e_easy_get_core; - - fn expect_output(input: TokenStream, output: TokenStream) { - assert_eq!(e_easy_get_core(input).to_string(), output.to_string()) - } - - #[test] - fn test_get_pub() { - expect_output( - quote! { - #[derive(EasyGet)] - pub struct Foo { - #[get(pub)] - bar: usize, - } - }, - quote! { - impl Foo { - pub fn bar(&self) -> usize { - self.bar - } - } - }, - ); - } - - #[test] - fn test_get_generic() { - expect_output( - quote! { - #[derive(EasyGet)] - pub struct Foo { - #[get(pub)] - bar: T, - } - }, - quote! { - impl Foo { - pub fn bar(&self) -> T { - self.bar - } - } - }, - ); - } - - #[test] - fn test_get_ref_generic_default() { - expect_output( - quote! { - #[derive(EasyGet)] - pub struct Foo { - #[get_ref(pub)] - bar: T, - } - }, - quote! { - impl Foo { - pub fn bar(&self) -> &T { - &self.bar - } - } - }, - ); - } - - #[test] - fn test_rename() { - expect_output( - quote! { - #[derive(EasyGet)] - pub struct Foo { - #[get_ref(pub, rename = "baz")] - bar: T, - } - }, - quote! { - impl Foo { - pub fn baz(&self) -> &T { - &self.bar - } - } - }, - ) - } - - #[test] - fn test_get_mut() { - expect_output( - quote! { - #[derive(EasyGet)] - pub struct Foo { - #[get_mut(pub)] - bar: T, - } - }, - quote! { - impl Foo { - pub fn bar_mut(&mut self) -> &mut T { - &mut self.bar - } - } - }, - ) - } -} diff --git a/proc-macros/easy-get/src/lib.rs b/proc-macros/easy-get/src/lib.rs deleted file mode 100644 index 2e49ff1..0000000 --- a/proc-macros/easy-get/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -use e_easy_get_core::e_easy_get_core; -use proc_macro::TokenStream; -use proc_macro_error::proc_macro_error; - -#[proc_macro_error] -#[proc_macro_derive(EasyGet, attributes(get, get_ref, get_mut))] -pub fn easy_get(input: TokenStream) -> TokenStream { - e_easy_get_core(input.into()).into() -} diff --git a/proc-macros/impl-for-refs/Cargo.toml b/proc-macros/impl-for-refs/Cargo.toml deleted file mode 100644 index 95be47b..0000000 --- a/proc-macros/impl-for-refs/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "e-impl-for-refs" -version = "1.0.0" -edition = "2021" - -[dependencies] -proc-macro-error = { workspace = true } -proc-macro2 = { workspace = true } -syn = { workspace = true } -quote = { workspace = true } - -e-impl-for-refs-core = { path = "./core" } - -[lib] -proc-macro = true \ No newline at end of file diff --git a/proc-macros/impl-for-refs/core/Cargo.toml b/proc-macros/impl-for-refs/core/Cargo.toml deleted file mode 100644 index e981e26..0000000 --- a/proc-macros/impl-for-refs/core/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "e-impl-for-refs-core" -version = "1.0.0" -edition = "2021" - -[dependencies] -proc-macro-error = { workspace = true } -proc-macro2 = { workspace = true } -syn = { workspace = true } -quote = { workspace = true } diff --git a/proc-macros/impl-for-refs/core/src/lib.rs b/proc-macros/impl-for-refs/core/src/lib.rs deleted file mode 100644 index 093b28f..0000000 --- a/proc-macros/impl-for-refs/core/src/lib.rs +++ /dev/null @@ -1,108 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::{FnArg, ItemTrait, Pat}; - -pub fn impl_for_refs_core( - _attrs: TokenStream, - item: TokenStream, -) -> TokenStream { - let trt: ItemTrait = match syn::parse2(item.clone()) { - Ok(e) => e, - Err(e) => return e.into_compile_error(), - }; - - let trt_name = &trt.ident; - - let fns = trt - .items - .iter() - .filter_map(|i| match i { - syn::TraitItem::Fn(f) => { - if f.default.is_some() { - return None; - } - - let sig = &f.sig; - let fn_name = &f.sig.ident; - let args = sig.inputs.iter().map(|i| match i { - FnArg::Receiver(_s) => { - quote!((&**self)) - }, - FnArg::Typed(t) => match t.pat.as_ref() { - Pat::Ident(e) => quote!(#e), - _ => todo!(), - }, - }); - - Some(quote! { - #sig { - #trt_name::#fn_name(#(#args),*) - } - }) - }, - _ => None, - }) - .collect::(); - - quote! { - #item - - impl<'a, T> #trt_name for &'a T where T: ?Sized + #trt_name { - #fns - } - - impl<'a, T> #trt_name for &'a mut T where T: ?Sized + #trt_name { - #fns - } - } -} - -#[cfg(test)] -mod test { - use proc_macro2::TokenStream; - use quote::quote; - - use crate::impl_for_refs_core; - - fn expect_output( - attrs: TokenStream, - input: TokenStream, - output: TokenStream, - ) { - assert_eq!( - impl_for_refs_core(attrs, input).to_string(), - output.to_string() - ) - } - - #[test] - fn test_works() { - expect_output( - quote!(), - quote! { - #[impl_for_refs] - trait Test { - fn test(&self) -> usize; - } - }, - quote! { - #[impl_for_refs] - trait Test { - fn test(&self) -> usize; - } - - impl<'a, T> Test for &'a T where T: ?Sized + Test { - fn test(&self) -> usize { - Test::test((&**self)) - } - } - - impl<'a, T> Test for &'a mut T where T: ?Sized + Test { - fn test(&self) -> usize { - Test::test((&**self)) - } - } - }, - ) - } -} diff --git a/proc-macros/impl-for-refs/src/lib.rs b/proc-macros/impl-for-refs/src/lib.rs deleted file mode 100644 index f384d3a..0000000 --- a/proc-macros/impl-for-refs/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -use e_impl_for_refs_core::impl_for_refs_core; -use proc_macro::TokenStream; -use proc_macro_error::proc_macro_error; - -#[proc_macro_error] -#[proc_macro_attribute] -pub fn impl_for_refs(attrs: TokenStream, item: TokenStream) -> TokenStream { - impl_for_refs_core(attrs.into(), item.into()).into() -}