I'm using gtk-rs to take the value of an input and use it to execute a command with xdotool:
input.connect_activate(clone!(#weak window => move |entry| {
let input_text = entry.text();
let cmd = format!(
"xdotool search --onlyvisible --name {} windowactivate",
input_text
);
let output = std::process::Command::new("sh")
.arg("-c")
.arg(cmd)
.spawn()
.unwrap();
println!("{}", String::from_utf8_lossy(&output.stdout));
window.close();
}));
I'm getting this compiling error:
error[E0308]: mismatched types
--> src/main.rs:66:48
|
66 | println!("{}", String::from_utf8_lossy(&output.stdout));
| ----------------------- ^^^^^^^^^^^^^^ expected slice `[u8]`, found enum `std::option::Option`
| |
| arguments to this function are incorrect
|
= note: expected reference `&[u8]`
found reference `&std::option::Option<ChildStdout>`
note: associated function defined here
--> /home/alex/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/string.rs:631:12
|
631 | pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
| ^^^^^^^^^^^^^^^
So I tried this:
match output.stdout {
Some(stdout) => {
println!("{}", String::from_utf8_lossy(&stdout));
},
None => {
println!("No output");
}
}
But I'm getting the same error.
Update:
I tried:
let output = std::process::Command::new("sh")
.arg("-c")
.arg(cmd)
.output()
.unwrap();
println!(Output: "{}", String::from_utf8_lossy(&output.stdout));
But nothing is being printed:
Output:
Full code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ea4431b73191c132f4392378cce13604
After reading the comments and docs, I managed to print the command with:
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
But I had to do: xdotool search --onlyvisible --name {} because xdotool search --onlyvisible --name {} windowactivate prints nothing.
Related
I have the following function, which runs fine:
use chrono_tz::Tz;
use chrono::{TimeZone, NaiveDate, NaiveDateTime};
fn my_func(time_zone: &str, fmt: &str, ndt: NaiveDateTime) {
let datefmt_func = |ndt: NaiveDateTime| time_zone.parse::<Tz>().unwrap().from_utc_datetime(&ndt).format(fmt);
let res = datefmt_func(ndt).to_string();
println!("res: {res}");
}
fn main() {
let time_zone = "UTC";
let fmt = "%Y-%m-%d %H:%M:%S%z";
let ndt = NaiveDate::from_ymd_opt(2018, 9, 28).unwrap().and_hms_opt(2, 30, 0).unwrap();
my_func(time_zone, fmt, ndt);
}
I'd like to let it accept None as time_zone. Within it, I need to repeatedly call datefmt_func, so I'd like to assign to datefmt_func once and reuse it. Here's what I've tried:
use chrono_tz::Tz;
use chrono::{TimeZone, NaiveDate, NaiveDateTime};
fn my_func(time_zone: Option<&str>, fmt: &str, ndt: NaiveDateTime) {
let datefmt_func = match time_zone {
Some(time_zone) => |ndt: NaiveDateTime| time_zone.parse::<Tz>().unwrap().from_utc_datetime(&ndt).format(fmt),
None => |ndt: NaiveDateTime| ndt.format(fmt),
};
let res = datefmt_func(ndt).to_string();
println!("res: {res}");
}
fn main() {
let time_zone = Some("UTC");
let fmt = "%Y-%m-%d %H:%M:%S%z";
let ndt = NaiveDate::from_ymd_opt(2018, 9, 28).unwrap().and_hms_opt(2, 30, 0).unwrap();
my_func(time_zone, fmt, ndt);
}
However, this gives me
error[E0308]: `match` arms have incompatible types
--> src/main.rs:7:17
|
5 | let datefmt_func = match time_zone {
| ________________________-
6 | | Some(time_zone) => |ndt: NaiveDateTime| time_zone.parse::<Tz>().unwrap().from_utc_datetime(&ndt).format(fmt),
| | -----------------------------------------------------------------------------------------
| | |
| | the expected closure
| | this is found to be of type `[closure#src/main.rs:6:28: 6:48]`
7 | | None => |ndt: NaiveDateTime| ndt.format(fmt),
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
8 | | };
| |_____- `match` arms have incompatible types
|
= note: expected closure `[closure#src/main.rs:6:28: 6:48]`
found closure `[closure#src/main.rs:7:17: 7:37]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
For more information about this error, try `rustc --explain E0308`.
error: could not compile `tmp` due to previous error
How can I adjust my code so that it will run? If "no two closures, even if identical, have the same type", then how can I assign a function which depends on a local variable (time_zone) to datefmt_func?
Do as the compiler tells you, use trait objects and Box the closures:
fn my_func(time_zone: Option<&str>, fmt: &str, ndt: NaiveDateTime) {
let datefmt_func: Box<dyn Fn(_) -> _> = match time_zone {
Some(time_zone) => Box::new(|ndt: NaiveDateTime| {
time_zone
.parse::<Tz>()
.unwrap()
.from_utc_datetime(&ndt)
.format(fmt)
}),
None => Box::new(|ndt: NaiveDateTime| ndt.format(fmt)),
};
let res = datefmt_func(ndt).to_string();
println!("res: {res}");
}
Or in your simple example just run the code instead of creating a closure which you immediately call:
fn my_func(time_zone: Option<&str>, fmt: &str, ndt: NaiveDateTime) {
let res = match time_zone {
Some(time_zone) => time_zone
.parse::<Tz>()
.unwrap()
.from_utc_datetime(&ndt)
.format(fmt),
None => ndt.format(fmt),
}
.to_string();
println!("res: {res}");
}
I'm using axum and this code (found here) to download files:
use axum::{
body::StreamBody,
http::{header, StatusCode},
response::{Headers, IntoResponse},
routing::get,
Router,
};
use std::net::SocketAddr;
use tokio_util::io::ReaderStream;
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(handler));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn handler() -> impl IntoResponse {
// `File` implements `AsyncRead`
let file = match tokio::fs::File::open("Cargo.toml").await {
Ok(file) => file,
Err(err) => return Err((StatusCode::NOT_FOUND, format!("File not found: {}", err))),
};
// convert the `AsyncRead` into a `Stream`
let stream = ReaderStream::new(file);
// convert the `Stream` into an `axum::body::HttpBody`
let body = StreamBody::new(stream);
let headers = Headers([
(header::CONTENT_TYPE, "text/toml; charset=utf-8"),
]);
Ok((headers, body))
}
Everything works. But I cannot find a way to move the below code in a separate function:
let file = match tokio::fs::File::open("Cargo.toml").await {
Ok(file) => file,
Err(err) => return Err((StatusCode::NOT_FOUND, format!("File not found: {}", err))),
};
I would like to use both tokio::fs::File and https://crates.io/crates/rust-s3 methods in this function.
So I need a "common type" which appear to be AsyncRead, I think.
What should be the signature of the function?
I tried with:
use tokio::io::AsyncRead;
pub struct Player {
db: Arc<DB>
}
impl Handler {
pub async fn player_pdf(
&self,
id: &str,
) -> Result<&(dyn AsyncRead)> {
//...use id here...
let file = &tokio::fs::File::open("player.pdf").await?;
Ok(file)
}
}
but I get the error:
error[E0308]: mismatched types
|
55 | Ok(file)
| -- ^^^^
| | |
| | expected reference, found struct `tokio::fs::File`
| | help: consider borrowing here: `&file`
| arguments to this enum variant are incorrect
|
= note: expected reference `&dyn tokio::io::AsyncRead`
found struct `tokio::fs::File`
I tried with: let file = &tokio::fs::File::open("player.pdf").await?; and I got:
error[E0515]: cannot return value referencing temporary value
|
43 | let file = &tokio::fs::File::open(...
| --------------------------- temporary value created here
...
55 | Ok(file)
| ^^^^^^^^ returns a value referencing data owned by the current function
What can I use?
Returning a generic "boxed" value might be the solution here:
impl Handler {
pub async fn player_pdf(
&self,
id: &str,
) -> Result<Box<dyn AsyncRead>> {
//...use id here...
Ok(Box::new(tokio::fs::File::open("player.pdf").await?))
}
}
Where now there's no dangling reference, it's encapsulated and fully owned.
This question already has answers here:
Return local String as a slice (&str)
(7 answers)
Closed 2 years ago.
I'm new to rust and trying to collect files into a string vector.
use glob::glob;
use std::env;
fn main() {
let mut file_names: Vec<&str> = Vec::new();
let cwd = env::current_dir().unwrap();
for entry in glob(cwd.to_str().unwrap()).expect("Failed to read directory.") {
match entry {
Ok(file) => {
println!("{:?}", file.file_name());
let file_name = file.file_name().unwrap().to_str();
file_names.push(file_name.unwrap());
}
Err(e) => println!("{:?}", e),
}
}
}
Receiving the following error.
error[E0597]: `file` does not live long enough
--> src/main.rs:13:33
|
13 | let file_name = file.file_name().unwrap().to_str();
| ^^^^ borrowed value does not live long enough
14 | file_names.push(file_name.unwrap());
| ---------- borrow later used here
15 | }
16 | Err(e) => println!("{:?}", e),
| - `file` dropped here while still borrowed
error: aborting due to previous error
I'm not sure how to push the file names into the vector. Thanks!
Thanks to #PeterHall this is the corrected code.
use glob::glob;
use std::env;
fn main() {
let mut file_names: Vec<String> = Vec::new();
let cwd = env::current_dir().unwrap();
for entry in glob(cwd.to_str().unwrap()).expect("Failed to read logs directory.") {
match entry {
Ok(file) => {
println!("{:?}", file.file_name());
let file_name = file.file_name().unwrap().to_str().unwrap();
file_names.push(file_name.to_string());
}
Err(e) => println!("{:?}", e),
}
}
for file_name in file_names {
println!("{:?}", file_name);
}
}
I'm rewriting a simple TCP based server to experiment with Rust. It should retrieve input of an client and then match that input to run a function:
use std::io::BufRead;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::Write;
use std::net::{TcpListener, TcpStream};
use std::thread;
fn handle_connection(stream: TcpStream) {
let stream_clone = stream.try_clone().unwrap();
let mut reader = BufReader::new(stream);
let mut writer = BufWriter::new(stream_clone);
loop {
let mut s = String::new();
reader.read_line(&mut s).unwrap();
match s.as_str() {
//"test" => writer.write(s.as_bytes()).unwrap();
"test" => writer.write(b"test successfull").unwrap(),
_ => writer.write(b"Command not recognized...").unwrap(),
}
writer.flush().unwrap();
}
}
fn main() {
let listener = TcpListener::bind("127.0.0.1:8888").unwrap();
for stream in listener.incoming() {
thread::spawn(move || {
handle_connection(stream.unwrap());
});
}
}
And the error:
error[E0308]: mismatched types
--> src/main.rs:16:9
|
16 | / match s.as_str() {
17 | | //"test" => writer.write(s.as_bytes()).unwrap();
18 | | "test" => writer.write(b"test successfull").unwrap(),
19 | | _ => writer.write(b"Command not recognized...").unwrap(),
20 | | }
| |_________^ expected (), found usize
|
= note: expected type `()`
found type `usize`
My main problem now is to check the retrieved bytes if they belong to an match and I'm not quite sure how to achieve that.
I couldn't find a fix for this online, rustc --explain didn't help me either
Add a semicolon after your match expression.
The type of all of the match arms is usize, so the resulting type of the match is also a usize. Your code is effectively
fn main() {
{
42
}
println!("Hi");
}
error[E0308]: mismatched types
--> src/main.rs:3:9
|
3 | 42
| ^^ expected `()`, found integer
See also:
Why don't we add a semicolon (;) at the end of if/else?
Are semicolons optional in Rust?
I'm rewriting a simple TCP based server to experiment with Rust. It should retrieve input of an client and then match that input to run a function:
use std::io::BufRead;
use std::io::BufReader;
use std::io::BufWriter;
use std::io::Write;
use std::net::{TcpListener, TcpStream};
use std::thread;
fn handle_connection(stream: TcpStream) {
let stream_clone = stream.try_clone().unwrap();
let mut reader = BufReader::new(stream);
let mut writer = BufWriter::new(stream_clone);
loop {
let mut s = String::new();
reader.read_line(&mut s).unwrap();
match s.as_str() {
//"test" => writer.write(s.as_bytes()).unwrap();
"test" => writer.write(b"test successfull").unwrap(),
_ => writer.write(b"Command not recognized...").unwrap(),
}
writer.flush().unwrap();
}
}
fn main() {
let listener = TcpListener::bind("127.0.0.1:8888").unwrap();
for stream in listener.incoming() {
thread::spawn(move || {
handle_connection(stream.unwrap());
});
}
}
And the error:
error[E0308]: mismatched types
--> src/main.rs:16:9
|
16 | / match s.as_str() {
17 | | //"test" => writer.write(s.as_bytes()).unwrap();
18 | | "test" => writer.write(b"test successfull").unwrap(),
19 | | _ => writer.write(b"Command not recognized...").unwrap(),
20 | | }
| |_________^ expected (), found usize
|
= note: expected type `()`
found type `usize`
My main problem now is to check the retrieved bytes if they belong to an match and I'm not quite sure how to achieve that.
I couldn't find a fix for this online, rustc --explain didn't help me either
Add a semicolon after your match expression.
The type of all of the match arms is usize, so the resulting type of the match is also a usize. Your code is effectively
fn main() {
{
42
}
println!("Hi");
}
error[E0308]: mismatched types
--> src/main.rs:3:9
|
3 | 42
| ^^ expected `()`, found integer
See also:
Why don't we add a semicolon (;) at the end of if/else?
Are semicolons optional in Rust?