I've recently tried to implement streaming a multipart file to S3 using rust-s3 without having to keep the full file in memory or on disk.
let field: actix_multipart::Field = …;
let payload_stream = field.map_err(|e| {
TokioIoError::new(multipart_error_to_tokio_io_error_kind(&e), anyhow!(e))
});
let mut payload_reader = tokio::io::stream_reader(payload_stream);
bucket
.tokio_put_object_stream(&mut payload_reader, &upload_path)
.await?;
For this to compile (it actually working is blocked on https://github.com/durch/rust-s3/issues/110) I needed some long-winded error conversion code:
fn multipart_error_to_tokio_io_error_kind(e: &MultipartError) -> TokioIoErrorKind {
match e {
MultipartError::Payload(p) => match p {
PayloadError::Incomplete(_) => TokioIoErrorKind::UnexpectedEof,
PayloadError::Io(io) => std_io_error_kind_to_tokio_io_error_kind(io.kind()),
PayloadError::Http2Payload(h2) => match h2.get_io() {
Some(io) => std_io_error_kind_to_tokio_io_error_kind(io.kind()),
None => TokioIoErrorKind::Other,
},
_ => TokioIoErrorKind::Other,
},
_ => TokioIoErrorKind::Other,
}
}
fn std_io_error_kind_to_tokio_io_error_kind(kind: StdIoErrorKind) -> TokioIoErrorKind {
match kind {
StdIoErrorKind::NotFound => TokioIoErrorKind::NotFound,
StdIoErrorKind::PermissionDenied => TokioIoErrorKind::PermissionDenied,
StdIoErrorKind::ConnectionRefused => TokioIoErrorKind::ConnectionRefused,
StdIoErrorKind::ConnectionReset => TokioIoErrorKind::ConnectionReset,
StdIoErrorKind::ConnectionAborted => TokioIoErrorKind::ConnectionAborted,
StdIoErrorKind::NotConnected => TokioIoErrorKind::NotConnected,
StdIoErrorKind::AddrInUse => TokioIoErrorKind::AddrInUse,
StdIoErrorKind::AddrNotAvailable => TokioIoErrorKind::AddrNotAvailable,
StdIoErrorKind::BrokenPipe => TokioIoErrorKind::BrokenPipe,
StdIoErrorKind::AlreadyExists => TokioIoErrorKind::AlreadyExists,
StdIoErrorKind::WouldBlock => TokioIoErrorKind::WouldBlock,
StdIoErrorKind::InvalidInput => TokioIoErrorKind::InvalidInput,
StdIoErrorKind::InvalidData => TokioIoErrorKind::InvalidData,
StdIoErrorKind::TimedOut => TokioIoErrorKind::TimedOut,
StdIoErrorKind::WriteZero => TokioIoErrorKind::WriteZero,
StdIoErrorKind::Interrupted => TokioIoErrorKind::Interrupted,
StdIoErrorKind::UnexpectedEof => TokioIoErrorKind::UnexpectedEof,
_ => TokioIoErrorKind::Other,
}
}
It seems to me like the second function, or sth. better, could just be part of tokio so I wouldn't have to write all of this myself.
Describe the solution you'd like
// in tokio::io
impl From<std::io::Error> for Error { ... }
Describe alternatives you've considered
I'm not actually sure I need all of this error conversion, but it seems like I'm setting myself up for hard to debug errors by just mapping everything to TokioIoErrorKind::Other. I've also looked into not using stream_reader, but haven't found an alternative that would work here. Any tips in that direction would be appreciated, separately from this feature request :slightly_smiling_face:
Tokio's io::Error is std's io::Error: https://docs.rs/tokio/0.2.22/src/tokio/io/mod.rs.html#239.
Oh. Well, seems like I wrote some quite stupid code. Is this documented anywhere?
https://docs.rs/tokio/0.2.22/tokio/io/index.html#std-re-exports
std re-exports
Additionally, Error, ErrorKind, and Result are re-exported from std::io for ease of use.
Most helpful comment
https://docs.rs/tokio/0.2.22/tokio/io/index.html#std-re-exports