accursed_unutterable_type_id_derive/
lib.rs1use std::{env, fs, path::PathBuf};
2
3use fslock::LockFile;
4use proc_macro::TokenStream;
5use quote::{quote, ToTokens};
6use syn::{parse_macro_input, DeriveInput, GenericParam};
7
8const DEFAULT_LOCK_FILE_NAME: &str =
9 "accursed-unutterable-type-id-global-store-oh-god-is-this-cursed-dont-touch-it-LOCK";
10
11const DEFAULT_FILE_NAME: &str =
12 "accursed-unutterable-type-id-global-store-oh-god-is-this-cursed-dont-touch-it";
13
14#[proc_macro_derive(AccursedUnutterablyTypeIdentified)]
15pub fn derive_accursed_unutterable_type_identified(input: TokenStream) -> TokenStream {
16 let input = parse_macro_input!(input as DeriveInput);
17
18 let dir_path = match env::var("ACCURSED_UNUTTERABLE_TYPE_ID_DIR") {
19 Ok(string) => PathBuf::from(string),
20 Err(_) => {
21 let manifest_dir = env::var("CARGO_MANIFEST_DIR")
22 .unwrap_or_else(|_| fail("`CARGO_MANIFEST_DIR` environment variable not found"));
23 let manifest_dir = PathBuf::from(manifest_dir);
24 manifest_dir.join("target")
25 }
26 };
27
28 let lock_path = dir_path.join(DEFAULT_LOCK_FILE_NAME);
29 let file_path = dir_path.join(DEFAULT_FILE_NAME);
30
31 let mut file = LockFile::open(&dir_path.join(lock_path))
32 .unwrap_or_else(|_| fail("failed to open global lock file"));
33
34 file.lock().unwrap_or_else(|_| fail("failed to lock file"));
35
36 let old = fs::read_to_string(&file_path).unwrap_or_else(|_| "0".to_string()); let old: u64 = old.trim().parse().unwrap_or(0); let new_value = old
41 .checked_add(1)
42 .unwrap_or_else(|| fail("integer overflow. use cargo clean. if the problem persists, you have way too many derives, the fuck"));
43
44 fs::write(&file_path, new_value.to_string())
45 .unwrap_or_else(|_| fail("failed to write new number"));
46
47 let _ = file.unlock();
48
49 let name = input.ident;
50 let generics1 = input.generics.params.iter().map(|p| match p {
51 GenericParam::Type(ty) => {
52 let name = &ty.ident;
53 let bounds = ty.bounds.iter();
54 quote!(#name: #(#bounds +)* ::accursed_unutterable_type_id::AccursedUnutterablyTypeIdentified + 'static)
55 }
56 other => other.to_token_stream(),
57 });
58 let generics2 = input.generics.params.iter().map(|p| match p {
59 GenericParam::Const(const_param) => const_param.ident.to_token_stream(),
60 GenericParam::Type(ty) => ty.ident.to_token_stream(),
61 other => other.to_token_stream(),
62 });
63
64 let where_clause = input.generics.where_clause;
65
66 let ty_param_ids = input.generics.params.iter().filter_map(|p| match p {
67 GenericParam::Lifetime(_) => None,
68 GenericParam::Type(ty) => {
69 let name = &ty.ident;
70 Some(quote! {
71 ::accursed_unutterable_type_id::AccursedUnutterableTypeId::of::<#name>()
72 })
73 }
74 GenericParam::Const(_) => Some(quote!(compile_error!(
75 "const generics are not supported yet"
76 ))),
77 });
78
79 let expanded = quote! {
82 unsafe impl<#(#generics1),*> ::accursed_unutterable_type_id::AccursedUnutterablyTypeIdentified for #name<#(#generics2),*>
83 #where_clause
84 {
85 #[allow(unused_mut)]
86 fn type_id() -> ::accursed_unutterable_type_id::AccursedUnutterableTypeId {
87 let mut hasher = ::std::collections::hash_map::DefaultHasher::new();
88
89 #(
90 ::std::hash::Hash::hash(&#ty_param_ids, &mut hasher);
91 )*
92
93 let value = <::std::collections::hash_map::DefaultHasher as ::std::hash::Hasher>::finish(&hasher);
94
95 ::accursed_unutterable_type_id::AccursedUnutterableTypeId::__internal_new(
96 ::accursed_unutterable_type_id::InternalAccursedUnutterableTypeId::__internal_new(
97 #new_value, value,
98 )
99 )
100 }
101 }
102 };
103
104 TokenStream::from(expanded)
106}
107
108#[proc_macro_attribute]
109#[doc(hidden)]
110pub fn __foreign_accursed_unutterable_type_identified(
111 _attr: TokenStream,
112 item: TokenStream,
113) -> TokenStream {
114 todo!()
115}
116
117fn fail(msg: impl Into<String>) -> ! {
118 let msg = msg.into();
119
120 panic!("Failed to run accursed-unutterable-type-id proc macro with error '{msg}'. \
121 Set the `ACCURSED_UNUTTERABLE_TYPE_ID_DIR` environment variable to a file path of your choice to fix this issue. \
122 cargo clean could help as well.");
123}