use proc_macro2::{Group, TokenTree};
use quote::{format_ident, quote, quote_spanned};
use super::*;
pub(crate) struct TransparentInfo<'a> {
pub inner_field_type: Option<&'a TokenStream>,
pub inner_is_opaque: bool,
pub is_zst: bool,
}
pub(crate) struct TraitSources<'a> {
pub declared_traits: Option<&'a DeclaredTraits>,
pub facet_default: bool,
}
impl<'a> TraitSources<'a> {
pub fn from_attrs(attrs: &'a PAttrs) -> Self {
Self {
declared_traits: attrs.declared_traits.as_ref(),
facet_default: attrs.has_builtin("default"),
}
}
fn has_declared(&self, check: impl FnOnce(&DeclaredTraits) -> bool) -> bool {
self.declared_traits.is_some_and(check)
}
const fn should_auto(&self) -> bool {
self.declared_traits.is_none()
}
}
fn lifetimes_to_static(tokens: &TokenStream) -> TokenStream {
fn rewrite(stream: TokenStream) -> TokenStream {
let mut out = TokenStream::new();
let mut iter = stream.into_iter().peekable();
while let Some(tt) = iter.next() {
match tt {
TokenTree::Group(group) => {
let mut rewritten = Group::new(group.delimiter(), rewrite(group.stream()));
rewritten.set_span(group.span());
out.extend([TokenTree::Group(rewritten)]);
}
TokenTree::Punct(punct) if punct.as_char() == '\'' => {
if matches!(iter.peek(), Some(TokenTree::Ident(_))) {
iter.next();
out.extend(quote! { 'static });
} else {
out.extend([TokenTree::Punct(punct)]);
}
}
other => out.extend([other]),
}
}
out
}
rewrite(tokens.clone())
}
pub(crate) fn phantom_attr_use(
attr: &PFacetAttr,
facet_crate: &TokenStream,
) -> Option<TokenStream> {
if !attr.is_builtin() {
return None;
}
let binding = attr.key_str();
let variant_name = RenameRule::PascalCase.apply(&binding);
let variant_ident = proc_macro2::Ident::new(&variant_name, attr.key.span());
Some(quote! { { use #facet_crate::builtin::Attr::#variant_ident as _; } })
}
pub(crate) fn collect_trailing_shape_checks(
fields: &[PStructField],
facet_crate: &TokenStream,
) -> std::result::Result<Vec<TokenStream>, TokenStream> {
let mut trailing_shape_checks = Vec::new();
for (idx, field) in fields.iter().enumerate() {
for attr in &field.attrs.facet {
if !attr.is_builtin() || attr.key != "trailing" {
continue;
}
if !attr.args.is_empty() {
let span = attr.key.span();
return Err(quote_spanned! { span =>
compile_error!("`#[facet(trailing)]` does not accept arguments");
});
}
if field.attrs.has_builtin("flatten") {
let span = attr.key.span();
return Err(quote_spanned! { span =>
compile_error!("`#[facet(trailing)]` is not supported on flattened fields");
});
}
if idx + 1 != fields.len() {
let span = attr.key.span();
return Err(quote_spanned! { span =>
compile_error!("`#[facet(trailing)]` requires this field to be the last field in its container");
});
}
if !field.attrs.has_builtin("opaque") {
let span = attr.key.span();
let field_type = &field.ty;
trailing_shape_checks.push(quote_spanned! { span =>
if !<#field_type as #facet_crate::Facet<'ʄ>>::SHAPE.has_opaque_adapter() {
panic!("`#[facet(trailing)]` requires an opaque field (`#[facet(opaque)]`) or a field type with `#[facet(opaque = ...)]`");
}
});
}
}
}
Ok(trailing_shape_checks)
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn gen_vtable(
facet_crate: &TokenStream,
type_name_fn: &TokenStream,
sources: &TraitSources<'_>,
transparent: Option<&TransparentInfo<'_>>,
struct_type: &TokenStream,
invariants_fn: Option<&TokenStream>,
use_inherent_borrow_inner: bool,
try_from_fn_direct: Option<&TokenStream>,
_try_from_fn_indirect: Option<&TokenStream>,
_has_type_or_const_generics: bool,
has_any_generics: bool,
) -> TokenStream {
gen_vtable_direct(
facet_crate,
type_name_fn,
sources,
transparent,
struct_type,
invariants_fn,
use_inherent_borrow_inner,
try_from_fn_direct,
has_any_generics,
)
}
#[allow(clippy::too_many_arguments)]
fn gen_vtable_direct(
facet_crate: &TokenStream,
_type_name_fn: &TokenStream,
sources: &TraitSources<'_>,
transparent: Option<&TransparentInfo<'_>>,
struct_type: &TokenStream,
invariants_fn: Option<&TokenStream>,
use_inherent_borrow_inner: bool,
try_from_fn: Option<&TokenStream>,
has_any_generics: bool,
) -> TokenStream {
let can_auto_detect = sources.should_auto() && !has_any_generics;
let display_call = if sources.has_declared(|d| d.display) {
quote! { .display(<Self as ::core::fmt::Display>::fmt) }
} else if can_auto_detect {
quote! {
.display_opt(
if #facet_crate::𝟋::impls!(Self: ::core::fmt::Display) {
𝟋Some({
fn __display(v: &#struct_type, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
(&&#facet_crate::𝟋::Spez(v)).spez_display(f)
}
__display
})
} else {
𝟋None
}
)
}
} else {
quote! {}
};
let debug_call = if sources.has_declared(|d| d.debug) {
quote! { .debug(<Self as ::core::fmt::Debug>::fmt) }
} else if can_auto_detect {
quote! {
.debug_opt(
if #facet_crate::𝟋::impls!(Self: ::core::fmt::Debug) {
𝟋Some({
fn __debug(v: &#struct_type, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
(&&#facet_crate::𝟋::Spez(v)).spez_debug(f)
}
__debug
})
} else {
𝟋None
}
)
}
} else {
quote! {}
};
let partial_eq_call = if sources.has_declared(|d| d.partial_eq) {
quote! { .partial_eq(<Self as ::core::cmp::PartialEq>::eq) }
} else if can_auto_detect {
quote! {
.partial_eq_opt(
if #facet_crate::𝟋::impls!(Self: ::core::cmp::PartialEq) {
𝟋Some({
fn __partial_eq(a: &#struct_type, b: &#struct_type) -> bool {
(&&#facet_crate::𝟋::Spez(a)).spez_partial_eq(&&#facet_crate::𝟋::Spez(b))
}
__partial_eq
})
} else {
𝟋None
}
)
}
} else {
quote! {}
};
let partial_ord_call = if sources.has_declared(|d| d.partial_ord) {
quote! { .partial_cmp(<Self as ::core::cmp::PartialOrd>::partial_cmp) }
} else if can_auto_detect {
quote! {
.partial_cmp_opt(
if #facet_crate::𝟋::impls!(Self: ::core::cmp::PartialOrd) {
𝟋Some({
fn __partial_cmp(a: &#struct_type, b: &#struct_type) -> ::core::option::Option<::core::cmp::Ordering> {
(&&#facet_crate::𝟋::Spez(a)).spez_partial_cmp(&&#facet_crate::𝟋::Spez(b))
}
__partial_cmp
})
} else {
𝟋None
}
)
}
} else {
quote! {}
};
let ord_call = if sources.has_declared(|d| d.ord) {
quote! { .cmp(<Self as ::core::cmp::Ord>::cmp) }
} else if can_auto_detect {
quote! {
.cmp_opt(
if #facet_crate::𝟋::impls!(Self: ::core::cmp::Ord) {
𝟋Some({
fn __cmp(a: &#struct_type, b: &#struct_type) -> ::core::cmp::Ordering {
(&&#facet_crate::𝟋::Spez(a)).spez_cmp(&&#facet_crate::𝟋::Spez(b))
}
__cmp
})
} else {
𝟋None
}
)
}
} else {
quote! {}
};
let hash_call = if sources.has_declared(|d| d.hash) {
quote! { .hash(<Self as ::core::hash::Hash>::hash::<#facet_crate::HashProxy>) }
} else if can_auto_detect {
quote! {
.hash_opt(
if #facet_crate::𝟋::impls!(Self: ::core::hash::Hash) {
𝟋Some({
fn __hash(v: &#struct_type, h: &mut #facet_crate::HashProxy<'static>) {
(&&#facet_crate::𝟋::Spez(v)).spez_hash(h)
}
__hash
})
} else {
𝟋None
}
)
}
} else {
quote! {}
};
let try_borrow_inner_call = if let Some(info) = transparent {
if info.inner_is_opaque {
quote! {}
} else if info.is_zst {
quote! {}
} else if info.inner_field_type.is_some() {
if use_inherent_borrow_inner {
quote! {
.try_borrow_inner(<Self>::__facet_try_borrow_inner)
}
} else {
quote! {
.try_borrow_inner({
unsafe fn __try_borrow_inner(src: *const #struct_type) -> ::core::result::Result<#facet_crate::PtrMut, #facet_crate::𝟋::𝟋Str> {
let wrapper_ptr = src as *mut #struct_type;
let inner_ptr: *mut _ = unsafe { &raw mut (*wrapper_ptr).0 };
𝟋Ok(#facet_crate::PtrMut::new(inner_ptr as *mut u8))
}
__try_borrow_inner
})
}
}
} else {
quote! {}
}
} else {
quote! {}
};
let invariants_call = if let Some(inv_fn) = invariants_fn {
quote! { .invariants(#inv_fn) }
} else {
quote! {}
};
let try_from_call = if let Some(try_from_fn) = try_from_fn {
quote! { .try_from(#try_from_fn) }
} else {
quote! {}
};
quote! {
𝟋VtE::Direct(&const {
𝟋VtD::builder_for::<Self>()
#display_call
#debug_call
#partial_eq_call
#partial_ord_call
#ord_call
#hash_call
#invariants_call
#try_borrow_inner_call
#try_from_call
.build()
})
}
}
pub(crate) fn gen_type_ops(
facet_crate: &TokenStream,
sources: &TraitSources<'_>,
struct_type: &TokenStream,
has_type_or_const_generics: bool,
has_any_generics: bool,
truthy_fn: Option<&TokenStream>,
) -> Option<TokenStream> {
if has_type_or_const_generics {
return gen_type_ops_indirect(facet_crate, sources, struct_type, truthy_fn);
}
gen_type_ops_direct(
facet_crate,
sources,
struct_type,
truthy_fn,
has_any_generics,
)
}
fn gen_type_ops_direct(
facet_crate: &TokenStream,
sources: &TraitSources<'_>,
struct_type: &TokenStream,
truthy_fn: Option<&TokenStream>,
has_any_generics: bool,
) -> Option<TokenStream> {
let can_auto_detect = sources.should_auto() && !has_any_generics;
let has_default = sources.has_declared(|d| d.default) || sources.facet_default;
let has_clone = sources.has_declared(|d| d.clone);
let default_field = if has_default {
quote! {
default_in_place: 𝟋Some(
unsafe { 𝟋transmute(#facet_crate::𝟋::𝟋default_for::<Self>() as unsafe fn(*mut Self)) }
),
}
} else if can_auto_detect {
quote! {
default_in_place: if #facet_crate::𝟋::impls!(Self: ::core::default::Default) {
𝟋Some({
unsafe fn __default_in_place(ptr: *mut ()) {
let target = #facet_crate::PtrUninit::new(ptr as *mut u8);
unsafe { (&&&#facet_crate::𝟋::SpezEmpty::<#struct_type>::SPEZ).spez_default_in_place(target) };
}
__default_in_place
})
} else {
𝟋None
},
}
} else {
quote! { default_in_place: 𝟋None, }
};
let clone_field = if has_clone {
quote! {
clone_into: 𝟋Some(
unsafe { 𝟋transmute(#facet_crate::𝟋::𝟋clone_for::<Self>() as unsafe fn(*const Self, *mut Self)) }
),
}
} else if can_auto_detect {
quote! {
clone_into: if #facet_crate::𝟋::impls!(Self: ::core::clone::Clone) {
𝟋Some({
unsafe fn __clone_into(src: *const (), dst: *mut ()) {
let src_ref: &#struct_type = unsafe { &*(src as *const #struct_type) };
let target = #facet_crate::PtrUninit::new(dst as *mut u8);
unsafe { (&&&#facet_crate::𝟋::Spez(src_ref)).spez_clone_into(target) };
}
__clone_into
})
} else {
𝟋None
},
}
} else {
quote! { clone_into: 𝟋None, }
};
let truthy_field = if let Some(truthy) = truthy_fn {
quote! {
is_truthy: 𝟋Some({
unsafe fn __truthy(value: #facet_crate::PtrConst) -> bool {
let this: &#struct_type = unsafe { value.get::<#struct_type>() };
#truthy(this)
}
__truthy
}),
}
} else {
quote! { is_truthy: 𝟋None, }
};
Some(quote! {
#facet_crate::TypeOps::Direct(&const {
#facet_crate::TypeOpsDirect {
drop_in_place: unsafe { 𝟋transmute(𝟋drop_in_place::<Self> as unsafe fn(*mut Self)) },
#default_field
#clone_field
#truthy_field
}
})
})
}
fn gen_type_ops_indirect(
facet_crate: &TokenStream,
sources: &TraitSources<'_>,
_struct_type: &TokenStream,
truthy_fn: Option<&TokenStream>,
) -> Option<TokenStream> {
let default_field = if sources.has_declared(|d| d.default) || sources.facet_default {
quote! {
default_in_place: 𝟋Some(#facet_crate::𝟋::𝟋indirect_default_for::<Self>()),
}
} else {
quote! { default_in_place: 𝟋None, }
};
let clone_field = if sources.has_declared(|d| d.clone) {
quote! {
clone_into: 𝟋Some(#facet_crate::𝟋::𝟋indirect_clone_for::<Self>()),
}
} else {
quote! { clone_into: 𝟋None, }
};
let truthy_field = if let Some(truthy) = truthy_fn {
quote! {
is_truthy: 𝟋Some({
unsafe fn __truthy(value: #facet_crate::PtrConst) -> bool {
let this: &Self = unsafe { value.get::<Self>() };
#truthy(this)
}
__truthy
}),
}
} else {
quote! { is_truthy: 𝟋None, }
};
Some(quote! {
#facet_crate::TypeOps::Indirect(&const {
#facet_crate::TypeOpsIndirect {
drop_in_place: #facet_crate::𝟋::𝟋indirect_drop_for::<Self>(),
#default_field
#clone_field
#truthy_field
}
})
})
}
pub(crate) fn gen_trait_bounds(
declared: Option<&DeclaredTraits>,
facet_default: bool,
) -> Option<TokenStream> {
let mut bounds = Vec::new();
if let Some(declared) = declared {
if declared.display {
bounds.push(quote! { core::fmt::Display });
}
if declared.debug {
bounds.push(quote! { core::fmt::Debug });
}
if declared.clone {
bounds.push(quote! { core::clone::Clone });
}
if declared.copy {
bounds.push(quote! { core::marker::Copy });
}
if declared.partial_eq {
bounds.push(quote! { core::cmp::PartialEq });
}
if declared.eq {
bounds.push(quote! { core::cmp::Eq });
}
if declared.partial_ord {
bounds.push(quote! { core::cmp::PartialOrd });
}
if declared.ord {
bounds.push(quote! { core::cmp::Ord });
}
if declared.hash {
bounds.push(quote! { core::hash::Hash });
}
if declared.default {
bounds.push(quote! { core::default::Default });
}
if declared.send {
bounds.push(quote! { core::marker::Send });
}
if declared.sync {
bounds.push(quote! { core::marker::Sync });
}
if declared.unpin {
bounds.push(quote! { core::marker::Unpin });
}
}
if facet_default && !declared.is_some_and(|d| d.default) {
bounds.push(quote! { core::default::Default });
}
if bounds.is_empty() {
None
} else {
Some(quote! { #(#bounds)+* })
}
}
pub(crate) fn gen_field_from_pfield(
field: &PStructField,
struct_name: &Ident,
bgp: &BoundedGenericParams,
base_offset: Option<TokenStream>,
facet_crate: &TokenStream,
skip_all_unless_truthy: bool,
needs_const_dispatch: bool,
) -> TokenStream {
let field_name = &field.name.original;
let field_name_raw = &field.name.raw;
let field_type = &field.ty;
let field_type_static = lifetimes_to_static(field_type);
let bgp_without_bounds = bgp.display_without_bounds();
#[cfg(feature = "doc")]
let doc_lines: Vec<String> = field
.attrs
.doc
.iter()
.map(|doc| doc.as_str().replace("\\\"", "\""))
.collect();
let is_recursive = field.attrs.has_builtin("recursive_type");
let shape_expr = if field.attrs.has_builtin("opaque") {
quote! { <#facet_crate::OpaqueBorrow<'_, #field_type> as 𝟋Fct>::SHAPE }
} else {
quote! { <#field_type as 𝟋Fct>::SHAPE }
};
enum DefaultKind {
FromTrait,
Custom(TokenStream),
}
let mut flags: Vec<TokenStream> = Vec::new();
let mut alias_value: Option<TokenStream> = None;
let mut default_value: Option<DefaultKind> = None;
let mut skip_serializing_if_value: Option<TokenStream> = None;
let mut invariants_value: Option<TokenStream> = None;
let mut proxy_value: Option<TokenStream> = None;
let mut format_proxies_list: Vec<TokenStream> = Vec::new();
let mut metadata_value: Option<String> = None;
let mut attribute_list: Vec<TokenStream> = Vec::new();
let field_orig_ident_span = match &field.name.raw {
facet_macro_parse::IdentOrLiteral::Ident(ident) => ident.span(),
facet_macro_parse::IdentOrLiteral::Literal(_) => {
field.attrs.get_builtin_span("default").unwrap_or_else(|| {
field
.ty
.clone()
.into_iter()
.next()
.map(|t| t.span())
.unwrap_or_else(proc_macro2::Span::call_site)
})
}
};
let mut want_truthy_skip = skip_all_unless_truthy;
for attr in &field.attrs.facet {
if attr.is_builtin() {
let key = attr.key_str();
match key.as_str() {
"sensitive" => {
flags.push(quote! { 𝟋FF::SENSITIVE });
}
"flatten" => {
flags.push(quote! { 𝟋FF::FLATTEN });
}
"child" => {
flags.push(quote! { 𝟋FF::CHILD });
}
"skip" => {
flags.push(quote! { 𝟋FF::SKIP });
}
"skip_serializing" => {
flags.push(quote! { 𝟋FF::SKIP_SERIALIZING });
}
"skip_deserializing" => {
flags.push(quote! { 𝟋FF::SKIP_DESERIALIZING });
}
"default" => {
let args = &attr.args;
if args.is_empty() {
default_value = Some(DefaultKind::FromTrait);
} else {
default_value = Some(DefaultKind::Custom(args.clone()));
}
}
"recursive_type" => {
flags.push(quote! { 𝟋FF::RECURSIVE_TYPE });
}
"metadata" => {
let args = &attr.args;
let args_str = args.to_string();
let kind_str = args_str.trim_start_matches('=').trim().trim_matches('"');
metadata_value = Some(kind_str.to_string());
}
"alias" => {
let args = &attr.args;
alias_value = Some(quote! { #args });
}
"skip_serializing_if" => {
let fn_name = &attr.args;
skip_serializing_if_value = Some(quote! {
{
unsafe fn __skip_ser_if_wrapper(ptr: #facet_crate::PtrConst) -> bool {
let value: &#field_type = unsafe { ptr.get() };
#fn_name(value)
}
__skip_ser_if_wrapper
}
});
}
"skip_unless_truthy" => {
want_truthy_skip = true;
}
"invariants" => {
let fn_name = &attr.args;
invariants_value = Some(quote! { #fn_name });
}
"proxy" => {
let proxy_type = &attr.args;
let is_opaque = field.attrs.has_builtin("opaque");
let convert_out_impl = if is_opaque {
quote! {
let opaque_ref: &#facet_crate::OpaqueBorrow<'_, #field_type> = field_ptr.get();
let field_ref: &#field_type = &opaque_ref.0;
match <#proxy_type as ::core::convert::TryFrom<&#field_type>>::try_from(field_ref) {
𝟋Ok(proxy) => 𝟋Ok(proxy_ptr.put(proxy)),
𝟋Err(e) => 𝟋Err(__alloc::string::ToString::to_string(&e)),
}
}
} else {
quote! {
let field_ref: &#field_type = field_ptr.get();
match <#proxy_type as ::core::convert::TryFrom<&#field_type>>::try_from(field_ref) {
𝟋Ok(proxy) => 𝟋Ok(proxy_ptr.put(proxy)),
𝟋Err(e) => 𝟋Err(__alloc::string::ToString::to_string(&e)),
}
}
};
proxy_value = Some(quote! {
&const {
extern crate alloc as __alloc;
unsafe fn __proxy_convert_in(
proxy_ptr: #facet_crate::PtrConst,
field_ptr: #facet_crate::PtrUninit,
) -> ::core::result::Result<#facet_crate::PtrMut, __alloc::string::String> {
let proxy: #proxy_type = proxy_ptr.read();
match <#field_type as ::core::convert::TryFrom<#proxy_type>>::try_from(proxy) {
𝟋Ok(value) => 𝟋Ok(field_ptr.put(value)),
𝟋Err(e) => 𝟋Err(__alloc::string::ToString::to_string(&e)),
}
}
unsafe fn __proxy_convert_out(
field_ptr: #facet_crate::PtrConst,
proxy_ptr: #facet_crate::PtrUninit,
) -> ::core::result::Result<#facet_crate::PtrMut, __alloc::string::String> {
#convert_out_impl
}
#facet_crate::ProxyDef {
shape: <#proxy_type as #facet_crate::Facet>::SHAPE,
convert_in: __proxy_convert_in,
convert_out: __proxy_convert_out,
}
}
});
}
_ => {
let ext_attr = emit_attr_for_field(
attr,
field_name_raw,
field_type,
facet_crate,
needs_const_dispatch,
);
attribute_list.push(quote! { #ext_attr });
}
}
} else {
let key = attr.key_str();
let ns = attr.ns.as_ref().expect("namespaced attr should have ns");
let ns_str = ns.to_string();
if key == "proxy" {
let proxy_type = &attr.args;
let is_opaque = field.attrs.has_builtin("opaque");
let convert_out_impl = if is_opaque {
quote! {
let opaque_ref: &#facet_crate::OpaqueBorrow<'_, #field_type> = field_ptr.get();
let field_ref: &#field_type = &opaque_ref.0;
match <#proxy_type as ::core::convert::TryFrom<&#field_type>>::try_from(field_ref) {
𝟋Ok(proxy) => 𝟋Ok(proxy_ptr.put(proxy)),
𝟋Err(e) => 𝟋Err(__alloc::string::ToString::to_string(&e)),
}
}
} else {
quote! {
let field_ref: &#field_type = field_ptr.get();
match <#proxy_type as ::core::convert::TryFrom<&#field_type>>::try_from(field_ref) {
𝟋Ok(proxy) => 𝟋Ok(proxy_ptr.put(proxy)),
𝟋Err(e) => 𝟋Err(__alloc::string::ToString::to_string(&e)),
}
}
};
let format_proxy = quote! {
#facet_crate::FormatProxy {
format: #ns_str,
proxy: &const {
extern crate alloc as __alloc;
unsafe fn __proxy_convert_in(
proxy_ptr: #facet_crate::PtrConst,
field_ptr: #facet_crate::PtrUninit,
) -> ::core::result::Result<#facet_crate::PtrMut, __alloc::string::String> {
let proxy: #proxy_type = proxy_ptr.read();
match <#field_type as ::core::convert::TryFrom<#proxy_type>>::try_from(proxy) {
𝟋Ok(value) => 𝟋Ok(field_ptr.put(value)),
𝟋Err(e) => 𝟋Err(__alloc::string::ToString::to_string(&e)),
}
}
unsafe fn __proxy_convert_out(
field_ptr: #facet_crate::PtrConst,
proxy_ptr: #facet_crate::PtrUninit,
) -> ::core::result::Result<#facet_crate::PtrMut, __alloc::string::String> {
#convert_out_impl
}
#facet_crate::ProxyDef {
shape: <#proxy_type as #facet_crate::Facet>::SHAPE,
convert_in: __proxy_convert_in,
convert_out: __proxy_convert_out,
}
},
}
};
format_proxies_list.push(format_proxy);
} else {
let ext_attr = emit_attr_for_field(
attr,
field_name_raw,
field_type,
facet_crate,
needs_const_dispatch,
);
attribute_list.push(quote! { #ext_attr });
}
}
}
if skip_serializing_if_value.is_none() && want_truthy_skip {
skip_serializing_if_value = Some(quote! {
{
unsafe fn __truthiness_with_fallback(
shape: &'static #facet_crate::Shape,
ptr: #facet_crate::PtrConst,
) -> Option<bool> {
if let Some(truthy) = shape.truthiness_fn() {
return Some(unsafe { truthy(ptr) });
}
if let #facet_crate::Def::Pointer(ptr_def) = shape.def {
if let (Some(inner_shape), Some(borrow)) =
(ptr_def.pointee(), ptr_def.vtable.borrow_fn)
{
let inner_ptr = unsafe { borrow(ptr) };
return __truthiness_with_fallback(inner_shape, inner_ptr);
}
}
if let #facet_crate::Type::User(#facet_crate::UserType::Struct(st)) = shape.ty
&& matches!(st.kind, #facet_crate::StructKind::Tuple)
{
for field in st.fields {
if field.shape.get().layout.sized_layout().is_err() {
continue;
}
let field_ptr = #facet_crate::PtrConst::new(unsafe {
ptr.as_byte_ptr().add(field.offset)
} as *const ());
if let Some(true) = __truthiness_with_fallback(field.shape.get(), field_ptr) {
return Some(true);
}
}
return Some(false);
}
None
}
unsafe fn __skip_unless_truthy<T: #facet_crate::Facet<'static>>(
ptr: #facet_crate::PtrConst,
) -> bool {
let shape = <T as #facet_crate::Facet>::SHAPE;
match __truthiness_with_fallback(shape, ptr) {
Some(result) => !result,
None => false,
}
}
__skip_unless_truthy::<#field_type_static>
}
});
}
let maybe_attributes = if attribute_list.is_empty() {
quote! { &[] }
} else {
quote! { &const {[#(#attribute_list),*]} }
};
#[cfg(feature = "doc")]
let maybe_field_doc = if doc_lines.is_empty() || crate::is_no_doc() {
quote! { &[] }
} else {
quote! { &[#(#doc_lines),*] }
};
#[cfg(not(feature = "doc"))]
let maybe_field_doc = quote! { &[] };
let final_offset = match base_offset {
Some(base) => {
quote! { #base + ::core::mem::offset_of!(#struct_name #bgp_without_bounds, #field_name_raw) }
}
None => {
quote! { ::core::mem::offset_of!(#struct_name #bgp_without_bounds, #field_name_raw) }
}
};
let is_opaque = field.attrs.has_builtin("opaque");
let shape_ref_expr = if is_recursive {
quote! { 𝟋ShpR(|| #shape_expr) }
} else if is_opaque {
quote! { 𝟋ShpR(𝟋shp::<#facet_crate::OpaqueBorrow<'_, #field_type>>) }
} else {
quote! { 𝟋ShpR(𝟋shp::<#field_type>) }
};
let flags_expr = if flags.is_empty() {
quote! { 𝟋NOFL }
} else if flags.len() == 1 {
let f = &flags[0];
quote! { #f }
} else {
let first = &flags[0];
let rest = &flags[1..];
quote! { #first #(.union(#rest))* }
};
let rename_expr = match &field.name.rename {
Some(rename) => quote! { 𝟋Some(#rename) },
None => quote! { 𝟋None },
};
let alias_expr = match &alias_value {
Some(alias) => quote! { 𝟋Some(#alias) },
None => quote! { 𝟋None },
};
let default_expr = match &default_value {
Some(DefaultKind::FromTrait) => {
if field.attrs.has_builtin("opaque") {
let type_str = field_type.to_token_stream().to_string();
let is_option = type_str.starts_with("Option") || type_str.contains(":: Option");
if is_option {
quote! {
𝟋Some(𝟋DS::Custom({
unsafe fn __default(__ptr: #facet_crate::PtrUninit) -> #facet_crate::PtrMut {
__ptr.put(<#field_type>::None)
}
__default
}))
}
} else {
quote! {
𝟋Some(𝟋DS::Custom({
unsafe fn __default(__ptr: #facet_crate::PtrUninit) -> #facet_crate::PtrMut {
__ptr.put(<#field_type as ::core::default::Default>::default())
}
__default
}))
}
}
} else {
quote! { 𝟋Some(𝟋DS::FromTrait) }
}
}
Some(DefaultKind::Custom(expr)) => {
let panic_failed = quote_spanned! { field_orig_ident_span =>
panic!("Field '{}' expects {}, but default function returns {}: {}",
#field_name,
__dst_shape,
__src_shape,
e
)
};
let panic_unsupported = quote_spanned! { field_orig_ident_span =>
panic!("Field '{}' expects {}, but default function returns {}",
#field_name,
__dst_shape,
__src_shape
)
};
quote! {
𝟋Some(𝟋DS::Custom({
#[allow(clippy::forget_non_drop)]
unsafe fn __default(__ptr: #facet_crate::PtrUninit) -> #facet_crate::PtrMut {
#[inline]
fn __shape_of_val<'a, T: #facet_crate::Facet<'a>>(_: &T) -> &'static #facet_crate::Shape {
T::SHAPE
}
let __src_value = #expr;
let __src_shape = __shape_of_val(&__src_value);
let __dst_shape = <#field_type as #facet_crate::Facet>::SHAPE;
if __src_shape.id == __dst_shape.id {
return unsafe { __ptr.put(__src_value) };
}
let __src_ptr = #facet_crate::PtrConst::new(
&__src_value as *const _ as *const u8
);
match unsafe { __dst_shape.call_try_from(__src_shape, __src_ptr, __ptr) } {
Some(#facet_crate::TryFromOutcome::Converted) => {
𝟋forget(__src_value);
unsafe { __ptr.assume_init() }
},
Some(#facet_crate::TryFromOutcome::Failed(e)) => {
𝟋forget(__src_value);
#panic_failed
},
Some(#facet_crate::TryFromOutcome::Unsupported) => {
#panic_unsupported
},
None => {
#panic_unsupported
},
}
}
__default
}))
}
}
None => quote! { 𝟋None },
};
let skip_ser_if_expr = match &skip_serializing_if_value {
Some(skip_ser_if) => quote! { 𝟋Some(#skip_ser_if) },
None => quote! { 𝟋None },
};
let invariants_expr = match &invariants_value {
Some(inv) => quote! { 𝟋Some(#inv) },
None => quote! { 𝟋None },
};
let proxy_expr = match &proxy_value {
Some(proxy) => quote! { 𝟋Some(#proxy) },
None => quote! { 𝟋None },
};
let format_proxies_expr = if format_proxies_list.is_empty() {
quote! { &[] }
} else {
quote! { &const {[#(#format_proxies_list),*]} }
};
let metadata_expr = match &metadata_value {
Some(kind) => quote! { 𝟋Some(#kind) },
None => quote! { 𝟋None },
};
quote! {
𝟋Fld {
name: #field_name,
shape: #shape_ref_expr,
offset: #final_offset,
flags: #flags_expr,
rename: #rename_expr,
alias: #alias_expr,
attributes: #maybe_attributes,
doc: #maybe_field_doc,
default: #default_expr,
skip_serializing_if: #skip_ser_if_expr,
invariants: #invariants_expr,
proxy: #proxy_expr,
format_proxies: #format_proxies_expr,
metadata: #metadata_expr,
}
}
}
pub(crate) fn process_struct(parsed: Struct) -> TokenStream {
let ps = PStruct::parse(&parsed);
if !ps.container.attrs.errors.is_empty() {
let errors = ps.container.attrs.errors.iter().map(|e| {
let msg = &e.message;
let span = e.span;
quote_spanned! { span => compile_error!(#msg); }
});
return quote! { #(#errors)* };
}
let has_pod = ps.container.attrs.has_builtin("pod");
let has_invariants = ps
.container
.attrs
.facet
.iter()
.any(|a| a.is_builtin() && a.key_str() == "invariants");
if has_pod && has_invariants {
let pod_span = ps
.container
.attrs
.facet
.iter()
.find(|a| a.is_builtin() && a.key_str() == "pod")
.map(|a| a.key.span())
.unwrap_or_else(proc_macro2::Span::call_site);
return quote_spanned! { pod_span =>
compile_error!("#[facet(pod)] and #[facet(invariants = ...)] are mutually exclusive. \
POD types by definition have no invariants.");
};
}
let has_metadata_container = ps.container.attrs.has_builtin("metadata_container");
if has_metadata_container {
let all_fields: &[PStructField] = match &ps.kind {
PStructKind::Struct { fields } => fields,
PStructKind::TupleStruct { fields } => fields,
PStructKind::UnitStruct => &[],
};
let metadata_fields: Vec<_> = all_fields
.iter()
.filter(|f| {
f.attrs
.facet
.iter()
.any(|a| a.is_builtin() && a.key_str() == "metadata")
})
.collect();
let non_metadata_fields: Vec<_> = all_fields
.iter()
.filter(|f| {
!f.attrs
.facet
.iter()
.any(|a| a.is_builtin() && a.key_str() == "metadata")
})
.collect();
if non_metadata_fields.len() != 1 {
let mc_span = ps
.container
.attrs
.facet
.iter()
.find(|a| a.is_builtin() && a.key_str() == "metadata_container")
.map(|a| a.key.span())
.unwrap_or_else(proc_macro2::Span::call_site);
return quote_spanned! { mc_span =>
compile_error!("#[facet(metadata_container)] requires exactly one non-metadata field (the value field)");
};
}
if metadata_fields.is_empty() {
let mc_span = ps
.container
.attrs
.facet
.iter()
.find(|a| a.is_builtin() && a.key_str() == "metadata_container")
.map(|a| a.key.span())
.unwrap_or_else(proc_macro2::Span::call_site);
return quote_spanned! { mc_span =>
compile_error!("#[facet(metadata_container)] requires at least one field with #[facet(metadata = \"...\")]");
};
}
let mut seen_kinds = std::collections::HashSet::new();
for field in &metadata_fields {
let kind = field.attrs.facet.iter().find_map(|a| {
if a.is_builtin() && a.key_str() == "metadata" {
let args_str = a.args.to_string();
let kind_str = args_str.trim_start_matches('=').trim().trim_matches('"');
Some(kind_str.to_string())
} else {
None
}
});
if let Some(kind) = kind
&& !seen_kinds.insert(kind.clone())
{
let mc_span = ps
.container
.attrs
.facet
.iter()
.find(|a| a.is_builtin() && a.key_str() == "metadata_container")
.map(|a| a.key.span())
.unwrap_or_else(proc_macro2::Span::call_site);
let msg = format!(
"#[facet(metadata_container)] has duplicate metadata kind: {}",
kind
);
return quote_spanned! { mc_span =>
compile_error!(#msg);
};
}
}
}
let struct_name_ident = format_ident!("{}", ps.container.name);
let struct_name = &ps.container.name;
let struct_name_str = struct_name.to_string();
let opaque = ps.container.attrs.has_builtin("opaque");
let skip_all_unless_truthy = ps.container.attrs.has_builtin("skip_all_unless_truthy");
let truthy_attr: Option<TokenStream> = ps.container.attrs.facet.iter().find_map(|attr| {
if attr.is_builtin() && attr.key_str() == "truthy" {
let args = &attr.args;
if args.is_empty() {
return None;
}
Some(args.clone())
} else {
None
}
});
let facet_crate = ps.container.attrs.facet_crate();
let mut phantom_attr_uses: Vec<TokenStream> = Vec::new();
for attr in &ps.container.attrs.facet {
if let Some(phantom) = phantom_attr_use(attr, &facet_crate) {
phantom_attr_uses.push(phantom);
}
}
let fields: &[PStructField] = match &ps.kind {
PStructKind::Struct { fields } => fields,
PStructKind::TupleStruct { fields } => fields,
PStructKind::UnitStruct => &[],
};
let trailing_shape_checks = match collect_trailing_shape_checks(fields, &facet_crate) {
Ok(checks) => checks,
Err(err) => return err,
};
for field in fields {
if let Some(attr) = field
.attrs
.facet
.iter()
.find(|a| a.is_builtin() && a.key_str() == "opaque" && !a.args.is_empty())
{
let span = attr.key.span();
return quote_spanned! { span =>
compile_error!("`#[facet(opaque = ...)]` is container-level only for now");
};
}
}
for field in fields {
for attr in &field.attrs.facet {
if let Some(phantom) = phantom_attr_use(attr, &facet_crate) {
phantom_attr_uses.push(phantom);
}
}
}
let type_name_fn =
generate_type_name_fn(struct_name, parsed.generics.as_ref(), opaque, &facet_crate);
let has_explicit_facet_transparent = ps.container.attrs.has_builtin("transparent");
let has_repr_transparent = ps.container.attrs.is_repr_transparent();
let repr_implies_facet_transparent = if has_repr_transparent && !has_explicit_facet_transparent
{
match &ps.kind {
PStructKind::TupleStruct { fields } => fields.len() <= 1,
_ => false,
}
} else {
false
};
let use_transparent_semantics =
has_explicit_facet_transparent || repr_implies_facet_transparent;
let inner_field: Option<PStructField> = if use_transparent_semantics {
match &ps.kind {
PStructKind::TupleStruct { fields } => {
if fields.len() > 1 {
return quote! {
compile_error!("Transparent structs must be tuple structs with zero or one field");
};
}
fields.first().cloned()
}
_ => {
return quote! {
compile_error!("Transparent structs must be tuple structs");
};
}
}
} else {
None
};
let transparent_info = if use_transparent_semantics {
Some(TransparentInfo {
inner_field_type: inner_field.as_ref().map(|f| &f.ty),
inner_is_opaque: inner_field
.as_ref()
.is_some_and(|f| f.attrs.has_builtin("opaque")),
is_zst: inner_field.is_none(),
})
} else {
None
};
let trait_sources = TraitSources::from_attrs(&ps.container.attrs);
let bgp_for_vtable = ps.container.bgp.display_without_bounds();
let struct_type_for_vtable = quote! { #struct_name_ident #bgp_for_vtable };
let has_any_generics = !ps.container.bgp.params.is_empty();
let has_type_or_const_generics = ps.container.bgp.params.iter().any(|p| {
matches!(
p.param,
facet_macro_parse::GenericParamName::Type(_)
| facet_macro_parse::GenericParamName::Const(_)
)
});
let needs_inherent_borrow_inner = use_transparent_semantics
&& has_type_or_const_generics
&& inner_field
.as_ref()
.is_some_and(|f| !f.attrs.has_builtin("opaque"));
let invariants_wrapper: Option<TokenStream> = {
let invariant_exprs: Vec<&TokenStream> = ps
.container
.attrs
.facet
.iter()
.filter(|attr| attr.is_builtin() && attr.key_str() == "invariants")
.map(|attr| &attr.args)
.collect();
if !invariant_exprs.is_empty() {
let tests = invariant_exprs.iter().map(|expr| {
quote! {
if !#expr(value) {
return 𝟋Result::Err(𝟋Str::from("invariant check failed"));
}
}
});
Some(quote! {
{
fn __invariants_wrapper(value: &#struct_type_for_vtable) -> 𝟋Result<(), 𝟋Str> {
use #facet_crate::𝟋::*;
#(#tests)*
𝟋Result::Ok(())
}
__invariants_wrapper
}
})
} else {
None
}
};
let has_from_ref =
ps.container.attrs.facet.iter().any(|a| {
a.is_builtin() && (a.key_str() == "from_ref" || a.key_str() == "try_from_ref")
});
let (try_from_fn_direct, try_from_fn_indirect): (Option<TokenStream>, Option<TokenStream>) =
if has_from_ref {
(
Some(quote! { <Self>::__facet_try_from_ref }),
Some(quote! { <Self>::__facet_try_from_ref_indirect }),
)
} else {
(None, None)
};
let vtable_code = gen_vtable(
&facet_crate,
&type_name_fn,
&trait_sources,
transparent_info.as_ref(),
&struct_type_for_vtable,
invariants_wrapper.as_ref(),
needs_inherent_borrow_inner,
try_from_fn_direct.as_ref(),
try_from_fn_indirect.as_ref(),
has_type_or_const_generics,
has_any_generics,
);
let vtable_init = vtable_code;
let type_ops_init = gen_type_ops(
&facet_crate,
&trait_sources,
&struct_type_for_vtable,
has_type_or_const_generics,
has_any_generics,
truthy_attr.as_ref(),
);
let repr = match &ps.container.attrs.repr {
PRepr::Transparent => quote! { 𝟋Repr::TRANSPARENT },
PRepr::Rust(_) => quote! { 𝟋Repr::RUST },
PRepr::C(_) => quote! { 𝟋Repr::C },
PRepr::RustcWillCatch => {
return quote! {};
}
};
let (kind, fields_vec) = match &ps.kind {
PStructKind::Struct { fields } => {
let kind = quote!(𝟋Sk::Struct);
let fields_vec = fields
.iter()
.map(|field| {
gen_field_from_pfield(
field,
struct_name,
&ps.container.bgp,
None,
&facet_crate,
skip_all_unless_truthy,
has_type_or_const_generics,
)
})
.collect::<Vec<_>>();
(kind, fields_vec)
}
PStructKind::TupleStruct { fields } => {
let kind = quote!(𝟋Sk::TupleStruct);
let fields_vec = fields
.iter()
.map(|field| {
gen_field_from_pfield(
field,
struct_name,
&ps.container.bgp,
None,
&facet_crate,
skip_all_unless_truthy,
has_type_or_const_generics,
)
})
.collect::<Vec<_>>();
(kind, fields_vec)
}
PStructKind::UnitStruct => {
let kind = quote!(𝟋Sk::Unit);
(kind, vec![])
}
};
let variance_call = if opaque {
quote! { .variance(𝟋VncD::INVARIANT) }
} else {
quote! { .variance(𝟋CV) }
};
let where_clauses_ast = match &parsed.kind {
StructKind::Struct { clauses, .. } => clauses.as_ref(),
StructKind::TupleStruct { clauses, .. } => clauses.as_ref(),
StructKind::UnitStruct { clauses, .. } => clauses.as_ref(),
};
let where_clauses = build_where_clauses(
where_clauses_ast,
parsed.generics.as_ref(),
opaque,
&facet_crate,
&ps.container.attrs.custom_bounds,
);
let transparent_inherent_impl = if needs_inherent_borrow_inner {
let helper_bgp = ps
.container
.bgp
.with_lifetime(LifetimeName(format_ident!("ʄ")));
let bgp_def_for_helper = helper_bgp.display_with_bounds();
let bgp_display = ps.container.bgp.display_without_bounds();
quote! {
#[doc(hidden)]
impl #bgp_def_for_helper #struct_name_ident #bgp_display
#where_clauses
{
#[doc(hidden)]
unsafe fn __facet_try_borrow_inner(
src: *const Self,
) -> ::core::result::Result<#facet_crate::PtrMut, #facet_crate::𝟋::𝟋Str> {
let wrapper_ptr = src as *mut Self;
let inner_ptr: *mut _ = unsafe { &raw mut (*wrapper_ptr).0 };
#facet_crate::𝟋::𝟋Ok(#facet_crate::PtrMut::new(inner_ptr as *mut u8))
}
}
}
} else {
quote! {}
};
let type_params_call = build_type_params_call(parsed.generics.as_ref(), opaque, &facet_crate);
let const_params_call = build_const_params_call(parsed.generics.as_ref(), opaque, &facet_crate);
#[cfg(feature = "doc")]
let doc_call = if ps.container.attrs.doc.is_empty() || crate::is_no_doc() {
quote! {}
} else {
let doc_lines = ps.container.attrs.doc.iter().map(|s| quote!(#s));
quote! { .doc(&[#(#doc_lines),*]) }
};
#[cfg(not(feature = "doc"))]
let doc_call = quote! {};
#[cfg(feature = "doc")]
let source_location_call = if crate::is_no_doc() {
quote! {}
} else {
quote! {
.source_file(::core::file!())
.source_line(::core::line!())
.source_column(::core::column!())
}
};
#[cfg(not(feature = "doc"))]
let source_location_call = quote! {};
let decl_id_call = quote! {
.decl_id(𝟋DId::new(𝟋dih(::core::concat!(
::core::file!(), ":",
::core::line!(), ":",
::core::column!(), "#",
"struct", "#",
#struct_name_str
))))
};
let attributes_call = {
let items: Vec<TokenStream> = ps
.container
.attrs
.facet
.iter()
.filter(|attr| {
if attr.is_builtin() {
let key = attr.key_str();
if key == "opaque" && !attr.args.is_empty() {
return false;
}
!matches!(
key.as_str(),
"invariants"
| "crate"
| "traits"
| "auto_traits" | "proxy"
| "truthy"
| "skip_all_unless_truthy"
| "where"
)
} else {
let key = attr.key_str();
key != "proxy"
}
})
.map(|attr| {
let ext_attr = emit_attr(attr, &facet_crate, has_type_or_const_generics);
quote! { #ext_attr }
})
.collect();
if items.is_empty() {
quote! {}
} else {
quote! { .attributes(&const {[#(#items),*]}) }
}
};
let pod_call = if ps.container.attrs.has_builtin("pod") {
quote! { .pod() }
} else {
quote! {}
};
let metadata_container_call = if has_metadata_container {
quote! { .metadata_container() }
} else {
quote! {}
};
let type_tag_call = {
if let Some(type_tag) = ps.container.attrs.get_builtin_args("type_tag") {
quote! { .type_tag(#type_tag) }
} else {
quote! {}
}
};
let (proxy_inherent_impl, proxy_call) = {
if let Some(attr) = ps
.container
.attrs
.facet
.iter()
.find(|a| a.is_builtin() && a.key_str() == "proxy")
{
let proxy_type = &attr.args;
let struct_type = &struct_name_ident;
let bgp_display = ps.container.bgp.display_without_bounds();
let helper_bgp = ps
.container
.bgp
.with_lifetime(LifetimeName(format_ident!("ʄ")));
let bgp_def_for_helper = helper_bgp.display_with_bounds();
let proxy_where = {
let additional_clauses = quote! { #proxy_type: #facet_crate::Facet<'ʄ> };
if where_clauses.is_empty() {
quote! { where #additional_clauses }
} else {
quote! { #where_clauses, #additional_clauses }
}
};
let proxy_impl = quote! {
#[doc(hidden)]
impl #bgp_def_for_helper #struct_type #bgp_display
#proxy_where
{
#[doc(hidden)]
unsafe fn __facet_proxy_convert_in(
proxy_ptr: #facet_crate::PtrConst,
field_ptr: #facet_crate::PtrUninit,
) -> ::core::result::Result<#facet_crate::PtrMut, #facet_crate::𝟋::𝟋Str> {
extern crate alloc as __alloc;
let proxy: #proxy_type = proxy_ptr.read();
match <#struct_type #bgp_display as ::core::convert::TryFrom<#proxy_type>>::try_from(proxy) {
#facet_crate::𝟋::𝟋Ok(value) => #facet_crate::𝟋::𝟋Ok(field_ptr.put(value)),
#facet_crate::𝟋::𝟋Err(e) => #facet_crate::𝟋::𝟋Err(__alloc::string::ToString::to_string(&e)),
}
}
#[doc(hidden)]
unsafe fn __facet_proxy_convert_out(
field_ptr: #facet_crate::PtrConst,
proxy_ptr: #facet_crate::PtrUninit,
) -> ::core::result::Result<#facet_crate::PtrMut, #facet_crate::𝟋::𝟋Str> {
extern crate alloc as __alloc;
let field_ref: &#struct_type #bgp_display = field_ptr.get();
match <#proxy_type as ::core::convert::TryFrom<&#struct_type #bgp_display>>::try_from(field_ref) {
#facet_crate::𝟋::𝟋Ok(proxy) => #facet_crate::𝟋::𝟋Ok(proxy_ptr.put(proxy)),
#facet_crate::𝟋::𝟋Err(e) => #facet_crate::𝟋::𝟋Err(__alloc::string::ToString::to_string(&e)),
}
}
#[doc(hidden)]
const fn __facet_proxy_shape() -> &'static #facet_crate::Shape {
<#proxy_type as #facet_crate::Facet>::SHAPE
}
}
};
let proxy_ref = quote! {
.proxy(&const {
#facet_crate::ProxyDef {
shape: <Self>::__facet_proxy_shape(),
convert_in: <Self>::__facet_proxy_convert_in,
convert_out: <Self>::__facet_proxy_convert_out,
}
})
};
(proxy_impl, proxy_ref)
} else {
(quote! {}, quote! {})
}
};
let (opaque_adapter_inherent_impl, opaque_adapter_call) = {
if let Some(attr) = ps
.container
.attrs
.facet
.iter()
.find(|a| a.is_builtin() && a.key_str() == "opaque" && !a.args.is_empty())
{
let adapter_type = &attr.args;
let struct_type = &struct_name_ident;
let bgp_display = ps.container.bgp.display_without_bounds();
let helper_bgp = ps
.container
.bgp
.with_lifetime(LifetimeName(format_ident!("ʄ")));
let bgp_def_for_helper = helper_bgp.display_with_bounds();
let adapter_where = {
let additional_clauses = quote! { #adapter_type: #facet_crate::FacetOpaqueAdapter };
if where_clauses.is_empty() {
quote! { where #additional_clauses }
} else {
quote! { #where_clauses, #additional_clauses }
}
};
let adapter_impl = quote! {
#[doc(hidden)]
impl #bgp_def_for_helper #struct_type #bgp_display
#adapter_where
{
#[doc(hidden)]
fn __facet_opaque_adapter_assert_send_type(
value: &Self,
) -> &<#adapter_type as #facet_crate::FacetOpaqueAdapter>::SendValue<'ʄ> {
value
}
#[doc(hidden)]
fn __facet_opaque_adapter_assert_recv_type(
value: <#adapter_type as #facet_crate::FacetOpaqueAdapter>::RecvValue<'ʄ>,
) -> Self {
value
}
#[doc(hidden)]
unsafe fn __facet_opaque_adapter_serialize(
value_ptr: #facet_crate::PtrConst,
) -> #facet_crate::OpaqueSerialize {
let value: &Self = value_ptr.get();
let send_value = <Self>::__facet_opaque_adapter_assert_send_type(value);
<#adapter_type as #facet_crate::FacetOpaqueAdapter>::serialize_map(send_value)
}
#[doc(hidden)]
unsafe fn __facet_opaque_adapter_deserialize<'de>(
input: #facet_crate::OpaqueDeserialize<'de>,
value_ptr: #facet_crate::PtrUninit,
) -> ::core::result::Result<#facet_crate::PtrMut, #facet_crate::𝟋::𝟋Str> {
extern crate alloc as __alloc;
let value =
<#adapter_type as #facet_crate::FacetOpaqueAdapter>::deserialize_build(input)
.map_err(|e| __alloc::string::ToString::to_string(&e))?;
#facet_crate::𝟋::𝟋Ok(value_ptr.put(value))
}
}
};
let adapter_ref = quote! {
.opaque_adapter(&const {
#facet_crate::OpaqueAdapterDef {
serialize: <Self>::__facet_opaque_adapter_serialize,
deserialize: <Self>::__facet_opaque_adapter_deserialize,
}
})
};
(adapter_impl, adapter_ref)
} else {
(quote! {}, quote! {})
}
};
let (format_proxies_inherent_impl, format_proxies_call) = {
let format_proxy_attrs: Vec<_> = ps
.container
.attrs
.facet
.iter()
.filter(|a| !a.is_builtin() && a.key_str() == "proxy")
.collect();
if format_proxy_attrs.is_empty() {
(quote! {}, quote! {})
} else {
let struct_type = &struct_name_ident;
let bgp_display = ps.container.bgp.display_without_bounds();
let helper_bgp = ps
.container
.bgp
.with_lifetime(LifetimeName(format_ident!("ʄ")));
let bgp_def_for_helper = helper_bgp.display_with_bounds();
let mut proxy_methods = Vec::new();
let mut format_proxy_items = Vec::new();
for (idx, attr) in format_proxy_attrs.iter().enumerate() {
let proxy_type = &attr.args;
let ns = attr.ns.as_ref().expect("namespaced attr should have ns");
let ns_str = ns.to_string();
let convert_in_name = format_ident!("__facet_format_proxy_convert_in_{}", idx);
let convert_out_name = format_ident!("__facet_format_proxy_convert_out_{}", idx);
let shape_name = format_ident!("__facet_format_proxy_shape_{}", idx);
let proxy_where = {
let additional_clauses = quote! { #proxy_type: #facet_crate::Facet<'ʄ> };
if where_clauses.is_empty() {
quote! { where #additional_clauses }
} else {
quote! { #where_clauses, #additional_clauses }
}
};
proxy_methods.push(quote! {
#[doc(hidden)]
impl #bgp_def_for_helper #struct_type #bgp_display
#proxy_where
{
#[doc(hidden)]
unsafe fn #convert_in_name(
proxy_ptr: #facet_crate::PtrConst,
field_ptr: #facet_crate::PtrUninit,
) -> ::core::result::Result<#facet_crate::PtrMut, #facet_crate::𝟋::𝟋Str> {
extern crate alloc as __alloc;
let proxy: #proxy_type = proxy_ptr.read();
match <#struct_type #bgp_display as ::core::convert::TryFrom<#proxy_type>>::try_from(proxy) {
#facet_crate::𝟋::𝟋Ok(value) => #facet_crate::𝟋::𝟋Ok(field_ptr.put(value)),
#facet_crate::𝟋::𝟋Err(e) => #facet_crate::𝟋::𝟋Err(__alloc::string::ToString::to_string(&e)),
}
}
#[doc(hidden)]
unsafe fn #convert_out_name(
field_ptr: #facet_crate::PtrConst,
proxy_ptr: #facet_crate::PtrUninit,
) -> ::core::result::Result<#facet_crate::PtrMut, #facet_crate::𝟋::𝟋Str> {
extern crate alloc as __alloc;
let field_ref: &#struct_type #bgp_display = field_ptr.get();
match <#proxy_type as ::core::convert::TryFrom<&#struct_type #bgp_display>>::try_from(field_ref) {
#facet_crate::𝟋::𝟋Ok(proxy) => #facet_crate::𝟋::𝟋Ok(proxy_ptr.put(proxy)),
#facet_crate::𝟋::𝟋Err(e) => #facet_crate::𝟋::𝟋Err(__alloc::string::ToString::to_string(&e)),
}
}
#[doc(hidden)]
const fn #shape_name() -> &'static #facet_crate::Shape {
<#proxy_type as #facet_crate::Facet>::SHAPE
}
}
});
format_proxy_items.push(quote! {
#facet_crate::FormatProxy {
format: #ns_str,
proxy: &const {
#facet_crate::ProxyDef {
shape: <Self>::#shape_name(),
convert_in: <Self>::#convert_in_name,
convert_out: <Self>::#convert_out_name,
}
},
}
});
}
let inherent_impl = quote! { #(#proxy_methods)* };
let format_proxies_ref = quote! {
.format_proxies(&const {[#(#format_proxy_items),*]})
};
(inherent_impl, format_proxies_ref)
}
};
let from_ref_inherent_impl = {
let from_ref_attr = ps
.container
.attrs
.facet
.iter()
.find(|a| a.is_builtin() && a.key_str() == "from_ref");
let try_from_ref_attr = ps
.container
.attrs
.facet
.iter()
.find(|a| a.is_builtin() && a.key_str() == "try_from_ref");
if let Some(func_attr) = from_ref_attr.or(try_from_ref_attr) {
let is_fallible = try_from_ref_attr.is_some();
let func_path = &func_attr.args;
let struct_type = &struct_name_ident;
let bgp_display = ps.container.bgp.display_without_bounds();
let helper_bgp = ps
.container
.bgp
.with_lifetime(LifetimeName(format_ident!("ʄ")));
let bgp_def_for_helper = helper_bgp.display_with_bounds();
let (helper_fn, helper_call, unwrap_val) = if is_fallible {
(
quote! {
#[inline]
const fn __facet_get_src_ref_shape<'f, F, Ref: #facet_crate::Facet<'f> + 'f, Out, Err>(_fn: &F) -> &'static #facet_crate::Shape
where
F: Fn(Ref) -> ::core::result::Result<Out, Err>,
{
Ref::SHAPE
}
},
quote! { __facet_get_src_ref_shape::<_, _, Self, _>(&#func_path) },
quote! {
match value {
::core::result::Result::Ok(v) => v,
::core::result::Result::Err(e) => { return #facet_crate::TryFromOutcome::Failed(__alloc::string::ToString::to_string(&e).into()) }
}
},
)
} else {
(
quote! {
#[inline]
const fn __facet_get_src_ref_shape<'f, F, Ref: #facet_crate::Facet<'f> + 'f, Out>(_fn: &F) -> &'static #facet_crate::Shape
where
F: Fn(Ref) -> Out,
{
Ref::SHAPE
}
},
quote! { __facet_get_src_ref_shape::<_, _, Self>(&#func_path) },
quote! { value },
)
};
quote! {
#[doc(hidden)]
impl #bgp_def_for_helper #struct_type #bgp_display
#where_clauses
{
#[doc(hidden)]
unsafe fn __facet_try_from_ref(
dst: *mut Self,
src_shape: &'static #facet_crate::Shape,
src: #facet_crate::PtrConst,
) -> #facet_crate::TryFromOutcome {
extern crate alloc as __alloc;
#helper_fn
if src_shape.id != #helper_call.id {
return #facet_crate::TryFromOutcome::Unsupported;
}
let value = #func_path(unsafe { src.get() });
unsafe { dst.write(#unwrap_val) };
#facet_crate::TryFromOutcome::Converted
}
#[doc(hidden)]
unsafe fn __facet_try_from_ref_indirect(
dst: #facet_crate::OxPtrUninit,
src_shape: &'static #facet_crate::Shape,
src: #facet_crate::PtrConst,
) -> #facet_crate::TryFromOutcome {
Self::__facet_try_from_ref(
dst.ptr().as_mut_byte_ptr() as *mut Self,
src_shape,
src,
)
}
}
}
} else {
quote! {}
}
};
let inner_call = if use_transparent_semantics {
let inner_shape_val = if let Some(inner_field) = &inner_field {
let ty = &inner_field.ty;
if inner_field.attrs.has_builtin("opaque") {
quote! { <#facet_crate::OpaqueBorrow<'_, #ty> as #facet_crate::Facet>::SHAPE }
} else {
quote! { <#ty as #facet_crate::Facet>::SHAPE }
}
} else {
quote! { <() as #facet_crate::Facet>::SHAPE }
};
quote! { .inner(#inner_shape_val) }
} else {
quote! {}
};
let type_name_call = if parsed.generics.is_some() && !opaque {
quote! { .type_name(#type_name_fn) }
} else {
quote! {}
};
let facet_bgp = ps
.container
.bgp
.with_lifetime(LifetimeName(format_ident!("ʄ")));
let bgp_def = facet_bgp.display_with_bounds();
let bgp_without_bounds = ps.container.bgp.display_without_bounds();
let (ty_field, fields_const) = if opaque {
(
quote! {
#facet_crate::Type::User(#facet_crate::UserType::Opaque)
},
quote! {},
)
} else if fields_vec.is_empty() {
(
quote! {
𝟋Ty::User(𝟋UTy::Struct(
𝟋STyB::new(#kind, &[]).repr(#repr).build()
))
},
quote! {},
)
} else {
let num_fields = fields_vec.len();
(
quote! {
𝟋Ty::User(𝟋UTy::Struct(
𝟋STyB::new(#kind, &Self::__FIELDS).repr(#repr).build()
))
},
quote! {
const __FIELDS: [#facet_crate::Field; #num_fields] = {
use #facet_crate::𝟋::*;
[#(#fields_vec),*]
};
},
)
};
let dead_code_suppression = quote! {
const _: () = {
#[allow(dead_code, clippy::multiple_bound_locations)]
fn __facet_use_struct #bgp_def (__v: &#struct_name_ident #bgp_without_bounds) #where_clauses {
let _ = __v;
}
};
};
let facet_default = ps.container.attrs.has_builtin("default");
let trait_assertion_fn = if let Some(bounds) =
gen_trait_bounds(ps.container.attrs.declared_traits.as_ref(), facet_default)
{
quote! {
const _: () = {
#[allow(dead_code, clippy::multiple_bound_locations)]
fn __facet_assert_traits #bgp_def (_: &#struct_name_ident #bgp_without_bounds)
where
#struct_name_ident #bgp_without_bounds: #bounds
{}
};
}
} else {
quote! {}
};
let vtable_field = quote! { #vtable_init };
let type_ops_call = match type_ops_init {
Some(ops) => quote! { .type_ops(#ops) },
None => quote! {},
};
let shape_inherent_impl = quote! {
#[doc(hidden)]
impl #bgp_def #struct_name_ident #bgp_without_bounds #where_clauses {
#fields_const
const __SHAPE_DATA: #facet_crate::Shape = {
use #facet_crate::𝟋::*;
#(#trailing_shape_checks)*
𝟋ShpB::for_sized::<Self>(#struct_name_str)
.module_path(::core::module_path!())
#decl_id_call
#source_location_call
.vtable(#vtable_field)
#type_ops_call
.ty(#ty_field)
.def(𝟋Def::Undefined)
#type_params_call
#const_params_call
#type_name_call
#doc_call
#attributes_call
#type_tag_call
#proxy_call
#opaque_adapter_call
#format_proxies_call
#inner_call
#variance_call
#pod_call
#metadata_container_call
.build()
};
}
};
let static_decl = crate::derive::generate_static_decl(
&struct_name_ident,
&facet_crate,
has_type_or_const_generics,
);
let phantom_attr_block = if phantom_attr_uses.is_empty() {
quote! {}
} else {
quote! {
const _: () = { #(#phantom_attr_uses)* };
}
};
let result = quote! {
#phantom_attr_block
#dead_code_suppression
#trait_assertion_fn
#proxy_inherent_impl
#opaque_adapter_inherent_impl
#format_proxies_inherent_impl
#from_ref_inherent_impl
#transparent_inherent_impl
#shape_inherent_impl
#[automatically_derived]
unsafe impl #bgp_def #facet_crate::Facet<'ʄ> for #struct_name_ident #bgp_without_bounds #where_clauses {
const SHAPE: &'static #facet_crate::Shape = &Self::__SHAPE_DATA;
}
#static_decl
};
result
}