0

Is there a way to bypass some field visibility requirements within code generated by proc-macros to structural construct types?

For example, lets say that I have this struct and I use a proc-macro to construct it with some external data. To be prevent unsafe usage, the variables need to meet some additional requirements that are checked within the proc-macro so they do not need to be re-verified during runtime.

pub struct Foo {
    x: u32,
    y: bool,
    // etc.
}

I am attempting to create something like this, however I do not know of any attributes or features which would make this possible. In this example, I am misusing the #[automatically_derived] attribute as a placeholder for something which allows the bypassing of field visibility requirements when constructing Foo.

use different_crate::{Foo, load_external_foo};

// Input
const FOO: Foo = load_external_foo!(...);

// Output
const FOO: Foo = {
    #[automatically_derived]
    ::different_crate::foo::Foo {
        x: 12345,
        y: false,
    }
};

I have looked though doc.rust-lang.org/reference/attributes, however I was unable to find any options that work for my use case. In this past, this page has been slow to receive updates on new attributes and does not include any involved in nightly features.

I know one possible alternative would be to use #[doc(hidden)], however this only feels like a partial solution as no matter how I use it there would be some drawbacks.

// Making fields public, but hidden would work. However, needs to be added to every struct
// involved and can clutter longer structs due to the requirement for the attribute to be
// placed on every field. Additionally, it would potentially allow the unsafe construction
// of some structures without an unsafe block.
pub struct Foo {
    #[doc(hidden)]
    pub x: u32,
    #[doc(hidden)]
    pub y: bool,
}

// While a hidden `const unsafe fn`s would technically solve the issue, it leaves a bit of
// uncertainty. On one hand it helps express that attempting to construct `Foo` manually
// would be unsafe, but there is no guarantee it gets inlined/executed at compile time. 
// While I like the simplicity, using #[doc(hidden)] on each field seems more preferable for
// this reason.
impl Foo {
    #[doc(hidden)]
    #[inline(always)]
    pub const unsafe fn macro_build_foo(x: u32, y: bool) -> Foo {
        Foo { x, y }
    }
}
Locke
  • 7,626
  • 2
  • 21
  • 41

1 Answers1

1

No, because in Rust macros ultimately are just code replacement/generation, it would require to allow access while at the same time forbidding access, which obviously is not possible.

cafce25
  • 15,907
  • 4
  • 25
  • 31