Skip to content

allow to_extend to work with reference to write #210

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

e00E
Copy link

@e00E e00E commented Feb 3, 2025

Currently the function takes the collection by value. Taking by mutable reference is better because it is more flexible. Whenever you have a value, you can also pass by mutable reference, but sometimes you only have a mutable reference and cannot pass by value.

This also fixes another problem with the current API: It keeps the collection on error. On success it returns it to the caller, but on error it does not. This makes the caller lose the collection.

I implement this as a new function rather than by changing the existing to_extend so that this is not a breaking change. When postcard is willing to make breaking changes in the future, then it could decide to remove the existing to_extend.

This is an alternative to #208 .

Currently the function takes the collection by value. Taking by mutable reference is better because it is more flexible. Whenever you have a value, you can also pass by mutable reference, but sometimes you only have a mutable reference and cannot pass by value.

This also fixes another problem with the current API: It keeps the collection on error. On success it returns it to the caller, but on error it does not. This makes the caller lose the collection.

I implement this as a new function rather than by changing the existing to_extend so that this is not a breaking change. When postcard is willing to make breaking changes in the future, then it could decide to remove the existing to_extend.
Copy link

netlify bot commented Feb 3, 2025

Deploy Preview for cute-starship-2d9c9b canceled.

Name Link
🔨 Latest commit 7713140
🔍 Latest deploy log https://app.netlify.com/sites/cute-starship-2d9c9b/deploys/67a09a1be0929700089ae15c

@Shatur
Copy link

Shatur commented Feb 5, 2025

Can we also have something like this for Vec? I think it might be more optimal then using Extend.

@e00E
Copy link
Author

e00E commented Feb 5, 2025

It's not necessary. The only difference is that on a vector you can call reserve, which you can't do through Extend. And the standard library already has special handling making extending vectors with slices faster.

@Shatur
Copy link

Shatur commented Feb 5, 2025

Do you think that compiler replaces self.iter.extend(b.iter().copied()); with memcpy? 🤔

@e00E
Copy link
Author

e00E commented Feb 6, 2025

If self is Vec<u8> and the other iter is over [u8] then yes.

fn foo(extend: &mut impl Extend<u8>, iter: impl Iterator<Item = u8>) {
    extend.extend(iter);
}

pub fn with_extend(a: &mut Vec<u8>, b: &[u8]) {
    foo(a, b.iter().copied());
}

pub fn with_extend_from_slice(a: &mut Vec<u8>, b: &[u8]) {
    a.extend_from_slice(b);
}

Both of the pub functions will reserve the right amount of space in the vector and then call memcpy. https://godbolt.org/z/81o3hvj58

Copy link

@Shatur Shatur left a comment

Choose a reason for hiding this comment

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

Thanks, I copied the implementation into my project, works perfectly :)

I left a couple suggestions.

///
/// This is like [`ExtendFlavor`], but it takes the writer by reference instead of
/// by value. This allows you to remain in control of the writer.
pub struct ExtendRefFlavor<'a, T> {
Copy link

Choose a reason for hiding this comment

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

Maybe use the word "mut" instead? When I see "ref", I usually expect &.

Suggested change
pub struct ExtendRefFlavor<'a, T> {
pub struct ExtendMutFlavor<'a, T> {

/// This is like [`ExtendFlavor`], but it takes the writer by reference instead of
/// by value. This allows you to remain in control of the writer.
pub struct ExtendRefFlavor<'a, T> {
iter: &'a mut T,
Copy link

Choose a reason for hiding this comment

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

Maybe call it bytes? Extend is not a trait for iterator, it represent a collection that can accept an iterator to extend itself.

Suggested change
iter: &'a mut T,
bytes: &'a mut T,

where
T: core::iter::Extend<u8>,
{
type Output = ();
Copy link

Choose a reason for hiding this comment

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

Maybe return used size for convenience?

@jamesmunns jamesmunns added the Q2 '25 Triage Items tracked as part of https://github.com/jamesmunns/postcard/issues/241 label Jun 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Q2 '25 Triage Items tracked as part of https://github.com/jamesmunns/postcard/issues/241
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants