Accept optional file on command line, default to stdin [closed] - rust

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 10 months ago.
This post was edited and submitted for review 10 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
I'm building a CLI program that takes as an optional final argument the name of a file to read from, which may be left off to read from standard input instead, as with cat and similar UNIX programs.
Is there any way I could have clap populate a member of my Cli struct with something like a Box<dyn BufRead> initialized from either the file or stdin, or is this just something I'm going to have to handle manually?
Not sure why this was closed as opinion-based, but it seems that the answer to my question is "no". There's no simple way to prepopulate a struct with an open reader on the right thing using only clap's built-in parsing, and I have to do it manually. Case closed.
I wasn't looking for how best to do it manually, just asking if there was a feature I'd overlooked that would let me avoid having to.

This solution: Doesn't use dynamic dispatch, is verbose, use default_value_t, require nightly see #93965 (It should be possible to not require nightly but it's was simpler for me)
use clap; // 3.1.6
use std::fmt::{self, Display, Formatter};
use std::fs::File;
use std::io::{self, stdin, BufRead, BufReader, Read, StdinLock};
use std::str::FromStr;
enum Input {
Stdin(StdinLock<'static>),
File(BufReader<File>),
}
impl Display for Input {
fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), fmt::Error> {
write!(fmt, "Input")
}
}
impl Default for Input {
fn default() -> Self {
Self::Stdin(stdin().lock())
}
}
impl FromStr for Input {
type Err = io::Error;
fn from_str(path: &str) -> Result<Self, <Self as FromStr>::Err> {
File::open(path).map(BufReader::new).map(Input::File)
}
}
impl BufRead for Input {
fn fill_buf(&mut self) -> Result<&[u8], io::Error> {
match self {
Self::Stdin(stdin) => stdin.fill_buf(),
Self::File(file) => file.fill_buf(),
}
}
fn consume(&mut self, amt: usize) {
match self {
Self::Stdin(stdin) => stdin.consume(amt),
Self::File(file) => file.consume(amt),
}
}
}
impl Read for Input {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
match self {
Self::Stdin(stdin) => stdin.read(buf),
Self::File(file) => file.read(buf),
}
}
}
#[derive(clap::Parser)]
struct Reader {
#[clap(default_value_t)]
input: Input,
}

You can use an Option<PathBuf> and use stdin when None, everything wrapped into a method (yes, you have to implement it yourself):
use std::io::BufReader;
use clap;
use std::io::BufRead;
use std::path::PathBuf; // 3.1.6
#[derive(clap::Parser)]
struct Reader {
input: Option<PathBuf>,
}
impl Reader {
fn reader(&self) -> Box<dyn BufRead> {
self.input.as_ref()
.map(|path| {
Box::new(BufReader::new(std::fs::File::open(path).unwrap())) as Box<dyn BufRead>
})
.unwrap_or_else(|| Box::new(BufReader::new(std::io::stdin())) as Box<dyn BufRead>)
}
}
Playground

Related

Returning Result type in Rust

I'm very new to Rust, since I decided to jump directly from Python to challenge myself.
I couldn't figure out the Result return type, so I thought maybe here I would find some help.
I'm currently writing a program which implements an input(message) function, like so:
fn input(message: &str) -> io::Result<String> {
print!("{}", message);
io::stdout().flush()?;
let mut user_input = String::new();
io::stdin().read_line(&mut user_input)?;
Ok(user_input.trim().to_owned())
}
(From a tutorial). The code works fine, but I'm trying to figure out how I could use std::result::Result instead of io::Result, just because.
I tried converting it to:
fn input(message: &str) -> Result<String, Error> {
/* */
}
But the compiler let me know that the question mark operator can't convert its error into std::fmt::Error.
I'm just trying to figure out how to use Result correctly as a return type.
Should I specify an Err(something) return? In that case, I wouldn't even know how to do that.
I'm in need of a clear explanation of what the hell is going on (like, veeery clear so my monkey brain can comprehend stuff). Thanks in advance, people.
You can combine Errors in your custom ErrorType:
#[derive(Debug)]
enum MyCustomError {
ParseError(ParseIntError),
IoError(std::io::Error),
}
impl std::error::Error for MyCustomError {}
impl fmt::Display for MyCustomError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MyCustomError::ParseError(e) => write!(f, "Parse Error {e}"),
MyCustomError::IoError(e) => write!(f, "Io Error {e}"),
}
}
}
Or you can use dyn errors (read more in rustbook):
fn throw_dyn_error() -> Result<(), Box<dyn error::Error>> {
//...
Err("What happens".into())
}
In other production-ready way you can use
anyhow crate and thiserror crate

