How do I call a function from an struct received on a macro?
My actual case is different but I reduced the issue to this piece of code:
macro_rules! macro_test {
($foo:ident) => {
{
println!("{}", <$foo>.to_string());
}
}
}
fn main() {
let ss = "sim";
macro_test!(ss);
}
It doesn't compile and I have found no clear answer on how to call <$received>.function().
The error:
Compiling playground v0.0.1 (/playground)
error: expected `::`, found `.`
--> src/main.rs:4:34
|
4 | println!("{}", <$foo>.to_string());
| ^ expected `::`
...
11 | macro_test!(ss);
| --------------- in this macro invocation
|
= note: this error originates in the macro `macro_test` (in Nightly builds, run with -Z macro-backtrace for more info)
The playgorund to test it does not compile. I have not found a way to call methods of an ident inside a macro.
Related
I am trying to implement a simple stream rpc using tonic and grpc. I have been following the routeguide tutorial.
When I try to return a tokio_stream::wrappers::ReceiverStream from my stream method I get compile error indicating I should return a Result wrapped by a ReceiverStream.
warning: unused manifest key: package.author
Compiling prng_generator v0.1.0 (/home/babbleshack/projects/prng_generator)
error[E0308]: mismatched types
--> src/bin/server.rs:51:46
|
51 | Ok(Response::new(ReceiverStream::new(rx)))
| ^^ expected enum `Result`, found struct `PrngResponse`
|
= note: expected struct `tokio::sync::mpsc::Receiver<Result<PrngResponse, Status>>`
found struct `tokio::sync::mpsc::Receiver<PrngResponse>`
note: return type inferred to be `tokio::sync::mpsc::Receiver<Result<PrngResponse, Status>>` here
--> src/bin/server.rs:41:67
|
41 | ) -> Result<Response<Self::PRNGServiceRequestStream>, Status> {
| ___________________________________________________________________^
42 | | let (mut tx, rx) = mpsc::channel(4);
43 | | let response_data = self.data.clone();
44 | |
... |
51 | | Ok(Response::new(ReceiverStream::new(rx)))
52 | | }
| |_____^
For more information about this error, try `rustc --explain E0308`.
error: could not compile `prng_generator` due to previous error
When I wrap my return channel in a Result I get a contradicting error message:
error[E0308]: mismatched types
--> src/bin/server.rs:51:46
|
51 | Ok(Response::new(ReceiverStream::new(Ok(rx))))
| ^^^^^^ expected struct `tokio::sync::mpsc::Receiver`, found enum `Result`
|
= note: expected struct `tokio::sync::mpsc::Receiver<Result<PrngResponse, Status>>`
found enum `Result<tokio::sync::mpsc::Receiver<PrngResponse>, _>`
note: return type inferred to be `tokio::sync::mpsc::Receiver<Result<PrngResponse, Status>>` here
--> src/bin/server.rs:41:67
|
41 | ) -> Result<Response<Self::PRNGServiceRequestStream>, Status> {
| ___________________________________________________________________^
42 | | let (mut tx, rx) = mpsc::channel(4);
43 | | let response_data = self.data.clone();
44 | |
... |
51 | | Ok(Response::new(ReceiverStream::new(Ok(rx))))
52 | | }
| |_____^
Here is my proto:
use std::sync::Arc;
use tokio::sync::mpsc;
use tonic::{Request, Response, Status};
use tokio_stream::wrappers::ReceiverStream;
pub mod types {
tonic::include_proto!("types");
}
use types::prng_service_server::PrngService;
use types::{PrngRequest, PrngResponse};
And the implementing rust code:
use std::sync::Arc;
use tokio::sync::mpsc;
use tonic::{Request, Response, Status};
use tokio_stream::wrappers::ReceiverStream;
pub mod types {
tonic::include_proto!("types");
}
use types::prng_service_server::PrngService;
use types::{PrngRequest, PrngResponse};
#[derive(Debug, Default)]
pub struct PRNGServiceImpl{
data: Arc<Vec<PrngResponse>>,
}
#[tonic::async_trait]
impl PrngService for PRNGServiceImpl {
type PRNGServiceRequestStream = ReceiverStream<Result<PrngResponse, Status>>;
async fn prng_service_request(
&self,
request: Request<PrngRequest>,
) -> Result<Response<Self::PRNGServiceRequestStream>, Status> {
let (mut tx, rx) = mpsc::channel(256);
let response_data = self.data.clone();
tokio::spawn(async move {
for response in &response_data[..] {
Ok(tx.send(response.clone()).await.unwrap());
}
println!(" /// done sending");
});
Ok(Response::new(ReceiverStream::new(rx)))
//Ok(Response::new(ReceverStream::new(Ok(rx))))
}
}
How do I determine what my return type should be here?
The error message indicates that your return type declares a stream that produces Result<PrngResponse, Status> values, but the stream you have given it produces PrngResponse values. Your attempt to fix the solution wraps the receiver channel in a Result, which is not the same thing.
To fix this, you need to change the type that rx is inferred to be. It's inferred to be a stream of PrngResponse because of the tx.send() call, which sends a PrngResponse, so you can fix this by sending a Result instead:
tx.send(Ok(response.clone()))
The compiler points at the returned value and not the tx.send() line because the problem is the mismatch between the declared return type of the function and what it actually returns. The compiler could probably figure out that this is due to the tx.send() invocation, but in many cases type inference uses information spread out over multiple lines and there may not be one single line responsible for the inferred type of the returned value.
One way you could trace the problem to its source is to provide an explicit type somewhere matching the return type. For example:
let (mut tx, rx) = mpsc::channel::<Result<PrngResponse, Status>>(256);
This change would resolve the return type issue, and the compiler would have then pointed at the tx.send() line indicating that the sent value is not a Result.
I am new to rust and trying to figure out what I am doing wrong here. From the docs.rs page on walkdir:
The following code recursively iterates over the directory given and prints the path for each entry:
use walkdir::WalkDir;
for entry in WalkDir::new("foo") {
println!("{}", entry?.path().display());
}
However when I try to run this as a simple program:
use walkdir::WalkDir;
fn main() {
for entry in WalkDir::new("~/Documents/ExampleDir/") {
println!("{}", entry?.path().display());
}
}
I get a compilation error:
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
--> src/main.rs:4:24
|
2 | / fn main() {
3 | | for entry in WalkDir::new("foo") {
4 | | println!("{}", entry?.path().display());
| | ^^^^^^ cannot use the `?` operator in a function that returns `()`
5 | | }
6 | | }
| |_- this function should return `Result` or `Option` to accept `?`
|
= help: the trait `Try` is not implemented for `()`
= note: required by `from_error`
If I remove the ? operator then I get a different compilation error:
error[E0599]: no method named `path` found for enum `std::result::Result<walkdir::DirEntry, walkdir::Error>` in the current scope
--> src/main.rs:4:30
|
4 | println!("{}", entry.path().display());
| ^^^^ method not found in `std::result::Result<walkdir::DirEntry, walkdir::Error>`
What am I doing wrong here? Is this an issue in my code or in the documentation?
The ? is shorthand for a match statement. See The question mark operator.
The question mark operator (?) unwraps valid values or returns erroneous values, propagating them to the calling function. It is a unary postfix operator that can only be applied to the types Result<T, E> and Option.
The (main) function requires a return value of type Result:
use std::error::Error;
use walkdir::WalkDir;
fn main() -> Result<(), Box<dyn Error>> {
for entry in WalkDir::new("~/Documents/ExampleDir/") {
println!("{}", entry?.path().display());
}
Ok(())
}
I'm new to rust and started experimenting with actix_web and sqlx. the goal is to create a simple, open-source Blog engine, but after I implemented the CLI argument parser and basic SQL connection pool, the code doesn't compile anymore. I'm getting the following error:
error[E0308]: mismatched types
--> src/main.rs:17:1
|
17 | #[actix_web::main]
| ^^^^^^^^^^^^^^^^^^
| |
| expected enum `std::result::Result`, found `()`
| help: try using a variant of the expected enum: `Ok(#[actix_web::main])`
18 | async fn main() -> std::io::Result<()> {
| ------------------- expected `std::result::Result<(), std::io::Error>` because of return type
|
= note: expected enum `std::result::Result<(), std::io::Error>`
found unit type `()`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
error: could not compile `rusty_read`.
To learn more, run the command again with --verbose.
the error suggests to use std::result::Result<(), std::io::Error> as return type, but I get the same error when replacing the current return type with it:
error[E0308]: mismatched types
--> src/main.rs:17:1
|
17 | #[actix_web::main]
| ^^^^^^^^^^^^^^^^^^
| |
| expected enum `std::result::Result`, found `()`
| help: try using a variant of the expected enum: `Ok(#[actix_web::main])`
18 | async fn main() -> std::result::Result<(), std::io::Error> {
| --------------------------------------- expected `std::result::Result<(), std::io::Error>` because of return type
|
= note: expected enum `std::result::Result<(), std::io::Error>`
found unit type `()`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
error: could not compile `rusty_read`.
To learn more, run the command again with --verbose.
so far I couldn't find anybody with the same issue and could not find any reason for it.
My Code:
/Cargo.toml
[package]
name = "rusty_read"
version = "0.1.0"
authors = ["LeMoonStar <webmaster#unitcore.de>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-web = "3.0.0-beta.1"
rust-ini = "0.15"
sqlx = { version = "0.4.0-beta.1", features = [ "all-databases", "any", "tls" ] }
clap = "2"
/src/main.rs
use actix_web::{get, web, App, HttpServer, Responder};
use ini::Ini;
use sqlx::pool::Pool;
use sqlx::any;
#[get("/")]
async fn index() -> impl Responder {
format!("index")
}
#[get("/article/{id}")]
async fn article(info: web::Path<u32>) -> impl Responder {
format!("article nr.{}", info)
}
#[actix_web::main]
async fn main() -> std::result::Result<(), std::io::Error> {
let conf = Ini::load_from_file("conf.ini").unwrap_or(Ini::load_from_str("[Server]
bindAddress = \"127.0.0.1:8080\"
[Database]
url = \"mysql://user:password#localhost/blog\"
").unwrap());
let matches = clap::App::new("Rusty Read")
.version("0.1 INDEV")
.author("LeMoonStar <webmaster#unitcore.de>")
.about("a blog engine written in rust")
.subcommand(clap::SubCommand::with_name("config")
.about("sets various configurations for the blog")
.arg(clap::Arg::with_name("address")
.short("a")
.long("adress")
.help("sets the address the http server binds on (eg. 127.0.0.1:8080)")
.takes_value(true))
.arg(clap::Arg::with_name("database")
.short("d")
.long("database")
.help("sets the url to the database (eg. mysql://user:password#localhost/blog)")
.takes_value(true)))
.subcommand(clap::SubCommand::with_name("init_database")
.about("Initializes the database which is set in the conf.ini file (or with the config command)"))
.get_matches();
if let Some(matches) = matches.subcommand_matches("config") {
if matches.is_present("address") {
conf.section(Some("Server")).unwrap()
.insert("bindAddress", "127.0.0.1:8080");
}
if matches.is_present("database") {
conf.section(Some("Database")).unwrap()
.insert("url", "mysql://user:password#localhost/blog");
}
} else if let Some(matches) = matches.subcommand_matches("init_database") {
} else {
let mut section = conf.section(Some("Server")).expect("conf.ini requires a [Server] section.");
let bind_address = section.get("bindAddress").expect("conf.ini's [Server] section requires a bindAdress.");
section = conf.section(Some("Database")).expect("conf.ini requires a [Database] section.");
let db_url = section.get("url").expect("conf.ini's [Database] section requires a url.");
let pool = Pool::<any::Any>::connect(db_url).await.expect("database connection pool could not be created.");
HttpServer::new(move || {
App::new()
.service(article)
.service(index)
.data(pool.clone())
})
.bind(bind_address).expect("could not bind http server")
.run()
.await;
}
}
I hope someone can help me with this problem since I can't continue to work on the project, while this problem is present.
the Ok(()) is actually working.. I've tried to copy-pasting all of your code before, and do cargo check i got the same problem as you write there on the comment. then I tried to clean the code inside the main function and then copy-pasting your code again piece by piece. after adding Ok(()) as the return of the main. and the error changed before I even finished the copy-pasting. see
the screenshot of different error on my local.
then I tried to fix it by adding clone() like below:
..
conf.section(Some("Server")).unwrap().clone()
..
conf.section(Some("Database")).unwrap().clone()
..
and then I cargo run it. and the server works fine! see the screenshot here.
So here I am, trucking along with Rustlings, until I get broadsided with test 4.
It wants me to write a macro that will satisfy the following code:
fn main() {
if my_macro!("world!") != "Hello world!" {
panic!("Oh no! Wrong output!");
}
}
So, I wrote this:
macro_rules! my_macro {
($val:expr) => {
println!("Hello {}", $val);
}
}
And Rustlings spat this out:
error[E0308]: mismatched types
--> exercises/test4.rs:15:31
|
15 | if my_macro!("world!") != "Hello world!" {
| ^^^^^^^^^^^^^^ expected (), found reference
|
= note: expected type `()`
found type `&'static str`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.
Which, you know. I get. I understand what the problem is, but I don't understand how to write a macro that will satisfy the code. I can change the code I'm testing against, but that's not what the test wants me to do. I'm only to write a macro. I'm stumped. I also don't understand how encapsulating the macro in a module is meant to help, but the test says it's a test on modules as well as macros.
println! will print to the stdout. Instead, you just want to format the string and return it from the macro. Use format! instead, and drop the ; so that it will return the expression instead of ():
macro_rules! my_macro {
($val:expr) => {
format!("Hello {}", $val)
}
}
I want to write a macro that prints "OK" then returns self in a method. It's my first macro, so I tried this, thinking it will just make something like a text replacement, but it fails:
macro_rules! print_ok_and_return_self {
() => {
println!("OK");
self
}
}
fn main() {
let a = A{};
a.a().a();
}
struct A {}
impl A {
fn a(self) -> Self {
print_ok_and_return_self!()
}
}
Error:
error: macro expansion ignores token `self` and any following
--> src/main.rs:4:13
|
4 | self
| ^^^^
|
note: caused by the macro expansion here; the usage of `print_ok_and_return_self!` is likely invalid in expression context
--> src/main.rs:17:13
|
17| print_ok_and_return_self!()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
After a quick look at the documentation, I know it's not just text replacement, but I still don't know how to make it work.
There are two errors in a row, let's fix the first one.
The syntax for a macro arm is:
(...) => {
...
}
which means that what your macro expands to is:
println!("OK");
self
which is not OK (two statements).
Instead, it should expand to an expression (in this case), which you get by enclosing it within {}:
macro_rules! print_ok_and_return_self {
() => {
{
println!("OK");
self
}
}
}
This leads to the second error:
error[E0424]: `self` is not available in a static method
--> <anon>:4:9
|
4 | self
| ^^^^ not available in static method
...
17 | print_ok_and_return_self!()
| --------------------------- in this macro invocation
|
= note: maybe a `self` argument is missing?
A macro cannot assume the existence of a variable in its scope, so you need to pass self as an argument:
macro_rules! print_ok_and_return_value {
($v:expr) => {{
println!("OK");
$v
}}
}
and the invocation becomes:
impl A {
fn a(self) -> Self {
print_ok_and_return_value!(self)
}
}