├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── readme.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | 4 | # Added by cargo 5 | # 6 | # already existing elements were commented out 7 | 8 | #/target 9 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "go-visibility-macro" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "proc-macro2", 10 | "quote", 11 | "syn", 12 | ] 13 | 14 | [[package]] 15 | name = "proc-macro2" 16 | version = "1.0.94" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 19 | dependencies = [ 20 | "unicode-ident", 21 | ] 22 | 23 | [[package]] 24 | name = "quote" 25 | version = "1.0.40" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 28 | dependencies = [ 29 | "proc-macro2", 30 | ] 31 | 32 | [[package]] 33 | name = "syn" 34 | version = "2.0.100" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 37 | dependencies = [ 38 | "proc-macro2", 39 | "quote", 40 | "unicode-ident", 41 | ] 42 | 43 | [[package]] 44 | name = "unicode-ident" 45 | version = "1.0.18" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 48 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "go-visibility-macro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | proc-macro = true 8 | 9 | [dependencies] 10 | syn = { version = "2.0", features = ["full"] } 11 | quote = "1.0" 12 | proc-macro2 = "1.0" -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 🦀 go_visibility_macro 🦀 2 | Because Rust's `pub` keyword was just too explicit 🔥 3 | Finally, a revolutionary crate that brings Go's brilliant visibility conventions to Rust — because who needs explicit keywords when you can just Capitalize Everything? 4 | 5 | ```rust 6 | use go_visibility_macro::go_visibility; 7 | 8 | #[go_visibility] 9 | struct MyStruct { // Automagically `pub`! 10 | PublicField: i32, // Also `pub`! 11 | private_field: i32, // Not `pub` (how sad) 12 | } 13 | 14 | #[go_visibility] 15 | impl MyStruct { 16 | fn New() -> Self { // `pub` because it's uppercase! 17 | Self { PublicField: 42, private_field: 69 } 18 | } 19 | 20 | fn get_secret(&self) -> i32 { // Still private (loser) 21 | self.private_field 22 | } 23 | } 24 | ``` 25 | 26 | --- 27 | 28 | ## ✨ Features ✨ 29 | 30 | ### 🚀 Automatic pub-ification 🎩✨ 31 | 32 | - Struct name starts with uppercase? `pub` it! 33 | - Field name looks important? `pub` that too! 34 | - Function name screams "I'm public"? `pub` it like it's hot! 35 | 36 | --- 37 | 38 | ### 😌 Go Developer PTSD Relief 39 | 40 | - Miss Go's subtle visibility rules? Now you can write Rust like it's Go! 41 | - No more confusing `pub` spam — just **Capitalize and pray** 🙏 42 | 43 | --- 44 | 45 | ### 🧙 Zero Runtime Overhead 46 | *(Because it's a proc macro, and we all know those never slow down compilation...)* 47 | 48 | --- 49 | 50 | ### 🤯 100% Guaranteed to Confuse Rust Purists 51 | 52 | > "Explicit is better than implicit?" 53 | > Not anymore! 54 | 55 | --- 56 | 57 | ## 📦 Installation 58 | 59 | Add this masterpiece to your `Cargo.toml`: 60 | 61 | ```toml 62 | [dependencies] 63 | go_visibility_macro = "0.1" # Because semver is for cowards 64 | ``` 65 | 66 | --- 67 | 68 | ## 🛠️ Usage 69 | 70 | ### 1. Structs? pub-ify them! 71 | 72 | ```rust 73 | use go_visibility_macro::go_visibility; 74 | 75 | #[go_visibility] 76 | struct MyStruct { // Automagically `pub`! 77 | PublicField: i32, // Also `pub`! 78 | private_field: i32, // Not `pub` (how sad) 79 | } 80 | ``` 81 | 82 | --- 83 | 84 | ### 2. Functions? pub-ify them harder! 85 | 86 | ```rust 87 | #[go_visibility] 88 | impl MyStruct { 89 | fn New() -> Self { // `pub` because it's uppercase! 90 | Self { PublicField: 42, private_field: 69 } 91 | } 92 | 93 | fn get_secret(&self) -> i32 { // Still private (loser) 94 | self.private_field 95 | } 96 | } 97 | ``` 98 | 99 | --- 100 | 101 | ### 3. Watch Rustaceans Scream in Horror 😱 102 | 103 | ```rust 104 | // "Wait... why is this public?!" — Some Rust dev, probably 105 | let s = MyStruct::New(); 106 | println!("{}", s.PublicField); // Works! 107 | // println!("{}", s.private_field); // ERROR! (As it should be) 108 | ``` 109 | 110 | --- 111 | 112 | ## 🤔 Why? 113 | 114 | - "I miss Go" — You, probably 115 | - "`pub` is too many letters" — Also you 116 | - "I like making my IDE highlight random words" — Definitely you 117 | 118 | --- 119 | 120 | ## ⚠️ Warning 121 | 122 | 🚨 **Not recommended for:** 123 | 124 | - Teams that like "readability" 125 | - People who enjoy Rust's explicitness 126 | 127 | 🚨 **Highly recommended for:** 128 | 129 | - Proving that yes, you *can* make Rust look like Go 130 | 131 | --- 132 | 133 | ## 🔮 Future Plans 134 | 135 | - `#[go_error_handling]` — Replace `Result` with `if err != nil` 136 | - `#[go_gc]` — Just `malloc()` everywhere and pray 137 | - `go!` macro for go code inlining, with support for [TinyGo](https://tinygo.org/) LLVM 138 | 139 | --- 140 | 141 | ## 🎉 Contributing 142 | 143 | PRs welcome! 144 | (Just make sure your function names are **Capitalized Correctly** or they won't be `pub`!) 145 | 146 | 🌟 Star this repo if you love Go! 147 | 148 | --- 149 | 150 | 🦀 *Rust is fun, but have you tried not being explicit?* 🦀 151 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use quote::quote; 3 | use syn::{parse_macro_input, ItemImpl, ItemStruct, Visibility}; 4 | 5 | #[proc_macro_attribute] 6 | pub fn go_visibility(_attr: TokenStream, item: TokenStream) -> TokenStream { 7 | let input = parse_macro_input!(item as syn::Item); 8 | 9 | match input { 10 | syn::Item::Struct(item) => handle_struct(item), 11 | syn::Item::Impl(item) => handle_impl(item), 12 | _ => TokenStream::from(quote! { #input }), 13 | } 14 | } 15 | 16 | fn handle_struct(item: ItemStruct) -> TokenStream { 17 | let mut output = item.clone(); 18 | 19 | // Handle struct visibility 20 | if item.ident.to_string().starts_with(char::is_uppercase) { 21 | output.vis = Visibility::Public(Default::default()); 22 | output.attrs.push(syn::parse_quote! { 23 | #[allow(non_snake_case)] 24 | }); 25 | } 26 | 27 | // Handle field visibility 28 | if let syn::Fields::Named(fields) = &mut output.fields { 29 | for field in &mut fields.named { 30 | if field 31 | .ident 32 | .as_ref() 33 | .unwrap() 34 | .to_string() 35 | .starts_with(char::is_uppercase) 36 | { 37 | field.vis = Visibility::Public(Default::default()); 38 | field.attrs.push(syn::parse_quote! { 39 | #[allow(non_snake_case)] 40 | }); 41 | } 42 | } 43 | } 44 | 45 | TokenStream::from(quote! { #output }) 46 | } 47 | 48 | fn handle_impl(item: ItemImpl) -> TokenStream { 49 | let mut output = item.clone(); 50 | 51 | for item in &mut output.items { 52 | if let syn::ImplItem::Fn(method) = item { 53 | if method.sig.ident.to_string().starts_with(char::is_uppercase) { 54 | method.vis = Visibility::Public(Default::default()); 55 | method.attrs.push(syn::parse_quote! { 56 | #[allow(non_snake_case)] 57 | }); 58 | } 59 | } 60 | } 61 | 62 | TokenStream::from(quote! { #output }) 63 | } 64 | --------------------------------------------------------------------------------