Is there support for the `std::io::Read` trait somehow?
I'm trying to use windows::Web::Http::HttpClient to download a file. I'm using HttpClient::GetInputStreamAsync to get an IInputStream and would like to somehow pass that to a function that expects something that implements the std::io::Read trait. Is that somehow possible? Or am I entirely on the wrong track here? It seems to me that somehow on some very general level I'm getting a stream from the Windows API here, and it would be nice if that composed nicely with the standard trait for reading from streams in Rust :)
That would actually require a trait with an async fn, which—to my knowledge—is not supported (IInputStream only exposes a ReadAsync method).
I'm not sure if we really need async in this case, since IAsyncOperation has a sync get method. I think the actual problem when implementing io::Read for IInputStream is the fact that you can't create a buffer(-view), that ReadAsync could read into.
However, there is an argument to be made that io::Read should be implemented for DataReader (and similarly io::Write for DataWriter - or the respective interface).
Proof of concept implementation
// for demonstration
#![feature(io_read_to_string)]
use std::io;
use windows::{
core::Result,
w,
Foundation::Uri,
Storage::Streams::{DataReader, IInputStream, InputStreamOptions},
Web::Http::{HttpClient, IHttpContent},
};
struct DataReaderWrap(DataReader);
impl io::Read for DataReaderWrap {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let mut bytes =
self.0
.LoadAsync(buf.len() as u32)
.map_err(|e| io::Error::from_raw_os_error(e.code().0))?
.get()
.map_err(|e| io::Error::from_raw_os_error(e.code().0))? as usize;
bytes = bytes.min(buf.len());
self.0
.ReadBytes(&mut buf[0..bytes])
.map_err(|e| io::Error::from_raw_os_error(e.code().0))
.map(|_| bytes)
}
}
fn main() -> Result<()> {
let uri = Uri::CreateUri(w!("https://www.rust-lang.org/"))?;
let http: HttpClient = HttpClient::new()?;
let content: IHttpContent = http.GetAsync(&uri)?.get()?.Content()?;
let is: IInputStream = content.ReadAsInputStreamAsync()?.get()?;
let reader = DataReader::CreateDataReader(&is)?;
// not needed but this might improve performance
reader.SetInputStreamOptions(InputStreamOptions::ReadAhead)?;
println!("{:?}", io::read_to_string(DataReaderWrap(reader)));
Ok(())
}
@Nerixyz Fantastic, that piece of code solved my problem completely, thanks so much! And agreed, it would be nice if that was included by default in the crate.
Neat, thanks for the example @Nerixyz! I'll think about whether this trait can offered automatically.