Else case in conditional compile in rust - rust

How can I have some code being compiled only when no cfg block match? For example something like this:
#IF NUM == 1
//something
#ELSE IF NUM == 2
// something
#ELSE
// no case match, panic!
#ENDIF

By hand e.g.
#[cfg(thing1)]
// something
#[cfg(all(not(thing1), thing2))]
// something
#[cfg(all(not(thing1), not(thing2)))]
// no case
Alternatively, within a function and if your "something"s are compilable in every case, you can use cfg!. Since it evaluates to a literal there's a good chance the optimiser will strip out the bits which don't match:
if cfg!(thing1) {
// something
} else if cfg!(thing2) {
// something
} else {
panic!();
}
although compile_error would make more sense than panic.
There is also a cfg-if crate for something more ergonomic.
For more on the topic, see the article Yak shaving conditional compilation in Rust which expands on and discusses the various approaches.

You can use not in the conditional part of a cfg block. You can see an example in the docs for cfg
// This function only gets compiled if the target OS is linux
#[cfg(target_os = "linux")]
fn are_you_on_linux() {
println!("You are running linux!");
}
// And this function only gets compiled if the target OS is *not* linux
#[cfg(not(target_os = "linux"))]
fn are_you_on_linux() {
println!("You are *not* running linux!");
}
If you need something more complicated you can also use any and all, something like:
#[cfg(target_os="linux")]
fn get_os() -> &str { return "Linux"; }
#[cfg(target_os="windows")]
fn get_os() -> &str { return "Windows"; }
#[cfg(not(any(target_os="linux", target_os="windows")))]
fn get_os() -> &str { return "Unknown"; }
Further details are available in the reference.

Related

Can I create my own conditional compilation attributes?

There are several ways of doing something in my crate, some result in fast execution, some in low binary size, some have other advantages, so I provide the user interfaces to all of them. Unused functions will be optimized away by the compiler. Internal functions in my crate have to use these interfaces as well, and I would like them to respect the user choice at compile time.
There are conditional compilation attributes like target_os, which store a value like linux or windows. How can I create such an attribute, for example prefer_method, so I and the user can use it somewhat like in the following code snippets?
My crate:
#[cfg(not(any(
not(prefer_method),
prefer_method = "fast",
prefer_method = "small"
)))]
compile_error("invalid `prefer_method` value");
pub fn bla() {
#[cfg(prefer_method = "fast")]
foo_fast();
#[cfg(prefer_method = "small")]
foo_small();
#[cfg(not(prefer_method))]
foo_default();
}
pub fn foo_fast() {
// Fast execution.
}
pub fn foo_small() {
// Small binary file.
}
pub fn foo_default() {
// Medium size, medium fast.
}
The user crate:
#[prefer_method = "small"]
extern crate my_crate;
fn f() {
// Uses the `foo_small` function, the other `foo_*` functions will not end up in the binary.
my_crate::bla();
// But the user can also call any function, which of course will also end up in the binary.
my_crate::foo_default();
}
I know there are --cfg attributes, but AFAIK these only represent boolean flags, not enumeration values, which allow setting multiple flags when only one enumeration value is valid.
Firstly, the --cfg flag supports key-value pairs using the syntax --cfg 'prefer_method="fast"'. This will allow you to write code like:
#[cfg(prefer_method = "fast")]
fn foo_fast() { }
You can also set these cfg options from a build script. For example:
// build.rs
fn main() {
println!("cargo:rustc-cfg=prefer_method=\"method_a\"");
}
// src/main.rs
#[cfg(prefer_method = "method_a")]
fn main() {
println!("It's A");
}
#[cfg(prefer_method = "method_b")]
fn main() {
println!("It's B");
}
#[cfg(not(any(prefer_method = "method_a", prefer_method = "method_b")))]
fn main() {
println!("No preferred method");
}
The above code will result in an executable that prints "It's A".
There's no syntax like the one you suggest to specify cfg settings. The best thing to expose these options to your crates' users is through Cargo features.
For example:
# Library Cargo.toml
# ...
[features]
method_a = []
method_b = []
// build.rs
fn main() {
// prefer method A if both method A and B are selected
if cfg!(feature = "method_a") {
println!("cargo:rustc-cfg=prefer_method=\"method_a\"");
} else if cfg!(feature = "method_b") {
println!("cargo:rustc-cfg=prefer_method=\"method_b\"");
}
}
# User Cargo.toml
# ...
[dependencies.my_crate]
version = "..."
features = ["method_a"]
However, in this case, I'd recommend just using the Cargo features directly in your code (i.e. #[cfg(feature = "fast")]) rather than adding the build script since there's a one-to-one correspondence between the cargo feature and the rustc-cfg being added.

