如何通过条件编译更改函数的限定符?

She*_*ter 9 conditional-compilation rust

我有一个能够实现为const:

#![feature(const_fn)]

// My crate would have:

const fn very_complicated_logic(a: u8, b: u8) -> u8 {
    a * b
}

// The caller would have:

const ANSWER: u8 = very_complicated_logic(1, 2);

fn main() {}
Run Code Online (Sandbox Code Playgroud)

我想继续支持稳定的Rust,因为无法定义这样的函数.这些稳定的消费者将无法使用该功能在一个conststatic,但应该可以使用该功能在其他情况下:

// My crate would have:

fn very_complicated_logic(a: u8, b: u8) -> u8 {
    a * b
}

// The caller would have:    

fn main() {
    let answer: u8 = very_complicated_logic(1, 2);
}
Run Code Online (Sandbox Code Playgroud)

我如何有条件地编译我的代码,以便我的箱子的冒险用户可以启用const fn支持,稳定的用户仍然可以使用我的代码,而且我不必编写每个函数两次?

同样的问题应该适用于函数的其他修饰符,但我不确定这些修饰符会根据某些条件发生变化的具体情况:

  • default
  • unsafe
  • extern

Fra*_*gné 10

拯救的宏!

#![cfg_attr(feature = "const-fn", feature(const_fn))]

#[cfg(not(feature = "const-fn"))]
macro_rules! maybe_const_fn {
    ($($tokens:tt)*) => {
        $($tokens)*
    };
}

#[cfg(feature = "const-fn")]
macro_rules! maybe_const_fn {
    ($(#[$($meta:meta)*])* $vis:vis $ident:ident $($tokens:tt)*) => {
        $(#[$($meta)*])* $vis const $ident $($tokens)*
    };
}

maybe_const_fn! {
    #[allow(unused)] // for demonstration purposes
    pub fn very_complicated_logic(a: u8, b: u8) -> u8 {
        internally_complicated_logic(a, b)
    }
}

maybe_const_fn! {
    fn internally_complicated_logic(a: u8, b: u8) -> u8 {
        a * b
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[cfg(feature = "const-fn")]
    #[test]
    fn use_in_const() {
        const ANSWER: u8 = very_complicated_logic(1, 2);
        drop(ANSWER);
    }

    #[test]
    fn use_in_variable() {
        let answer: u8 = very_complicated_logic(1, 2);
        drop(answer);
    }
}
Run Code Online (Sandbox Code Playgroud)

随之而来的是Cargo.toml:

[features]
const-fn = []
Run Code Online (Sandbox Code Playgroud)

由于宏只能扩展为完整的语法片段(即宏不能简单地扩展到const),我们必须将整个函数包装在宏中,并将其中的某些部分解析,以便我们可以const在适当的位置注入.然后,解析器可以将整个事物解析为函数定义.

属性和可见性限定符需要特殊处理,因为它们必须出现在之前const.我选择使用不稳定的vis匹配器来简化宏的实现.