Given the code below, how can I specifically check for EOF? Or rather, how can I distinguish between "there's nothing here" and "it exploded"?
match io::stdin().read_line() {
Ok(l) => print!("{}", l),
Err(_) => do_something_else(),
}
From the documentation for read_line:
If successful, this function will return the total number of bytes read.
If this function returns Ok(0), the stream has reached EOF.
This means we can check for a successful value of zero:
use std::io::{self, BufRead};
fn main() -> io::Result<()> {
let mut empty: &[u8] = &[];
let mut buffer = String::new();
let bytes = empty.read_line(&mut buffer)?;
if bytes == 0 {
println!("EOF reached");
}
Ok(())
}
Related
I am writing a client for a Unix Domain Socket, which should listen for messages from a server, I got it to work after hours of researching (it shows 1-2 messages), but after that tokio crashes with the error: Error: Kind(WouldBlock), here is my code:
use std::env::{var, VarError};
use std::io::{self, Write};
use tokio::net::UnixStream;
#[tokio::main]
async fn main() -> io::Result<()> {
let hypr_instance_sig = match var("HYPRLAND_INSTANCE_SIGNATURE") {
Ok(var) => var,
Err(VarError::NotPresent) => panic!("Is hyprland running?"),
Err(VarError::NotUnicode(_)) => panic!("wtf no unicode?"),
};
let socket_path = format!("/tmp/hypr/{hypr_instance_sig}/.socket2.sock");
let stream = UnixStream::connect(socket_path).await?;
loop {
stream.readable().await?;
let mut buf = [0; 4096];
stream.try_read(&mut buf)?;
io::stdout().lock().write_all(&buf)?;
}
}
Could someone please help me?
I fully agree with #Caesar's comment.
don't use try_read, use read instead
slice the buffer to the correct size after reading
check for 0 bytes read, which indicates that the end of the stream was reached
use std::env::{var, VarError};
use std::io::{self, Write};
use tokio::io::AsyncReadExt;
use tokio::net::UnixStream;
#[tokio::main]
async fn main() -> io::Result<()> {
let hypr_instance_sig = match var("HYPRLAND_INSTANCE_SIGNATURE") {
Ok(var) => var,
Err(VarError::NotPresent) => panic!("Is hyprland running?"),
Err(VarError::NotUnicode(_)) => panic!("wtf no unicode?"),
};
let socket_path = format!("/tmp/hypr/{hypr_instance_sig}/.socket2.sock");
let mut stream = UnixStream::connect(socket_path).await?;
let mut buf = [0; 4096];
loop {
let num_read = stream.read(&mut buf).await?;
if num_read == 0 {
break;
}
let buf = &buf[..num_read];
io::stdout().lock().write_all(buf)?;
}
Ok(())
}
Disclaimer: I didn't test the code because I don't have the required socket file. It compiles, though.
I am making a random number guessing program with Rust but when I check for an actual number I get an error that says "expected i16, found enum std::result::Result".
use rand::Rng; // 0.8.0
use std::io::{stdin, stdout, Write};
use std::process;
use std::result::Result;
fn read(input: &mut String) {
stdout().flush().expect("failed to flush");
stdin().read_line(input).expect("failed to read");
}
fn main() {
loop {
let mut number = String::new();
let rand_ = rand::thread_rng().gen_range(1..10);
let mut killcheck = String::new();
println!("Input a number between 0 and 10 \n");
match rand_ {
1..=5 => println!("it is 1 through 5"),
5..=10 => println!("it is 5 through 10"),
_ => continue,
}
read(&mut number);
let number: i16 = number.trim().parse::<i16>().unwrap();
match number {
Ok(ok) => continue,
Err(e) => println!("No number could be found"),
_ => continue
}
read(&mut killcheck);
if killcheck.trim() == "end" {
println!("error is null");
process::exit(0x0100);
}
if number == rand_ {
println!("Currect!\n")
}
if number != rand_ {
println!("Incorrect!\n")
}
read(&mut killcheck);
if killcheck.trim() == "end" {
println!("error is null");
process::exit(0x0100);
}
}
}
I don't understand the problem, I would think it would just be checking if it can happen then continue.
let number: i16 = number.trim().parse::<i16>().unwrap(); //*number is i16 type with the use of unwrap() instead of Result*
match number {
Ok(ok) => continue, //*It should be some i16 numbers here instead of Result(Ok/Err)*
Err(e) => println!("No number could be found"),
_ => continue
}
I do check function results on assignment using match statement. In some cases I want to exit the program with an error message like panic!() does. But how can I create a function or macro that can be used everywhere?
Example:
let args = match args::Args::parse() {
Ok(args) => args,
Err(e) => someerror("bla")
};
let mut statedoc = match state_loader.load() {
Ok(states) => states,
Err(e) => someerror("blub")
};
What does someerror() need to return to work everywhere?
One way is to use diverging function. Use the following syntax:
fn someerror(msg: &str) -> ! { // Note the `-> !` here
eprintln!("Error: {}", msg);
panic!();
}
fn main() {
let r: Result<i32, &str> = Err("hello");
let x = match r {
Ok(x) => x,
Err(e) => someerror(e),
};
println!("x = {}", x);
}
Remember that main can return a Result and you can use the ?-operator everywhere:
fn foo() -> Result<i32, &'static str> {
Err("Nope!")
}
fn main() -> Result<(), &'static str> {
let x = 5 * foo()?;
println!("{}", x);
Ok(())
}
When executed, the above program will just print "Error: Nope!" and have an exit status not equal to zero. To support more kinds of errors, you can have a a custom enum to wrap those and appropriate implementations of Into, so you can just do let args = args::Args::parse()?;. Any errors will bubble up to main() and cause the error to be printed out.
My example is slightly modified from the guessing game tutorial in The Rust Book.
After the first iteration, the loop does not appear to read in the user input to the mutable string correctly.
Can you please identify what is wrong in the below code with regards to mut input_text?
extern crate rand;
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
let random_number = rand::thread_rng().gen_range(1, 51);
let mut input_text = String::new(); // Works fine if allocated inside loop
loop {
println!("Enter your guess:");
io::stdin()
.read_line(&mut input_text)
.expect("Failed to read input");
let input_number: u32 = match input_text.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!(
"You entered {} which converted to u32 is {}",
input_text, input_number
);
match input_number.cmp(&random_number) {
Ordering::Greater => println!("Input > Random"),
Ordering::Less => println!("Input < Random"),
Ordering::Equal => println!("Input == Random"),
}
}
}
As #Jmb mentioned in the comments, read_line doesn't overwrite the String but appends to it. If you'd like to overwrite the String you have to first call clear on it like so:
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
let random_number = rand::thread_rng().gen_range(1, 51);
let mut input_text = String::new();
loop {
println!("Enter your guess:");
// clear input_text from previous loop iteration
input_text.clear();
io::stdin()
.read_line(&mut input_text)
.expect("Failed to read input");
let input_number: u32 = match input_text.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!(
"You entered {} which converted to u32 is {}",
input_text.trim(), input_number
);
match input_number.cmp(&random_number) {
Ordering::Greater => println!("Input > Random"),
Ordering::Less => println!("Input < Random"),
Ordering::Equal => {
println!("Input == Random");
break; // break on win condition
},
}
}
}
Also your program was an infinite loop so I added a break on the win condition.
I'm trying to get a String from standard input:
use std::io;
fn ask_nick() -> String {
let reader = io::stdin();
let mut buffer: String = String::new();
let nickname: String = reader.read_line(&mut buffer).ok()
.expect("ERRMSG").to_string();
println!("OK: Hello {}!", &nickname);
return nickname;
}
}
fn main() {
let nickname: String = ask_nick();
println!("{}", nickname);
}
But conversion from usize to String seems to change contents to it's length:
INPUT:= John
EXPECTED OUTPUT:= OK: Hello John!
John
OUTPUT:= OK: Hello 5!
5
INPUT:= Doe
EXPECTED OUTPUT:= OK: Hello Doe!
Doe
OUTPUT:= OK: Hello 4!
4
Please see the documentation, and you can see that read_line mutates the contents of its parameter (in your case, the empty string bound at buffer), putting the value read into it, and returns the length read. But you're unwrapping that result and converting that length to a string.
Instead, your function should look like:
fn ask_nick() -> String {
let reader = io::stdin();
let mut buffer: String = String::new();
reader.read_line(&mut buffer)
.ok()
.expect("ERRMSG");
println!("OK: Hello {}!", buffer);
return buffer;
}
Or, even more idiomatically, not panicking when invalid input is provided:
fn ask_nick() -> Result<String> {
let reader = io::stdin();
let mut buffer: String = String::new();
match reader.read_line(&mut buffer) {
Ok(_) => Ok(buffer),
Err(e) => Err(e),
}
}
In this variant, the caller is the one that decides how to handle errors.