Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let PacketWriter::write_packet use buffers convertible to Cow #25

Merged
merged 5 commits into from
Jan 14, 2022
Merged

Let PacketWriter::write_packet use buffers convertible to Cow #25

merged 5 commits into from
Jan 14, 2022

Conversation

AlexTMjugador
Copy link
Contributor

As pointed out in issue #19, in some cases it may not be desirable to heap allocate Ogg packet contents, but the current parameters of the write_packet method impose a heap allocation no matter what.

However, the PacketWriter struct doesn't actually need to own the packet data, as long as it stays in memory unmodified during its lifetime. The Cow smart pointer that the standard library provides captures this requirement more precisely, and provides for more elegant, flexible and potentially efficient client code.

Therefore, substitute Box for Cow in the aforementioned code. Boxed slices can still be used with this new design, although with a different syntax, which breaks backwards compatibility.

As pointed out in issue #19, in some cases it may not be desirable to
heap allocate Ogg packet contents, but the current parameters of the
`write_packet` method impose a heap allocation no matter what.

However, the `PacketWriter` struct doesn't actually need to own the
packet data, as long as it stays in memory unmodified during its
lifetime. The `Cow` smart pointer that the standard library provides
captures this requirement more precisely, and provides for more elegant,
flexible and potentially efficient client code.

Therefore, substitute `Box` for `Cow` in the aforementioned code. Boxed
slices can still be used with this new design, although with a different
syntax, which breaks backwards compatibility.
Copy link
Member

@est31 est31 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I wonder if it's possible to have something more general than Cow. Maybe AsRef<[u8]> or something?

src/writing.rs Outdated Show resolved Hide resolved
@AlexTMjugador
Copy link
Contributor Author

AlexTMjugador commented Sep 9, 2021

I wonder if it's possible to have something more general than Cow. Maybe AsRef<[u8]> or something?

This sounds like a good idea, thanks! However, after swapping the generic Into<Cow<[u8]>> parameter for AsRef<[u8]>, I found the result less ergonomic, because the write_packet method would need to always take a reference to a byte buffer, and not be able to accept an owned buffer like Vec<u8> (otherwise Rust would drop the maybe owned AsRef<[u8]> parameter at the end of the method body, which does not compile, because it needs to be converted to a byte buffer by calling as_ref, which borrows it. It may be possible to workaround this by adding additional type parameters to the struct or something like that, but that sounds like a fair amount of redesign work for not so much gain, and caller code would probably need to always provide buffers of the same type.)

On the other hand, with the current approach, the caller can just convert whatever type that implements AsRef<[u8]> beforehand to a byte slice by calling as_ref on that type, and things would still work fine because a Cow can then be constructed from that borrowed byte slice. So I'd argue that it's still flexible enough to accept a wide variety of byte buffers, although as I explained before the lifetime requirements are a bit longer than a user might expect, as it is necessary to call as_ref relatively "early", so the borrow lasts for long enough.

Another advantage I can see from using a Cow is that, in the (very?) unlikely case that this library is changed so there is a need to modify packet data before writing it, a Cow can also support that as efficiently as possible, because if the user already provided a Vec<u8> to the method, its memory buffer will be reused without any additional cost.

Newer Rust versions work introduced additional lifetime inference rules
that made this code work, but they are not available in the MSRV this
library targets.
@est31
Copy link
Member

est31 commented Sep 10, 2021

Good point about the need for a generic param. The PR should be good now but I won't merge it for now because it is a breaking change of the API. I want to make a new release of the ogg crate once the 2021 edition lands though.

@AlexTMjugador
Copy link
Contributor Author

AlexTMjugador commented Sep 10, 2021

That's understandable, thanks. However, right now it's bugging me a bit that the CI build for Rust 1.27.2 does not pass, as I've developed this PR using the latest Rust version and used some syntax that simply didn't compile back then. Do you plan on bumping MSRV on the next release? Should I continue to fix compilation with this older Rust version?

@est31
Copy link
Member

est31 commented Sep 10, 2021

@AlexTMjugador no, the MSRV will be increased to 1.56.0.

This reverts commit 01ee00e.

Fixing this build error is no longer necessary because MSRV will be
bumped to the current stable version, which accepts this shorter syntax.
@est31 est31 merged commit 6c53277 into RustAudio:master Jan 14, 2022
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 1, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 1, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 1, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 1, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 2, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 2, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 2, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 2, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 2, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 2, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 2, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
yubiuser added a commit to yubiuser/librespot that referenced this pull request Apr 2, 2023
Signed-off-by: Christian König <ckoenig@posteo.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants