I'm trying to create an MQTT connection with tokio and the codec provided in the mqtt_v5 crate. My code does not compile, and I don't understand why. Here is what I have written so far, the send code might not be correct.
use tokio::net::TcpStream;
use tokio_util::codec::Framed;
use tokio_util::codec::Decoder;
use std::net::SocketAddrV4;
use mqtt_v5::types::Packet as MqttPacket;
use mqtt_v5::codec::MqttCodec;
use futures_sink::Sink;
use futures_core::stream::Stream;
struct MqttConn {
inner: Framed<TcpStream, MqttCodec>,
}
impl MqttConn {
async fn new(addr: SocketAddrV4) -> MqttConn {
let tcp = TcpStream::connect(addr).await.expect("cannot connect to mqtt");
MqttConn { inner: MqttCodec::new().framed(tcp) }
}
async fn handle(&self, handler: &dyn Fn(&MqttConn, MqttPacket) -> ()) {
while let Some(p) = self.inner.next().await {
handler(self, p)
}
}
async fn send(&self, p: MqttPacket) {
self.inner.start_send(p);
}
}
I get these errors from the compiler:
error[E0599]: no method named `framed` found for struct `MqttCodec` in the current scope
--> src/mqtt.rs:17:44
|
17 | MqttConn { inner: MqttCodec::new().framed(tcp) }
| ^^^^^^ method not found in `MqttCodec`
|
= help: items from traits can only be used if the trait is in scope
= note: the following trait is implemented but not in scope; perhaps add a `use` for it:
`use tokio_util::codec::decoder::Decoder;`
error[E0599]: no method named `next` found for struct `Framed<tokio::net::TcpStream, MqttCodec>` in the current scope
--> src/mqtt.rs:21:40
|
21 | while let Some(p) = self.inner.next().await {
| ^^^^ method not found in `Framed<tokio::net::TcpStream, MqttCodec>`
error[E0599]: no method named `start_send` found for struct `Framed<tokio::net::TcpStream, MqttCodec>` in the current scope
--> src/mqtt.rs:27:20
|
27 | self.inner.start_send(p);
| ^^^^^^^^^^ method not found in `Framed<tokio::net::TcpStream, MqttCodec>`
warning: unused import: `tokio_util::codec::Decoder`
--> src/mqtt.rs:3:5
|
3 | use tokio_util::codec::Decoder;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused import: `futures_sink::Sink`
--> src/mqtt.rs:7:5
|
7 | use futures_sink::Sink;
| ^^^^^^^^^^^^^^^^^^
The compiler says that the Decoder trait is not in scope, but I use it. If I try the suggested import I find that the module tokio_util::codec::decoder is private. Based on the source tokio_util::codec::decoder::Decoder is reexported as tokio_util::codec::Decoder. Also if I read the docs correctly, Framed should implement Sink and Stream therefore it should have the next and start_send methods.
Relevant lines from Cargo.toml:
[dependencies]
tokio = { version = "1.0.1", features = ["full"] }
tokio-util = { version = "0.6", features = ["full"] }
futures-sink = "0.3.9"
futures-core = "0.3.9"
mqtt-v5 = "0.1.1"
How can I get this to compile?
You have a number of library incompatibilities that are causing some less-than-obvious error messages.
mqtt-v5 depends on tokio-util^0.3, which was written for tokio 0.2, not 1.0. You'll need to roll back to tokio 0.2 and tokio-util 0.3. This should fix the problem with Decoder and Sink.
Additionally, the Stream trait only provides poll_next(), which is the task-level stream method. next() is provided by the StreamExt trait, along with other convenience methods similar to those found in Iterator.
Related
In the tokio tests I see they use oneshot::channel together with serve_with_shutdown but the the compiler tells me to add use futures_util::future::future::FutureExt but as you can see in the example below I already added that trait to the scope.
What am I missing?
Here a reprex
run cargo new tokio-test
Cargo.toml
[package]
name = "tokio-test"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tonic = "0.7"
prost = "0.10.1"
tokio = { version = "1.18", features = ["macros", "rt-multi-thread"] }
[build-dependencies]
tonic-build = "0.7.2"
src/main.rs
pub mod console {
tonic::include_proto!("console");
}
use console::console_server::{Console, ConsoleServer};
use console::{ConsoleResponse, InfoRequest};
use tokio::runtime::Runtime;
use tokio::sync::oneshot;
use tonic::{transport::Server, Request, Response};
use futures_util::FutureExt;
#[derive(Default)]
pub struct ConsoleImpl {}
#[tonic::async_trait]
impl Console for ConsoleImpl {
async fn info(
&self,
request: Request<InfoRequest>,
) -> Result<Response<ConsoleResponse>, tonic::Status> {
println!("{}", request.get_ref().text);
Ok(Response::new(ConsoleResponse {}))
}
}
fn main() {
let addr = "[::1]:50051".parse().unwrap();
let maxconsole = ConsoleImpl::default();
println!("Console server listening on {}", addr);
let mut rt = Runtime::new().expect("failed to obtain a new RunTime object");
let (shutdown_send, shutdown_recv) = oneshot::channel::<()>();
let server_future = Server::builder()
.add_service(ConsoleServer::new(maxconsole))
// .serve(addr)
.serve_with_incoming_shutdown(
addr,
shutdown_recv.map(drop),
);
rt.block_on(server_future).expect("failed to successfully run the future on RunTime");
}
src/console.proto
syntax = "proto3";
package console;
service Console {
rpc info (InfoRequest) returns (ConsoleResponse) {}
}
message InfoRequest {
string text = 1;
}
message ConsoleResponse {
}
If you build the project it will complain
❯ cargo build
Updating crates.io index
Compiling tokio-test v0.1.0 (C:\s\tokio-test)
error[E0432]: unresolved import `futures_util`
--> src\main.rs:10:5
|
10 | use futures_util::FutureExt;
| ^^^^^^^^^^^^ use of undeclared crate or module `futures_util`
error[E0599]: `tokio::sync::oneshot::Receiver<()>` is not an iterator
--> src\main.rs:40:27
|
40 | shutdown_recv.map(drop),
| ^^^ `tokio::sync::oneshot::Receiver<()>` is not an iterator
|
::: C:\Users\FrancescElies\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-1.20.1\src\sync\oneshot.rs:318:1
|
318 | pub struct Receiver<T> {
| ---------------------- doesn't satisfy `tokio::sync::oneshot::Receiver<()>: Iterator`
|
= note: the following trait bounds were not satisfied:
`tokio::sync::oneshot::Receiver<()>: Iterator`
which is required by `&mut tokio::sync::oneshot::Receiver<()>: Iterator`
= 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:
|
1 | use futures_util::future::future::FutureExt;
|
Some errors have detailed explanations: E0432, E0599.
For more information about an error, try `rustc --explain E0432`.
error: could not compile `tokio-test` due to 2 previous errors
Yes, you added the FutureExt import, but did not tell Rust where to find that crate. The critical part of the error message is:
error[E0432]: unresolved import `futures_util`
--> src\main.rs:10:5
|
10 | use futures_util::FutureExt;
| ^^^^^^^^^^^^ use of undeclared crate or module `futures_util`
This can be fixed by adding the futures_util crate to your Cargo.toml dependency section.
I am using rust rocket rocket = { version = "=0.5.0-rc.2", features = ["json"] } as my web server, this is the code looks like:
/// # search the template list
///
/// return different type of template
#[openapi(tag = "template")]
#[get("/v1/list?<query..>")]
pub fn list(query: TemplateRequest) -> content::RawJson<String> {
let contents = get_template_list(query.template_type, query.name);
return box_rest_response(contents);
}
this code works fine. Now I facing a problem is that the rust rocket return raw json, the client side could not know the return content structure. it only show a json string in swagger:
the client did not know what the response content is. I have read the the rust rocket official document still did not figure out what should I do to return the entity structure. I have tried like this:
pub fn list(query: TemplateRequest) -> Result<Vec<TemplateResponse>, String> {
let contents = get_template_list(query.template_type, query.name);
return Ok(contents);
}
the compiler shows:
error[E0277]: the trait bound `std::vec::Vec<TemplateResponse>: Responder<'_, '_>` is not satisfied
--> src/biz/template/bill_book_template_controller.rs:28:1
|
28 | #[openapi(tag = "账本模版")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Responder<'_, '_>` is not implemented for `std::vec::Vec<TemplateResponse>`
|
= help: the following implementations were found:
<std::vec::Vec<u8> as Responder<'r, 'static>>
= note: required because of the requirements on the impl of `Responder<'_, '_>` for `Result<std::vec::Vec<TemplateResponse>, std::string::String>`
note: required by a bound in `rocket_okapi::response::OpenApiResponder::responses`
--> /Users/xiaoqiangjiang/.cargo/git/checkouts/okapi-727e9b4b9c217cbb/65244f0/rocket-okapi/src/response/mod.rs:10:41
|
10 | pub trait OpenApiResponder<'a, 'r: 'a>: rocket::response::Responder<'a, 'r> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `rocket_okapi::response::OpenApiResponder::responses`
= note: this error originates in the attribute macro `openapi` (in Nightly builds, run with -Z macro-backtrace for more info)
I have tried this way:
pub fn list(query: TemplateRequest) -> Result<content::RawJson<String>, String> {
let contents = get_template_list(query.template_type, query.name);
return Ok(box_rest_response(contents));
}
it could successfully compile but still could not show the response structure in swagger.
For some reason it is telling me that it is undeclared when i am trying to follow an example for an IRC in rust and it makes no sense that it is not working cause i have used libraries like this before and it worked before so idk what is happening \
code:
use futures::prelude::*;
use irc::client::prelude::*;
#[tokio::main]
async fn main() -> irc::error::Result<()> {
let config = Config {
nickname: Some("pickles".to_owned()),
server: Some("chat.freenode.net".to_owned()),
channels: vec!["#rust-spam".to_owned()],
..Default::default()
};
let mut client = Client::from_config(config).await?;
client.identify()?;
let mut stream = client.stream()?;
let sender = client.sender();
while let Some(message) = stream.next().await.transpose()? {
print!("{}", message);
match message.command {
Command::PRIVMSG(ref target, ref msg) => {
if msg.contains(client.current_nickname()) {
sender.send_privmsg(target, "Hi!")?;
}
}
_ => (),
}
}
Ok(())
}
Errors
--> src\main.rs:1:5
|
1 | use futures::prelude::*;
| ^^^^^^^ use of undeclared type or module `futures`
error[E0308]: mismatched types
--> src\main.rs:9:19
|
9 | channels: vec!["#rust-spam".to_owned()],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| expected enum `std::option::Option`, found struct `std::vec::Vec`
| help: try using a variant of the expected enum: `Some(<[_]>::into_vec(box [$($x),+]))`
|
= note: expected enum `std::option::Option<std::vec::Vec<_>>`
found struct `std::vec::Vec<_>`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0599]: no function or associated item named `from_config` found for trait object `dyn irc::client::Client` in the current scope
--> src\main.rs:13:30
|
13 | let mut client = Client::from_config(config).await?;
| ^^^^^^^^^^^ function or associated item not found in `dyn irc::client::Client`
Cargo.toml
[package]
name = "irc"
version = "0.1.0"
authors = ["sudo"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
irc = "0.13"
tokio = { version = "0.2.22", features = ["full"] }
Edit: Added Cargo.toml
You will need to add the futures crate to your cargo file. E.g. from the docs
[dependencies]
futures = "0.3"
You need to add futures to your Cargo.toml, even though a dependency already depends on it.
I'm stuck with ownership; I but can't make the Option<OutputPin> in my function usable. How should it be?
struct Chip {
wake_pin: Option<OutputPin>,
}
impl Chip {
pub fn new(wake_pin: Option<Pin>) -> Chip {
Chip {
wake_pin: wake_pin.map(|pin| pin.into_output()),
}
}
pub fn awake(&self) {
// Fails
if let Some(pin) = self.wake_pin {
pin.set_low();
}
}
}
fn main() {
let wake_pin = Gpio::new()
.expect("Can not init gpio")
.get(255)
.expect("Could not attach to wake pin");
let chip = Chip::new(Some(wake_pin));
}
I am using the rppal crate and the compiler fails in the if let Some area. I tried to borrow wake_pin, get the Option as a reference and some other things but I don't understand the ownership rules completely.
I believe I've duplicated your set up. If something isn't right, please edit your question with the relevant details.
src/main.rs:
use rppal::gpio::{Gpio, OutputPin, Pin};
struct Chip {
wake_pin: Option<OutputPin>,
}
impl Chip {
pub fn new(wake_pin: Option<Pin>) -> Chip {
Chip {
wake_pin: wake_pin.map(|pin| pin.into_output()),
}
}
pub fn awake(&self) {
// Fails
if let Some(pin) = self.wake_pin {
pin.set_low();
}
}
}
fn main() {
let wake_pin = Gpio::new()
.expect("Can not init gpio")
.get(255)
.expect("Could not attach to wake pin");
let chip = Chip::new(Some(wake_pin));
}
Cargo.toml:
[package]
name = "tmp"
version = "0.0.1"
edition = "2018"
[dependencies]
rppal = "0.11.3"
Attempting to compile this (with cargo check or similar), we get a warning and two errors.
warning: unused variable: `chip`
--> src/main.rs:28:9
|
28 | let chip = Chip::new(Some(wake_pin));
| ^^^^ help: consider prefixing with an underscore: `_chip`
|
= note: `#[warn(unused_variables)]` on by default
error[E0507]: cannot move out of `self.wake_pin.0` which is behind a shared reference
--> src/main.rs:16:28
|
16 | if let Some(pin) = self.wake_pin {
| --- ^^^^^^^^^^^^^ help: consider borrowing here: `&self.wake_pin`
| |
| data moved here
| move occurs because `pin` has type `rppal::gpio::pin::OutputPin`, which does not implement the `Copy` trait
error[E0596]: cannot borrow `pin` as mutable, as it is not declared as mutable
--> src/main.rs:17:13
|
16 | if let Some(pin) = self.wake_pin {
| --- help: consider changing this to be mutable: `mut pin`
17 | pin.set_low();
| ^^^ cannot borrow as mutable
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0507, E0596.
For more information about an error, try `rustc --explain E0507`.
error: Could not compile `tmp`.
To learn more, run the command again with --verbose.
Since you're presumably going to use chip later, we can silence the warning by temporarily renaming it to _chip.
let _chip = Chip::new(Some(wake_pin));
The first error tells us that we can't move the pin out of self since we're only borrowing self. It would be rather rude to invalidate the data behind self if we're only borrowing it. However, the compiler is telling us a solution. help: consider borrowing here: `&self.wake_pin`
It ends up not quite being right, but it's the right direction.
if let Some(pin) = &self.wake_pin {
pin.set_low();
}
Now instead of pin having type OutputPin (an owned value), it has type &OutputPin (a borrowed value).
We still get the second error though (with a slightly different phrasing). The point is that pin.set_low() requires pin to be a mutable reference. Right now, we're taking self as an immutable reference (pub fn awake(&self)). If we're going to mutate self or any of its fields, we need to take it mutably. This also means we need to make sure pin is borrowed mutably.
pub fn awake(&mut self) {
if let Some(pin) = &mut self.wake_pin {
pin.set_low();
}
}
I am testing some Rust code and want to log some of the intermediate data to a file to make sure it is correct before I write the next element in the pipeline that consumes the data. In any other language I'd just write the data to a file handle stored in a static variable, but rust complains (correctly) that this is not thread safe. Since the application in question uses gstreamer this is theoretically a threat. I'll just paste my naive version below:
use std::fs::File;
use std::io::Write;
fn main() {
log_mesh("bacon");
}
static mut meshes : Option<Result<File, std::io::Error>> = None;
fn log_mesh(message: &str)
{
if let None = meshes {
meshes = Some(File::open("/tmp/meshes.txt"));
}
if let Ok(mut f) = meshes.unwrap() {
f.write_all(message.as_bytes());
f.flush();
}
}
This results in two important kinds of compile errors:
error[E0507]: cannot move out of static item
--> src/main.rs:16:24
|
16 | if let Ok(mut f) = meshes.unwrap() {
| ^^^^^^ cannot move out of static item
error[E0133]: use of mutable static is unsafe and requires unsafe function or block
--> src/main.rs:12:19
|
12 | if let None = meshes {
| ^^^^^^ use of mutable static
|
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
I have flailed around with Mutex, lazy_static!, mut_static, but all of them lead me into the woods and I get lost. I assume there has to be some compact idiom to solve this problem that isn't coming up in Google search results.
The first attempt at lazy_static! usage would be
use lazy_static::lazy_static;
use std::sync::Mutex;
use std::fs::File;
use std::io::Write;
lazy_static! {
static ref meshes : Mutex<Result<File, std::io::Error>> = Mutex::new(File::open("/tmp/meshes.txt"));
}
pub fn log_mesh(message: &str)
{
let mut tmp = meshes.lock().unwrap();
if let Ok(ref mut f) = tmp {
f.write_all(message.as_bytes());
f.flush();
}
}
which triggers this compile error:
error[E0308]: mismatched types
--> src/module2.rs:16:12
|
16 | if let Ok(ref mut f) = tmp {
| ^^^^^^^^^^^^^ --- this match expression has type `std::sync::MutexGuard<'_, std::result::Result<std::fs::File, std::io::Error>>`
| |
| expected struct `std::sync::MutexGuard`, found enum `std::result::Result`
|
= note: expected type `std::sync::MutexGuard<'_, std::result::Result<std::fs::File, std::io::Error>, >`
found type `std::result::Result<_, _>`
which is somewhat discouraging and chock-full of behind-the-curtain magic, but can be solved by changing it to
if let Ok(ref mut f) = *tmp {
I hesitate to mark it as an answer because there could be race conditions a more experienced coder can spot or another idiom that is superior.