Make returned Future Send if parameters are Send

Can I propagate the Send trait of function parameters to its return type, so that the return type is impl Send if and only if the parameters are?
Details:
An async function has a nice feature. Its returned Future is automatically Send if it can be. In the following example, the async function will create a Future that is Send, if the inputs to the function are Send.
struct MyStruct;
impl MyStruct {
// This async fn returns an `impl Future<Output=T> + Send` if `T` is Send.
// Otherwise, it returns an `impl Future<Output=T>` without `Send`.
async fn func<T>(&self, t: T) -> T {
t
}
}
fn assert_is_send(_v: impl Send) {}
fn main() {
// This works
assert_is_send(MyStruct.func(4u64));
// And the following correctly fails
assert_is_send(MyStruct.func(std::rc::Rc::new(4u64)));
}
playground
Now, I want to move such a function into a trait, which requires using async-trait (which is some codegen that effectively writes my async fn as a function returning Pin<Box<dyn Future>>) or doing something similar manually. Is there a way to write this in a way to retain this auto-Send behavior where the returned Future is made Send if T is Send? The following example implements it as two separate functions:
use std::pin::Pin;
use std::future::Future;
struct MyStruct;
impl MyStruct {
fn func_send<T: 'static + Send>(&self, t: T) -> Pin<Box<dyn Future<Output = T> + Send>> {
Box::pin(async{t})
}
fn func_not_send<T: 'static>(&self, t: T) -> Pin<Box<dyn Future<Output = T>>> {
Box::pin(async{t})
}
}
fn assert_is_send(_v: impl Send) {}
fn main() {
// This works
assert_is_send(MyStruct.func_send(4u64));
// And the following correctly fails
// assert_is_send(MyStruct.func(std::rc::Rc::new(4u64)));
}
playground
But actually, I don't want them to be separate. I want them to be one function similar to how async fn does it automatically. Something along the lines of
use std::pin::Pin;
use std::future::Future;
struct MyStruct;
impl MyStruct {
fn func<T: 'static + ?Send>(&self, t: T) -> Pin<Box<dyn Future<Output = T> + ?Send>> {
Box::pin(async{t})
}
}
fn assert_is_send(_v: impl Send) {}
fn main() {
// This should
assert_is_send(MyStruct.func(4u64));
// And this should fail
assert_is_send(MyStruct.func(std::rc::Rc::new(4u64)));
}
Is something like this possible in Rust? I'm ok with writing the async-trait magic manually and modifying it instead of using the async-trait crate if that is a way to make it work.
Some ideas I had but they haven't really borne fruit yet:
Use min-specialization to specialize on Send? But doesn't seem like that feature is going to be stabilized anytime soon so maybe not the best option.
Return a custom MyFuture type instead of just impl Future and somehow impl Send for MyFuture where T: Send? Would probably be difficult though since I would have to be able to name that Future and async code usually produces impl Future types that cannot be named.
Writing a procedural macro that adds + Send to the return type if it recognizes that the input type is Send. Actually, can procedural macros detect if a certain type implements Send? My guess would be it's not possible since they just work on token streams.
(2) is the only way that could work.
There are two ways to make it work:
Write the future manually, without the help of async and .await. But that means writing the future manually:
enum ConditionalSendFut<T> {
Start { t: T },
Done,
}
impl<T> Unpin for ConditionalSendFut<T> {}
impl<T> Future for ConditionalSendFut<T> {
type Output = T;
fn poll(mut self: Pin<&mut Self>, _context: &mut Context<'_>) -> Poll<Self::Output> {
match &mut *self {
Self::Start { .. } => {
let t = match std::mem::replace(&mut *self, Self::Done) {
Self::Start { t } => t,
_ => unreachable!(),
};
Poll::Ready(t)
}
Self::Done => Poll::Pending,
}
}
}
struct MyStruct;
impl MyStruct {
fn func<T: 'static>(&self, t: T) -> ConditionalSendFut<T> {
ConditionalSendFut::Start { t }
}
}
Playground.
Store a Pin<Box<dyn Future<Output = T>>> and conditionally impl Send on the future. But this requires unsafe code and manually ensuring that you don't hold other non-Send types across .await points:
struct ConditionalSendFut<T>(Pin<Box<dyn Future<Output = T>>>);
// SAFETY: The only non-`Send` type we're holding across an `.await`
// point is `T`.
unsafe impl<T: Send> Send for ConditionalSendFut<T> {}
impl<T> Future for ConditionalSendFut<T> {
type Output = T;
fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
self.0.as_mut().poll(context)
}
}
struct MyStruct;
impl MyStruct {
fn func<T: 'static>(&self, t: T) -> ConditionalSendFut<T> {
ConditionalSendFut(Box::pin(async { t }))
}
}
Playground.
(1) cannot work with traits, as each impl will have a different future. This leaves us with (2) only. I would not recommend it, but it is possible.
It is very likely that when async fns in traits will be stable there will be a mechanism to that (what is talked about currently is to impl them conditionally and use bounds on use sites to require them) but currently there is no such thing, even on the nightly implementation of async fns in traits.