Option types and early returns. return an Error when is_none()

Using match (like in bar) seems to be a common approach..
#[derive(Debug)]
pub enum MyErrors {
SomeError,
}
fn foo(x: Option<u64>) -> Result<u64, MyErrors> {
if x.is_none() {
return Err(MyErrors::SomeError);
}
// .. some long code where more options
// are checked and matched
// The ok here is just so the code is simple and compiles
Ok(x.unwrap() * 2)
}
fn bar(x: Option<u64>) -> Result<u64, MyErrors> {
match x {
None => {
return Err(MyErrors::SomeError)?;
}
Some(v) => {
// .. some long code where more options
// are checked and matched
// The ok here is just so the code is simple and compiles
Ok(x.unwrap() * 2)
}
}
}
fn main() {
foo(Some(1));
bar(Some(2));
}
However, early returns (such as in foo) significantly reduce how nested the code looks like. If there are multiple times when an option has to be unwrapped or an error returned, code like bar gets very nested...
What is the recommended practice for early returning an error in the case of empty options?
If a longer method chain is undesirable due to complex logic inside, there are still a few readable, low-indent options.
ok_or and ?
We can convert an Option to a Result with a desired error, and immediately unwrap it with the ? operator. This solution probably provides the least indent possible, and can be easily used to "unwrap" multiple Options.
fn bar1(x: Option<u64>) -> Result<u64, MyErrors> {
let x = x.ok_or(MyErrors::SomeError)?;
// A lot of stuff going on.
Ok(x * 2)
}
This will evaluate the error inside ok_or regardless of whether or not it will actually be used. If this computation is expensive, ok_or_else, which produces the error lazily, will be more efficient (related question).
if let
This solution can still lead to a staircase of code if nested, but may be more appropriate if the else branch logic is more involved.
fn bar2(x: Option<u64>) -> Result<u64, MyErrors> {
if let Some(x) = x {
// Lot of stuff here as well.
Ok(x * 2)
} else {
Err(MyErrors::SomeError)
}
}

Identifier interpolation in macro definition [duplicate]

Basically, there are two parts to this question:
Can you pass an unknown identifier to a macro in Rust?
Can you combine strings to generate new variable names in a Rust macro?
For example, something like:
macro_rules! expand(
($x:ident) => (
let mut x_$x = 0;
)
)
Calling expand!(hi) obvious fails because hi is an unknown identifier; but can you somehow do this?
ie. The equivalent in C of something like:
#include <stdio.h>
#define FN(Name, base) \
int x1_##Name = 0 + base; \
int x2_##Name = 2 + base; \
int x3_##Name = 4 + base; \
int x4_##Name = 8 + base; \
int x5_##Name = 16 + base;
int main() {
FN(hello, 10)
printf("%d %d %d %d %d\n", x1_hello, x2_hello, x3_hello, x4_hello, x5_hello);
return 0;
}
Why you say, what a terrible idea. Why would you ever want to do that?
I'm glad you asked!
Consider this rust block:
{
let marker = 0;
let borrowed = borrow_with_block_lifetime(data, &marker);
unsafe {
perform_ffi_call(borrowed);
}
}
You now have a borrowed value with an explicitly bounded lifetime (marker) that isn't using a structure lifetime, but that we can guarantee exists for the entire scope of the ffi call; at the same time we don't run into obscure errors where a * is de-referenced unsafely inside an unsafe block and so the compiler doesn't catch it as an error, despite the error being made inside a safe block.
(see also Why are all my pointers pointing to the same place with to_c_str() in rust?)
The use a macro that can declare temporary variables for this purpose would considerably ease the troubles I have fighting with the compiler. That's why I want to do this.
Yes however this is only available as a nightly-only experimental API which may be removed.
You can pass arbitrary identifier into a macro and yes, you can concatenate identifiers into a new identifier using concat_idents!() macro:
#![feature(concat_idents)]
macro_rules! test {
($x:ident) => ({
let z = concat_idents!(hello_, $x);
z();
})
}
fn hello_world() { }
fn main() {
test!(world);
}
However, as far as I know, because concat_idents!() itself is a macro, you can't use this concatenated identifier everywhere you could use plain identifier, only in certain places like in example above, and this, in my opinion, is a HUGE drawback. Just yesterday I tried to write a macro which could remove a lot of boilerplate in my code, but eventually I was not able to do it because macros do not support arbitrary placement of concatenated identifiers.
BTW, if I understand your idea correctly, you don't really need concatenating identifiers to obtain unique names. Rust macros, contrary to the C ones, are hygienic. This means that all names of local variables introduced inside a macro won't leak to the scope where this macro is called. For example, you could assume that this code would work:
macro_rules! test {
($body:expr) => ({ let x = 10; $body })
}
fn main() {
let y = test!(x + 10);
println!("{}", y);
}
That is, we create a variable x and put an expression after its declaration. It is then natural to think that x in test!(x + 10) refers to that variable declared by the macro, and everything should be fine, but in fact this code won't compile:
main3.rs:8:19: 8:20 error: unresolved name `x`.
main3.rs:8 let y = test!(x + 10);
^
main3.rs:3:1: 5:2 note: in expansion of test!
main3.rs:8:13: 8:27 note: expansion site
error: aborting due to previous error
So if all you need is uniqueness of locals, then you can safely do nothing and use any names you want, they will be unique automatically. This is explained in macro tutorial, though I find the example there somewhat confusing.
There is also https://github.com/dtolnay/paste, which works well in cases where concat_idents is underpowered or in cases where you can't target the nightly compiler.
macro_rules! foo_macro {
( $( $name:ident ),+ ) => {
paste! {
#[test]
fn [<test_ $name>]() {
assert! false
}
}
};
}
In cases where concat_idents doesn't work (which is most cases I'd like to use it) changing the problem from concatenated identifiers to using namespaces does work.
That is, instead of the non-working code:
macro_rules! test {
($x:ident) => ({
struct concat_idents!(hello_, $x) {}
enum contact_idents!(hello_, $x) {}
})
}
The user can name the namespace, and then have preset names as shown below:
macro_rules! test {
($x:ident) => ({
mod $x {
struct HelloStruct {}
enum HelloEnum {}
}
})
}
Now you have a name based on the macro's argument. This technique is only helpful in specific cases.
You can collect your identifiers into a struct if you don't want to use nightly and external crates and your identifiers are types.
use std::fmt::Debug;
fn print_f<T: Debug>(v: &T){
println!("{:?}", v);
}
macro_rules! print_all {
($($name:ident),+) => {
struct Values{
$($name: $name),+
}
let values = Values{
$(
$name: $name::default()
),+
};
$(
print_f(&values.$name);
)+
};
}
fn main(){
print_all!(String, i32, usize);
}
This code prints
""
0
0
If you fear that Value will conflict with some type name, you can use some long UUID as part of the name:
struct Values_110cf51d7a694c808e6fe79bf1485d5b{
$($name:$name),+
}

How can I create "C Blocks" when using FFI?

