Applying a Rust attribute to more than one line
Asked Answered
B

2

9

To the best of my understanding of the Rust documentation, attributes are applied only to the line directly following an attribute. So, if I want to conditionally compile a line I can do this:

#[cfg(target_family = "unix")]
use termion::{color, style};

What happens when I want to conditionally compile two lines?

#[cfg(target_family = "unix")]
use termion::{color, style};
#[cfg(target_family = "unix")]
use termion::screen::*;

Is there a cleaner way for doing this?

Backpedal answered 29/10, 2019 at 6:29 Comment(4)
Well, in this case, you can merge those imports into to one line: use termion::{coloe, style, screen::*}. But it may not answer your Q in general.Immotile
@edwardw, true, I'm looking for a more general answerBackpedal
Side note: there'a at least one crate tackling the problem of cross-platform use of the terminal.Atropine
@DenysSéguret thanks I wasn't aware of it!Backpedal
S
18

There's no general grouping answer to my knowledge but there are specific solutions.

Most often, you can just use a block:

#[cfg(target_family = "unix")]
{
    // some code
}

use statements can always be grouped together, even when there's no common root:

#[cfg(target_family = "unix")]
use {
    termion::{color, style},
    std::io,
};

attributes are applied only to the line directly following an attribute

Not really. They're applied to the following "thing". There's a list of supported "things" in the documentation. It's not all what you'd probably want (it's not an if expression for example) but there's already a lot of covered ground.

Secund answered 29/10, 2019 at 7:6 Comment(0)
C
1

For people that come to this page seeking a general answer to "Applying a Rust attribute to more than one line", and not just module related attributes; a more general idea that could be used to apply an attribute to all items in a pseudo block, without creating a compile-time scoping problem, would be the macro, apply_attrib below.

// Apply the same attribute to all items in the block, but don't compile it as 
// an actual block.
macro_rules! apply_attrib {
    { #!$attr:tt $($it:item)* } => {
        $(
            #$attr
            $it
        )*
    }
}

apply_attrib! {
    #![allow(non_camel_case_types)]

    type c_ptr_hook = c_void;

    type c_ptr_list = c_void;

    #[allow(dead_code)]
    type c_ptr_context = c_void;

    // Many more `item`s...
}

// Declaration is accessible outside the pseudo block.
fn foo(p: *const c_ptr_hook) {
    // ...
}

An item in the rules applies to the type declarations and many other things; see the reference on item here. And here's the reference on macro metavariables.

This example can handle applying one attribute to all items in the pseudo block. Which solved my needs for a project, but if anyone has any suggestions that would make it so more than one attribute could be applied, please leave me a comment.

Caricaria answered 17/1 at 21:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.