How to implement `Futures::poll` over internal `async fn func(mut self)` method that takes full ownership? [duplicate]

This question already has answers here:
How to implement a Future or Stream that polls an async fn?
(2 answers)
Closed 5 months ago.
How to implement Futures::poll the the following code that will call async method with full ownership to the self?
use anyhow::Error;
use futures::Future;
use futures::channel::oneshot;
use futures::task::{Context, Poll};
use std::pin::Pin;
struct MyLongTask {
rx: oneshot::Receiver<()>,
}
impl MyLongTask {
// The method and full ownership to `self` is important to keep!
async fn recv(mut self) -> Result<(), Error> {
self.rx.await.map_err(|_| Error::msg("can't recv"))
}
}
// TryFuture not necessary here
impl Future for MyLongTask {
type Output = Result<(), Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
todo!("how to `self.recv().await` here?")
}
}
fn main() { }
Playground if needed.
You can't call self.recv() inside poll firstly because it does not own self, and secondly because it is not async.
Future::poll is synchronous but must return quickly regardless of whether a return value is ready (that's the whole idea of Poll::Pending).
In your case you should simply delegate the poll to self.rx: (playground)
impl Future for MyLongTask {
type Output = Result<(), Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.rx).poll(cx) {
Poll::Ready(x) => Poll::Ready(x.map_err(|_| Error::msg("can't recv"))),
Poll::Pending => Poll::Pending,
}
}
}
Now instead of using task.recv().await, you can just do task.await.
I'd also suggest you either implement Future or provide the recv method.
Otherwise you could run into trouble later when you change one implementation and forget to change the other.

Calling common method on enum types [duplicate]

