bytes
bytes copied to clipboard
implement Write trait for BytesMut per issue #425
There is some discussion of this in #425.
This implements Write for BytesMut exactly as is done for Vec
https://doc.rust-lang.org/src/std/io/impls.rs.html#370-402
Could we add some tests?
Because BufMut already implements fmt::Write, this change will break any code that uses write!()
with a BytesMut while both fmt::Write and io::Write are imported.
@sfackler good catch!
we should add a test to cover this edge case.
At the moment, I'm not sure how to proceed. I don't know how to avoid breaking write!() as @sfackler said, but wow, I'm so glad he caught it.
I don't see a way to proceed with this. It isn't great, but one can always use BufMut::writer()
to adapt.
I would appreciate a test that demonstrates the ability to call write!
with both mentioned traits in scope. You can reuse this PR or submit a new one.
I think you could in theory add an inherent write_fmt
method directly on impl BytesMut
since that would take precedence over either of the trait methods. It's a bit gross though.
Thanks so much for the directions @sfackler and @carllerche. I'll write some tests so we can evaluate them.
I tried adding write_fmt() directly on impl BytesMut, and still saw compiler errors when write!() saw both io::Write and fmt::Write impls.
So here's another option. This adds a BytesMutExt trait that implements io::Write.
It's a bit awkward to use though:. The successful test (included) looks like this:
#[test]
fn fmt_write_bytesmut_with_both_write_in_scope_test() {
use bytes::ext::BytesMutExt;
use bytes::BytesMut;
#[allow(unused_imports)]
use std::fmt::Write as FmtWrite;
use std::io::Write as IoWrite;
let mut buf = BytesMut::with_capacity(64);
write!(&mut buf as &mut dyn BytesMutExt, "hello").ok();
assert_eq!(&buf[..], b"hello");
}
This works, but it's awkward. I'm not sure this is helpful at all.
Please let me know if I've misunderstood the idea of having a write_fmt() directly in impl BytesMut
.
And if you think this is a dead horse, that 's ok too.
Found my way here from the issue. Did you consider something like the following?
write!(buf.as_io_write(), "hello")
I think this is more readable than write!(&mut buf as &mut dyn BytesMutExt, "hello")
and doesn't use dynamic dispatch.
The problem I have with the current BufMut::writer
is that it consumes the BytesMut
which doesn't work when you don't own the it. Eg in a tokio_util::codec::Encoder
I have to std::mem::replace
out the BytesMut
then put it back afterward:
https://github.com/scottlamb/retina/blob/265b6b94901d02b03e51d2b6f3338de899077687/src/lib.rs#L360-L363
fn as_io_write(&mut self) -> IoWriteRef<'_>
(or similar) wouldn't have this problem.
You could do write!((&mut buf).writer(), "hello")
, still I do see the point.
Oh, I didn't think of that. Thanks for the tip! Actually, I would have been perfectly happy if that example were just in writer()
's docstring.