#![doc(html_root_url = "https://docs.rs/ghost/0.1.13")]
#![allow(
clippy::doc_markdown,
// https://github.com/rust-lang/rust-clippy/issues/8538
clippy::iter_with_drain,
clippy::needless_doctest_main,
clippy::needless_pass_by_value,
clippy::too_many_lines
)]
extern crate proc_macro;
mod derive;
mod parse;
mod variance;
mod visibility;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::parse::Nothing;
use syn::{parse_macro_input, Error, GenericParam, Token};
use crate::parse::UnitStruct;
#[proc_macro_attribute]
pub fn phantom(args: TokenStream, input: TokenStream) -> TokenStream {
parse_macro_input!(args as Nothing);
let input = parse_macro_input!(input as UnitStruct);
let ident = &input.ident;
let call_site = Span::call_site();
let void_namespace = Ident::new(&format!("__void_{}", ident), call_site);
let value_namespace = Ident::new(&format!("__value_{}", ident), call_site);
let vis = &input.vis;
let vis_super = visibility::vis_super(vis);
let (derives, attrs) = match derive::expand(&input.attrs, &input) {
Ok(split) => split,
Err(err) => return err.to_compile_error().into(),
};
let void = Ident::new(
if ident == "Void" { "__Void" } else { "Void" },
Span::call_site(),
);
let type_param = Ident::new(
if ident == "TypeParam" {
"__TypeParam"
} else {
"TypeParam"
},
Span::call_site(),
);
let mut generics = input.generics;
let where_clause = generics.where_clause.take();
let mut impl_generics = Vec::new();
let mut ty_generics = Vec::new();
let mut phantoms = Vec::new();
for param in &mut generics.params {
match param {
GenericParam::Type(param) => {
let ident = ¶m.ident;
let elem = quote!(#ident);
impl_generics.push(quote!(#ident: ?::core::marker::Sized));
ty_generics.push(quote!(#ident));
phantoms.push(variance::apply(param, elem, &type_param));
}
GenericParam::Lifetime(param) => {
let lifetime = ¶m.lifetime;
let elem = quote!(&#lifetime ());
impl_generics.push(quote!(#lifetime));
ty_generics.push(quote!(#lifetime));
phantoms.push(variance::apply(param, elem, &type_param));
}
GenericParam::Const(param) => {
let msg = "const generics are not supported";
let err = Error::new_spanned(param, msg);
return err.to_compile_error().into();
}
}
}
let impl_generics = &impl_generics;
let ty_generics = &ty_generics;
let enum_token = Token;
let struct_token = input.struct_token;
TokenStream::from(quote! {
#[cfg(not(doc))]
mod #void_namespace {
enum #void {}
impl ::core::marker::Copy for #void {}
#[allow(clippy::expl_impl_clone_on_copy)]
impl ::core::clone::Clone for #void {
fn clone(&self) -> Self {
*self
}
}
#[repr(C, packed)]
struct #type_param<T: ?::core::marker::Sized>([*const T; 0]);
impl<T: ?::core::marker::Sized> ::core::marker::Copy for #type_param<T> {}
#[allow(clippy::expl_impl_clone_on_copy)]
impl<T: ?::core::marker::Sized> ::core::clone::Clone for #type_param<T> {
fn clone(&self) -> Self {
*self
}
}
unsafe impl<T: ?::core::marker::Sized + ::core::marker::Send> ::core::marker::Send for #type_param<T> {}
unsafe impl<T: ?::core::marker::Sized + ::core::marker::Sync> ::core::marker::Sync for #type_param<T> {}
#[allow(non_camel_case_types)]
#vis_super struct #ident <#(#impl_generics),*> (
#(
self::#type_param<#phantoms>,
)*
self::#void,
);
impl <#(#impl_generics),*> ::core::marker::Copy
for #ident <#(#ty_generics),*> {}
#[allow(clippy::expl_impl_clone_on_copy)]
impl <#(#impl_generics),*> ::core::clone::Clone
for #ident <#(#ty_generics),*> {
fn clone(&self) -> Self {
*self
}
}
}
#[cfg(not(doc))]
mod #value_namespace {
#vis_super use super::#ident::#ident;
}
#[cfg(not(doc))]
#(#attrs)*
#vis #enum_token #ident #generics #where_clause {
__Phantom(#void_namespace::#ident <#(#ty_generics),*>),
#ident,
}
#[cfg(not(doc))]
#[doc(hidden)]
#vis use self::#value_namespace::*;
#[cfg(doc)]
#(#attrs)*
#vis #struct_token #ident #generics #where_clause;
#derives
})
}