This question already has answers here:
Using enums for dynamic polymorphism in Rust
(2 answers)
Closed 2 years ago.
I have created an enum to represent a set of built in types and I am trying to implement fmt::Display by using the existing implementations, however the code seems very repetitive especially as the list of types grows. Is there any cleaner way to achieve this by calling the function once?
pub enum NodeVal {
I8(i8),
I16(i16),
I32(i32),
}
impl fmt::Display for NodeVal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
NodeVal::I8(v) => ::std::fmt::Display::fmt(&v, f),
NodeVal::I16(v) => ::std::fmt::Display::fmt(&v, f),
NodeVal::I32(v) => ::std::fmt::Display::fmt(&v, f)
}
}
}
You can use macros:
use std::fmt;
// macro that implements fmt::Display for each passed variant of `NodeVal`
macro_rules! display_node_val {
($($x:ident),*) => {
impl fmt::Display for NodeVal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
$( NodeVal::$x(v) => fmt::Display::fmt(&v, f), )*
}
}
}
};
}
We can use the above macro as shown below:
pub enum NodeVal {
I8(i8),
I16(i16),
I32(i32),
}
display_node_val!(I8, I16, I32);
fn main() {
println!("{}", NodeVal::I16(3))
}
// => 3
Here is a link to a Rust playground
The code above was derived from this answer

How to print! an Option<Box<struct>>?

I am trying to print an Option<Box<MyStruct>>, but I get a compile error when trying to implement Display for Option<Box<MyStruct>>.
use std::fmt;
fn main() {
let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42}));
println!("{}", maybe_my_struct);
}
struct MyStruct {
foo: i32,
}
impl fmt::Display for Option<Box<MyStruct>> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self {
Some(MyStruct) => write!(formatter, "{}", self.foo),
None => write!(formatter, "No struct"),
}
}
}
The error I get is :
error: the impl does not reference any types defined in this crate;
only traits defined in the current crate can be implemented for arbitrary types [E0117]
I have tried aliasing the Option type, and instead implementing Display for MyOption<Box<MyStruct>>, but that gives the same result. What am I doing wrong?
As you can see, you can't implement a trait you didn't write for a type you didn't write. This is part of what's known as "coherence" and exists to prevent really weird things like linking against a library suddenly causing unrelated parts of your program to change behaviour.
Aliasing Option to MyOption doesn't work either because, as you say, it's an alias. That is, it's just another name for the same thing, it's not an actual, different type.
Now, if you write a wrapper around Option like so:
struct MyOption<T>(Option<T>);
then MyOption will be a new, distinct type that you can implement a trait for. Of course, you'll want to write methods to wrap and unwrap the actual Option you're storing.
... But this is all rather irrelevant since you could also just derive Debug for your struct and use that.
fn main() {
let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42}));
println!("{:?}", Some(maybe_my_struct));
}
#[derive(Debug)]
struct MyStruct {
foo: i32,
}
Or, if you really want the custom display logic for the Option<Box<MyStruct>> combination, you can use a marker value (this same approach is used by Path in the standard library, incidentally). Like so:
use std::fmt;
fn main() {
let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42}));
println!("{:?}", maybe_my_struct);
// Instead of displaying directly, display via a custom marker.
println!("{}", maybe_my_struct.display());
println!("{}", None::<Box<MyStruct>>.display());
}
#[derive(Debug)]
struct MyStruct {
foo: i32,
}
// This is the marker we'll use to define our custom Display impl.
struct MmsDisplay<'a>(&'a Option<Box<MyStruct>>);
// This trait lets us extend Option<Box<MyStruct>> with a new method.
trait CustomMmsDisplay {
fn display<'a>(&'a self) -> MmsDisplay<'a>;
}
impl CustomMmsDisplay for Option<Box<MyStruct>> {
fn display<'a>(&'a self) -> MmsDisplay<'a> {
MmsDisplay(self)
}
}
// And here's the display logic.
impl<'a> fmt::Display for MmsDisplay<'a> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self.0 {
Some(ref ms) => write!(formatter, "{}", ms.foo),
None => write!(formatter, "No struct"),
}
}
}

Resources