Skip to content

NonEmptyLayout - #163739

Open
clarfonthey wants to merge 1 commit into
rust-lang:mainfrom
clarfonthey:nonempty-layout
Open

clarfonthey wants to merge 1 commit into
rust-lang:mainfrom
clarfonthey:nonempty-layout

Conversation

@clarfonthey

Copy link
Copy Markdown
Contributor

Notes:

  1. We can bikeshed NonEmptyLayout versus NonZeroLayout versus NonZero<Layout> later.
  2. It might be nice to make Layout and NonEmptyLayout explicitly repr(C) or something to allow literally transmuting from Layout to Option<NonEmptyLayout>. I didn't do this here because I know that repr(C) might cause other undesirable side effects.
  3. Right now, new::<T>() uses a const assertion to verify that T is non-zero-sized but new_for(&val) returns Option, with an unchecked variant. Is this the right approach?
  4. Actually making some kind of allocator trait that works on top of this, and try to use it in Box and Vec to avoid the ZST special-casing on allocations specifically (note: there will still be types that need special-casing, like slice::Iter)
  5. Technically adding new API without ACP, but since we've effectively talked about this in wg-allocators and it feels like a reasonable ask, I'm just going to create an MVP of this type and we can work out more details later.

r? nia-e (but I guess you can pass it to someone else if you want)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Oct 4, 2026
@rustbot

rustbot commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator

nia-e is currently at their maximum review capacity.
They may take a while to respond.

@nia-e

nia-e commented Oct 4, 2026

Copy link
Copy Markdown
Member

Was there an ACP for this? It seems like a decently big thing if we ever want to stabilise it (understandable if we want to keep it internal though, i see the rationale there).

in particular regarding extending Allocator, iirc the conclusion of the allocator layout discussion was that there are almost no cases where handling ZSTs isn't trivial on the allocator end.

i could see the case for extra provided methods on the base trait to use this. little worried about vtable size there but would need a benchmark

@clarfonthey

Copy link
Copy Markdown
Contributor Author

There was explicitly no ACP for this, since I mostly just wanted to see how not-awful this would be to implement. In terms of actually making allocators that use it, we definitely wanna have some kind of ACP, since the motivation here is basically in this thread: #t-libs/wg-allocators > Are we sure about zero-sized allocations?

Essentially, it might be useful to define specifically the exact behaviour of Vec and Box in a way that can be replicated across APIs.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

Copy link
Copy Markdown
Collaborator

The job test-pr-check-2 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)


/// Layout of a *non-empty* block of memory.
///
/// This is equivalent to [`Layout`], but with the added restriction that the

@programmerjake programmerjake Oct 4, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

truncated sentence

View changes since the review

}

#[inline]
const fn is_size_align_valid(size: usize, align: usize) -> bool {

@RustyYato RustyYato Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This can be made branchless via

godbolt

pub const fn is_size_align_valid(size: usize, align: usize) -> bool {
    let Some(alignment) = Alignment::new(align) else { return false };
    Self::is_nonzero_size_alignment_valid(size, alignment)
}

const fn is_nonzero_size_alignment_valid(size: usize, alignment: Alignment) -> bool {
    size.wrapping_sub(1) < max_size_for_alignment(alignment)
}

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If you want to optimize the case where size is known to be non-zero,

const fn is_nonzero_size_alignment_valid(size: usize, alignment: Alignment) -> bool {
    if is_val_statically_known(size > 0) {
        size <= max_size_for_alignment(alignment)
    } else {
        size.wrapping_sub(1) < max_size_for_alignment(alignment)
    }
}

Comment on lines +1133 to +1143
let Ok(result) = (if let Some(k) = n.checked_sub(1) {
let Ok(repeated) = padded.repeat_packed(k) else {
return Err(LayoutError);
};
repeated.extend_packed(self.get())
} else {
debug_assert!(n == 0);
self.repeat_packed(0)
}) else {
return Err(LayoutError);
};

@RustyYato RustyYato Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is super confusing to read, can the if let Some(k) = ... part be factored out into a separate variable?
Also, self.repeat_packed(0) is guaranteed to error, so that branch could just be return Err(LayoutError)

View changes since the review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe this instead?

Suggested change
let Ok(result) = (if let Some(k) = n.checked_sub(1) {
let Ok(repeated) = padded.repeat_packed(k) else {
return Err(LayoutError);
};
repeated.extend_packed(self.get())
} else {
debug_assert!(n == 0);
self.repeat_packed(0)
}) else {
return Err(LayoutError);
};
let result = if let Some(k) = n.checked_sub(1) {
let Ok(repeated) = padded.repeat_packed(k) else {
return Err(LayoutError);
};
let Ok(result) = repeated.extend_packed(self.get()) else {
return Err(LayoutError);
};
result
} else {
debug_assert!(n == 0);
return Err(LayoutError);
};

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants