Call proc macro inside other proc macro - rust

I have a small reproduction project which fails to compile. The project can be downloaded here: https://github.com/Jasperav/proc_macro_collision. The error is:
error[E0659]: `proc_macro_call` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
I have 3 libraries and 1 executable in the project:
Lib 1 - parser - parses the proc macro call
Lib 2 - proc_two - returns the literal string as a proc macro call
Lib 3 - proc_one - forwards the macro to proc_two (although it does not have a dependency on proc_two). This is like proc_two also a proc macro.
Relevant code for proc_one:
#[proc_macro_hack]
pub fn one(input: TokenStream) -> TokenStream {
let parse = parse_macro_input!(input as Parser);
let r = parse.lit;
let x = quote! {
two!(#r) // This is the problem I guess...
};
x.into()
}
Executable: calls proc_one (gives compile error).
Relevant code:
use proc_macro_hack::proc_macro_hack;
extern crate proc_one;
extern crate proc_two;
#[proc_macro_hack]
use proc_one::one;
#[proc_macro_hack]
use proc_two::two;
fn main() {
let hi: &'static str = one!("hi");
assert_eq!("hi", hi);
}
I don't understand why the call in the executable is ambiguous, lib 2 and 3 do not dependent on each other. This is the full error:
error[E0659]: `proc_macro_call` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
--> src\main.rs:10:1
|
10 | #[proc_macro_hack]
| ^^^^^^^^^^^^^^^^^^ ambiguous name
...
14 | let hi: &'static str = one!("hi");
| ---------- in this macro invocation
|
note: `proc_macro_call` could refer to the macro defined here
--> src\main.rs:11:15
|
11 | use proc_two::two;
| ^^^
...
14 | let hi: &'static str = one!("hi");
| ---------- in this macro invocation
note: `proc_macro_call` could also refer to the macro defined here
--> src\main.rs:9:15
|
9 | use proc_one::one;
| ^^^
...
14 | let hi: &'static str = one!("hi");
| ---------- in this macro invocation
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

According to proc_macro_hack documentation nested invocations are not supported:
By default, nested invocations are not supported i.e. the code emitted by a proc-macro-hack macro invocation cannot contain recursive calls to the same proc-macro-hack macro nor calls to any other proc-macro-hack macros. Use proc-macro-nested if you require support for nested invocations.
Therefore the code marked by you is the real issue:
let x = quote! {
two!(#r) // This is the problem
};
And there is a suggestion to look at proc-macro-nested "if you require support for nested invocations".

Related

implementing obj-rs example to glium

I am trying to load a model into glium, I am using crate obj-rs for this. My model works fine with this example. Unfortunately whenever I try to move code from the example to my project (which is basically code copied from here) I fail with an error:
error[E0277]: the trait bound `glium::Display: glium::backend::Facade` is not satisfied
--> src/main.rs:27:32
|
27 | let vb = obj.vertex_buffer(&display)?;
| ------------- ^^^^^^^^ the trait `glium::backend::Facade` is not implemented for `glium::Display`
| |
| required by a bound introduced by this call
|
= help: the trait `glium::backend::Facade` is implemented for `Rc<glium::context::Context>`
note: required by a bound in `obj::glium_support::<impl Obj<V, I>>::vertex_buffer`
--> /Users/user/project/obj-rs/src/lib.rs:309:33
|
309 | pub fn vertex_buffer<F: Facade>(
| ^^^^^^ required by this bound in `obj::glium_support::<impl Obj<V, I>>::vertex_buffer`
error[E0277]: the trait bound `glium::Display: glium::backend::Facade` is not satisfied
--> src/main.rs:28:31
|
28 | let ib = obj.index_buffer(&display)?;
| ------------ ^^^^^^^^ the trait `glium::backend::Facade` is not implemented for `glium::Display`
| |
| required by a bound introduced by this call
|
= help: the trait `glium::backend::Facade` is implemented for `Rc<glium::context::Context>`
note: required by a bound in `obj::glium_support::<impl Obj<V, I>>::index_buffer`
--> /Users/user/project/obj-rs/src/lib.rs:317:32
|
317 | pub fn index_buffer<F: Facade>(
| ^^^^^^ required by this bound in `obj::glium_support::<impl Obj<V, I>>::index_buffer`
I am new to rust so most of the time I don't know what I am doing. I find it really hard to simply make copied code work. I tried implementing Facade for Display but that didn't seem to make any difference, just more errors. Could you tell me what's wrong, or at least provide me with an example that works, I just want to add my own models to glium examples.
Here are the parts of code that I changed:
fn main() -> Result<(), Box<dyn std::error::Error>>{
#[allow(unused_imports)]
use glium::{glutin, Surface};
use obj::{load_obj, Obj};
use glium::glutin::dpi::LogicalSize;
let event_loop = glutin::event_loop::EventLoop::new();
let window = glutin::window::WindowBuilder::new()
.with_inner_size(LogicalSize::new(500.0, 400.0))
.with_title("obj-rs");
let context = glutin::ContextBuilder::new().with_depth_buffer(24);
let display = glium::Display::new(window, context, &event_loop)?;
let input = include_bytes!("model.obj");
let obj: Obj = load_obj(&input[..])?;
//two lines causing the problem
//let vb = obj.vertex_buffer(&display)?;
//let ib = obj.index_buffer(&display)?;
let positions = glium::VertexBuffer::new(&display, &teapot::VERTICES).unwrap();
..... rest is the same as in the glium example
One thing that I would like to differ from obj-rs example is not to use local source if you know what I mean. Basically something like this:
[dependencies]
glium = "*"
obj-rs = { version = "*", features = ["glium"] }

How do I specify that Cargo should build binaries only on a certain target?

I have a Cargo project set up with a library and a binary. The library is meant to be used on many platforms, including Android, while the binary is only meant to be used on Linux. As such, the binary contains a bunch of Linux-specific code that does not compile when I target Android. Is there a way to specify (without using features) that the binary should only be compiled on Linux?
I tried putting #![cfg(target_os = "linux")] in the main.rs of my binary, but then I got this error:
error[E0601]: `main` function not found in crate `server`
--> src/bin/server/main.rs:1:1
|
1 | / #![cfg(target_os = "linux")]
2 | |
3 | | use anyhow::{self, Context};
4 | |
... |
36 | | }
37 | | }
| |_^ consider adding a `main` function to `src/bin/server/main.rs`
I had exactly the same problem. The official Rust docs do not seem to mention how to solve it. But I found a solution.
The trick is to specify two main() functions in the file main.rs. The first one contains the code you want to execute when you are on Linux. The second one remains empty. With the help of conditional compilation, you tell the compiler which of the two main() functions to compile.
// within main.rs
#[cfg(target_os = "linux")]
fn main() {
// Your Linux-specific code goes here...
}
#[cfg(not(target_os = "linux"))]
fn main() {} // remains empty for all other OS
If you have OS-specific imports or other code at the top-level, just wrap it inside a module and use conditional compilation for it as well.
#[cfg(target_os = "linux")]
mod linux {
use anyhow::{self, Context};
// ...
}
The below link has related information that should help you in terms of target selection and selective compilation https://doc.rust-lang.org/cargo/commands/cargo-build.html#target-selection

Embedded Rust Discovery Book example fails to compile

I am new to rust and embedded systems. I was reading and going along "The Discovery Book" and I can't seem to figure out the errors below.
I have placed this in my main.rs:
#![deny(unsafe_code)]
#![no_main]
#![no_std]
use aux5::{entry, prelude::*, Delay, Leds};
#[entry]
fn main() -> ! {
let (mut delay, mut leds): (Delay, Leds) = aux5::init();
let half_period = 500_u16;
loop {
leds[0].on();
delay.delay_ms(half_period);
leds[0].off();
delay.delay_ms(half_period);
}
}
My auxiliary lib.rs contains:
pub use stm32f3_discovery::{leds::Leds, stm32f3xx_hal, switch_hal};
pub use switch_hal::{ActiveHigh, OutputSwitch, Switch, ToggleableOutputSwitch};
use stm32f3xx_hal::prelude::*;
pub use stm32f3xx_hal::{
delay::Delay,
gpio::{gpioe, Output, PushPull},
hal::blocking::delay::DelayMs,
stm32,
};
pub type LedArray = [Switch<gpioe::PEx<Output<PushPull>>, ActiveHigh>; 8];
pub fn init() -> (Delay, LedArray) {
let device_periphs = stm32::Peripherals::take().unwrap();
let mut reset_and_clock_control = device_periphs.RCC.constrain();
let core_periphs = cortex_m::Peripherals::take().unwrap();
let mut flash = device_periphs.FLASH.constrain();
let clocks = reset_and_clock_control.cfgr.freeze(&mut flash.acr);
let delay = Delay::new(core_periphs.SYST, clocks);
// initialize user leds
let mut gpioe = device_periphs.GPIOE.split(&mut reset_and_clock_control.ahb);
let leds = Leds::new(
gpioe.pe8,
gpioe.pe9,
gpioe.pe10,
gpioe.pe11,
gpioe.pe12,
gpioe.pe13,
gpioe.pe14,
gpioe.pe15,
&mut gpioe.moder,
&mut gpioe.otyper,
);
(delay, leds.into_array())
}
I have not changed anything in lib.rs and I am following the instructions from the book, along with the source code.
Running the code results in the following errors when building for the target:
error[E0432]: unresolved import `aux5::prelude`
--> src\05-led-roulette\src\main.rs:5:19
|
5 | use aux5::{entry, prelude::*, Delay, Leds};
| ^^^^^^^ could not find `prelude` in `aux5`
error[E0308]: mismatched types
--> src\05-led-roulette\src\main.rs:9:48
|
9 | let (mut delay, mut leds): (Delay, Leds) = aux5::init();
| ------------- ^^^^^^^^^^^^ expected struct `Leds`, found array of 8 elements
| |
| expected due to this
|
= note: expected tuple `(Delay, Leds)`
found tuple `(Delay, [Switch<PEx<Output<PushPull>>, ActiveHigh>; 8])`
error[E0608]: cannot index into a value of type `Leds`
--> src\05-led-roulette\src\main.rs:14:9
|
14 | leds[0].on();
| ^^^^^^^
error[E0599]: no method named `delay_ms` found for struct `Delay` in the current scope
--> src\05-led-roulette\src\main.rs:15:15
|
15 | delay.delay_ms(half_period);
| ^^^^^^^^ method not found in `Delay`
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
5 | use aux5::DelayMs;
|
error[E0608]: cannot index into a value of type `Leds`
--> src\05-led-roulette\src\main.rs:17:9
|
17 | leds[0].off();
| ^^^^^^^
error[E0599]: no method named `delay_ms` found for struct `Delay` in the current scope
--> src\05-led-roulette\src\main.rs:18:15
|
18 | delay.delay_ms(half_period);
| ^^^^^^^^ method not found in `Delay`
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
5 | use aux5::DelayMs;
|
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0308, E0432, E0599, E0608.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `led-roulette`
To learn more, run the command again with --verbose.
From the following page, "The Led and Delay abstractions", it looks like this is the set of imports that you need.
use aux5::{entry, Delay, DelayMs, LedArray, OutputSwitch};
In the above abstraction, compared to your main.rs, note the:
Addition of DelayMs trait, making .delay_ms() available.
Removal of a prelude as it is not being used.
Change from Leds to the expected LedArray.
Also see:
Stack Overflow, "Why do I need to import a trait to use the methods it defines for a type?"

Why doesn't Dbg seem to work within a for_each loop?

Why doesn't dbg! work in this for_each loop? Playground link
fn main() {
let chars = "hello".chars();
chars.clone().for_each(|x| dbg!(x));
}
I get this compile error:
error[E0308]: mismatched types
--> src/main.rs:4:32
|
4 | chars.clone().for_each(|x| dbg!(x));
| ^^^^^^^ expected (), found char
|
= note: expected type `()`
found type `char`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
I've tried passing in a reference to x too.
println works:
fn main() {
let chars = "hello".chars();
chars.clone().for_each(|x| println!("{:?}", x));
}
dbg! returns the value you passed in, while for_each requires a unit type to be returned. println! returns a unit type.
We can make this work by adding ;:
chars.clone().for_each(|x| {dbg!(x);});

The std documentation examples with question marks don't compile [duplicate]

This question already has answers here:
Why do try!() and ? not compile when used in a function that doesn't return Option or Result?
(4 answers)
Closed 5 years ago.
I'm having extreme difficulties with the try! and ? macro to the point that I'm starting to question the very fabric of reality. I lifted the example below straight from the rust-docs and it still blows up in my face.
Code:
pub use std::fs::File;
pub use std::io::prelude::*;
fn main() {
let mut file: File = File::open("foo.txt")?;
file.write_all(b"Hello, world!")?;
}
Error:
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
--> src/main.rs:6:23
|
6 | let mut file: File = File::open("foo.txt")?;
| ----------------------
| |
| the trait `std::ops::Try` is not implemented for `()`
| in this macro invocation
|
= note: required by `std::ops::Try::from_error`
error[E0277]: the trait bound `(): std::ops::Try` is not satisfied
--> src/main.rs:7:2
|
7 | file.write_all(b"Hello, world!")?;
| ---------------------------------
| |
| the trait `std::ops::Try` is not implemented for `()`
| in this macro invocation
|
= note: required by `std::ops::Try::from_error`
I'm on the latest stable release of Rust according to rustup (1.19.0)
These examples are currently expected to be run wrapped in a function returning a Result; if you click Run in the upper right corner of the example, you will see that it expands to:
fn main() {
use std::fs::File;
use std::io::prelude::*;
fn foo() -> std::io::Result<()> {
let mut file = File::create("foo.txt")?;
file.write_all(b"Hello, world!")?;
Ok(())
}
}
This is because functions returning Results (like File::create and io::Write::write_all) should be handled with possible errors in mind (which is especially important in documentation examples).
There was an RFC to allow returning Result from main() that was already merged, though the issue to allow ?s in main() is still active.

Resources