Repository: rust
Issue: Alloc: Clarify supported Layouts
Labels: A-allocators,T-libs-api,C-feature-request

# TLDR
The `Alloc` trait doesn't currently document what `Layout`s are guaranteed to be supported, which leaves consumers unsure whether their allocations will fail with `AllocErr::Unsupported`. This issue proposes addressing this by introducing a distinction between "general" and "specialized" allocators, and documenting a set of required `Layout`s that the former must be able to handle.

# Problem Statement
One of the errors that the `Alloc` trait's allocation methods can return is `AllocErr::Unsupported`, which indicates that the allocator doesn't support the requested `Layout`. Currently, the `Alloc` trait places no restrictions - either using the type system or in documentation - on what `Layout`s must be supported. Thus, consumers of a generic `Alloc` (as opposed to a particular type that implements `Alloc`) must assume that any given allocation request might be unsupported.

This creates a problem: in order for a consumer of an `Alloc` to be able to guarantee to their users that they will not crash at runtime (after all, having gotten `AllocErr::Unsupported`, there's really no other recourse other than to abort or bubble up the error), they need to document the set of `Layout`s that they might request from an allocator provided by the user. This, in turn, requires that all implementations of `Alloc` document precisely which `Layout`s they can handle so that users can ensure that they're upholding the requirements of the consumers. Even if all of this documentation was written and maintained, it'd impose a very large burden on the users. Imagine every time you wanted to use `Vec<T, A: Alloc>` for a particular, custom `A`, you had to carefully read the `Vec` documentation and the documentation for the desired allocator to ensure they were compatible.

Worse still, the current mechanism for configuring the global allocator involves providing an instance of `Alloc`. In this case, there's no way for code to communicate to the person configuring the global allocator what their requirements are, since that code might be buried behind an arbitrary number of dependencies (e.g., I use crate `foo` which depends on crate `bar` which depends on crate `baz` which is incompatible with the global allocator I've configured).

This came up in practice for me while working on my [slab-alloc](https://crates.io/crates/slab-alloc) crate (which is basically just an object cache). I allow users to provide a custom `Alloc` to back a `SlabAlloc` instance, but I currently have no way other than in documentation to ensure that the provided `Alloc`s will be compatible with the allocations I perform. If, for example, a user were to provide an allocator incapable of providing page-aligned allocations, or if somebody upstream of my crate configured a global allocator with this limitation, my code would crash at runtime.

# Proposal
In order to address this issue, I propose introducing (in the `Alloc` trait's documentation) the notion of a "general allocator," which is an implementation of the `Alloc` trait which guarantees the ability to handle a certain class of standard allocation requests.

All implementations of `Alloc` are assumed to be general allocators unless documented to the contrary. All consumers of an `Alloc` type parameter are assumed to be compatible with a general allocator (that is, they do not perform any allocations which are outside of the set of guaranteed-to-be-supported allocations) unless documented to the contrary.

An allocation is guaranteed to be supported so long as it meets the following criteria:
- The size is non-zero
- The alignment is a non-zero power of two (this is already enforced by `Layout`)
- The size is a multiple of the alignment (this is already enforced by `Layout`)
- The alignment is not larger than the system's page size
- The size is not larger than 2^31 bytes on 32-bit platforms or 2^47 on 64-bit platforms

This system does not hamstring special-case uses. `Alloc` implementations which do not provide all of these guarantees merely need to document this. `Alloc` consumers which require more than what a general allocator guarantees merely need to document this, placing the onus on their users to provide an appropriate `Alloc`.

## Open questions
- A 2^31 byte limit on 32-bit platforms might be limiting, so it might be worth making it 2^32 - 1 bytes (and 2^48 - 1 on 64-bit) instead. My concern is how this will play with signed integers, but that might be the sort of thing that it's reasonable to expect an allocator implementor to just be careful about.