I'm working with the CoreFoundation framework on OS X, but I don't know how to map this function in Rust:
void CFRunLoopPerformBlock(CFRunLoopRef fl, CFTypeRef mode, void (^block)(void));
The last parameter is void(^block)(void) — how can I create arguments of this type?
Short, probably helpful answer: there's the block crate, which looks like it might do the job.
Short, unhelpful answer: Insofar as I am aware, Rust doesn't have any support for Apple's block extension. There is no equivalent Rust type, assuming you want to call an API that expects a block.
Longer, marginally less unhelpful answer: From what I can gather from some Clang documentation on the Apple Block ABI, void(^)(void) would be the same size as a regular pointer.
As such, my advice is as follows: treat blocks as opaque, pointer-sized values. To invoke one, write a function in C which calls it for you.
The following is untested (I don't have a Mac), but should at least get you going in the right direction. Also, I'm marking this community wiki so anyone who can test it can fix it if need-be.
In Rust:
// These are the "raw" representations involved. I'm not using std::raw
// because that's not yet stabilised.
#[deriving(Copy, Clone)]
struct AppleBlock(*const ());
#[deriving(Copy, Clone)]
struct RustClosure(*const(), *const());
// Functions that we need to be written in C:
extern "C" {
fn rust_closure_to_block(closure_blob: RustClosure) -> AppleBlock;
fn block_release(block_blob: AppleBlock);
}
// The function that the C code will need. Note that this is *specific* to
// FnMut() closures. If you wanted to generalise this, you could write a
// generic version and pass a pointer to that to `rust_closure_to_block`.
extern "C" fn call_rust_closure(closure_blob: RustClosure) {
let closure_ref: &FnMut() = unsafe { mem::transmute(closure_blob) };
closure_ref();
}
// This is what you call in order to *temporarily* turn a closure into a
// block. So, you'd use it as:
//
// with_closure_as_block(
// || do_stuff(),
// |block| CFRunLoopPerformBlock(fl, mode, block)
// );
fn with_closure_as_block<C, B, R>(closure: C, body: B) -> R
where C: FnMut(), B: FnOnce(block_blob) -> R {
let closure_ref: &FnMut() = &closure;
let closure_blob: RustClosure = unsafe { mem::transmute(closure_ref) };
let block_blob = unsafe { rust_closure_to_block(closure_blob) };
let r = body(block_blob);
unsafe { block_release(block_blob) };
r
}
In C:
typedef struct AppleBlock {
void *ptr;
} AppleBlock;
typedef struct RustClosure {
void *ptr;
void *vt;
} RustClosure;
void call_rust_closure(RustClosure closure_blob);
AppleBlock rust_closure_to_block(RustClosure closure_blob) {
return (AppleBlock)Block_copy(^() {
call_rust_closure(closure_blob);
});
}
// I'm not using Block_release directly because I don't know if or how
// blocks change name mangling or calling. You might be able to just
// use Block_release directly from Rust.
void block_release(AppleBlock block) {
Block_release((void (^)(void))block);
}

Why do return expressions use semicolons when they're unnecessary?

I'm learning Rust and I've found something confusing with functions. According to the official reference, a return expression:
.. [is] denoted with the keyword return. Evaluating a return expression moves its
argument into the output slot of the current function, destroys the current function activation
frame, and transfers control to the caller frame.
So, this program works:
fn main() {
let current_hour = 10;
let message = get_message(current_hour);
println!("Good {0}", message);
}
fn get_message(current_hour: i32) -> &'static str {
if current_hour < 11 {
return "Morning"
}
else if current_hour < 17 {
return "Afternoon"
}
else {
return "Evening"
}
}
And when I add semi-colons to the "return" expressions, it still works:
fn main() {
let current_hour = 10;
let message = get_message(current_hour);
println!("Good {0}", message);
}
fn get_message(current_hour: i32) -> &'static str {
if current_hour < 11 {
return "Morning";
}
else if current_hour < 17 {
return "Afternoon";
}
else {
return "Evening";
}
}
My understanding of expression statements (e.g. expr;) is that it will evaluate the expr expression, and ignore the result (instead it will use ()). In the case of using return expr;, there doesn't seem to be a reason for using ; since return expr destroys the current function activation frame (and would then ignore the ;).
So, why does a lot of Rust code that I've seen use the semi-colon if it's not necessary (and in fact makes learning about Rust's functions very confusing... since it feels like it's contradictory). Is it just an idiom from other languages that has carried over?
Is it just an idiom from other languages that has carried over?
Yes, I think that's it, just habit and possibly a general sense of aesthetics about what feels weird and what doesn't (which is of course influenced by someone's previous languages).
AFAICT, the only difference it can make is for something like
fn foo() {
return;
println!("hi");
}
where return needs to be a statement... but the code after the return is unreachable (which the compiler will tell you), so this likely doesn't occur that much in real code.

Resources