# Pre-(Pre-)RFC: niche types

**URL:** <https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810>\
**Category:** language design\
**Created:** [November 2, 2024, 7:27pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810 "2024-11-02T19:27:48Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![gkgoat1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gkgoat1/32/12690_2.png) [@gkgoat1](https://internals.rust-lang.org/u/gkgoat1)\
**Post date:** [November 2, 2024, 7:27pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/1 "2024-11-02T19:27:48Z")

</div>

(by the way, this is my first time submitting anything to Rust)

# !!!!

## This Pre-(Pre-)RFC is pretty much a moot point, due to its only real uses covered by existing types and c-like bitpacking not working with Rust's compiler model

# !!!!

_Edit 1: conservatively assume `n8`s are uninhabited_

Feature Name: niche\_types Start Date: sometime in the future RFC PR/Rust Issue: N/A

# Summary:

Adds a primitive, 1 byte sized, type with an undefined memory representation.

# Motivation:

While talking on the Rust Community Discord, there came a need for bitpacking `struct`s. As part of it, creating niches would be necessary. Niches are bit patterns within a struct or enum which can be repurposed by an enclosing enum or, in the future, an enclosing struct. While this Pre(-Pre)-RFC does not propose bitpacking, it provides a utility to partially control Rust's niches.

# Guide-level explanation:

This Pre-(Pre-)RFC adds one type, `n8` (name not final), which has no memory representation, but takes up one byte of space. The actual byte used depends on the contents: an `Option<n8>` stores whether it is `Some` or `None` in the `n8`'s byte, meaning you CANNOT rely on its actual value. This means `transmute`ing it to or from a `u8`, optionally within pointers, references, and arrays, is always Undefined Behavior.

# Reference-level explanation:

See above. (TODO)

# Drawbacks:

Most likely uninhabited and unusable until the implementation of future ideas.

# Rationale and alternatives

Some implementations of binary formats require precise control of not only the layout of data, but how Rust can reason about it. A `u8` could be wrapped to obtain similar developer experience, but will not have a `n8`'s performance benefits. In that way, a `n8` can be seen as an optimizing hint.

# Prior Art

None, as Rust, to the best of my knowledge, has invented structure niches.

# Unresolved questions

- Would a `n8` actually be constructable? What rules _would_ need to be in place to construct one, or are they uninhabited? If `n8`s turn out to be uninhabited, would it make sense, in current Rust, to add it?

TODO, suggest some

# Future possibilities

For this to be useful, an abi guarantee would be needed to allow certain structures containing it to be inhabited.

This is a stepping stone towards bitpacked and bit-level `struct`s, which need padding (which can be created using normal types) _and_ niches within them.

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [November 2, 2024, 8:02pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/2 "2024-11-02T20:02:02Z")

</div>

I believe you can already do this by using a `#[repr(u8)] enum` with a single unit variant.

> **[Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2042ae6b0ca9c98e8f1af45535e3e582)**
>
> A browser interface to the Rust compiler to experiment with the language

You can even rely on its value being a specific byte.

> [@gkgoat1](#):
>
> there came a need for bitpacking `struct`s

I'm not sure I see how this type relates to bitpacking, do you have some concrete examples?

---

<div class="post-metadata">

**Author:** ![gkgoat1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gkgoat1/32/12690_2.png) [@gkgoat1](https://internals.rust-lang.org/u/gkgoat1)\
**Post date:** [November 2, 2024, 8:10pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/3 "2024-11-02T20:10:46Z")

</div>

> I believe you can already do this by using a `#[repr(u8)] enum` with a single unit variant.

> You can even rely on its value being a specific byte.

The idea of niche types is to have 256 niches (instead of the `enum`'s 255) and to not be able to rely on the byte's value.

> I'm not sure I see how this type relates to bitpacking, do you have some concrete examples?

Suppose `#[repr(bitpacked)]` packs bits and that Rust allowed arbitrary bitwidth integers. You could then use that proposal alongside this one to have a ` #[repr(bitpacked)] struct Padded{ first: u1, /*NOT part of this idea*/ rest: n7, /*Also NOT part of this idea*/ }`. Then, a `Padded` struct would have 128 niches, and thus could be composed in a ` #[repr(bitpacked)] struct Composed{ padded: Padded, data: u7, }`, which would be only one byte in size.

This pre-(pre-)RFC would lay the groundwork for those structure niches, another making them actually work (not just large `enum` packing), and another one would propose bitpacked structs, similar to how I described them. An advisor in the Discord server told me to split the idea up so as to allow independent progress on all.

---

<div class="post-metadata">

**Author:** ![jjpe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jjpe/32/9779_2.png) [@jjpe](https://internals.rust-lang.org/u/jjpe)\
**Post date:** [November 2, 2024, 8:27pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/4 "2024-11-02T20:27:16Z")

</div>

> [@gkgoat1](#):
>
> As part of it, creating niches would be necessary.

What do you mean by niche? Could you update the OP with a definition?

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [November 2, 2024, 8:58pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/5 "2024-11-02T20:58:32Z")

</div>

> [@gkgoat1](#):
>
> The idea of niche types is to have 256 niches (instead of the `enum`'s 255) and to not be able to rely on the byte's value.

You should update the pitch as that really doesn't come across:

> [@gkgoat1](#):
>
> which has one value, but takes up one byte of space.

I would consider "a byte with one value" to have 255 niches.

> [@gkgoat1](#):
>
> The actual byte used depends on the contents: an `Option<n8>` stores whether it is `Some` or `None` in the `n8`'s byte, meaning you CANNOT rely on its actual value. This means `transmute`ing it to or from a `u8`, optionally within pointers, references, and arrays, is always Undefined Behavior.

So, 0 possible values but not uninhabited.

---

<div class="post-metadata">

**Author:** ![gkgoat1](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gkgoat1/32/12690_2.png) [@gkgoat1](https://internals.rust-lang.org/u/gkgoat1)\
**Post date:** [November 2, 2024, 9:09pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/6 "2024-11-02T21:09:34Z")

</div>

> [@quinedot](#):
>
> > [@gkgoat1](#):
> >
> > which has one value, but takes up one byte of space.
> 
> I would consider "a byte with one value" to have 255 niches.

In a pure type-theoretic context, yes. However, in Rust, with the concept of undefined memory representation, it would be more like a unit type which spans but does not use one byte _of memory_.

> So, 0 possible values but not uninhabited.

No, one possible value which is undefined in memory. That does raise the issue of construction of a `n8` (and may even prove that `n8`s would be uninhabited, rendering this idea moot), as its bit pattern requiements depend on its context.

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [November 3, 2024, 9:26am UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/7 "2024-11-03T09:26:35Z")

</div>

> [@gkgoat1](#):
>
> In a pure type-theoretic context, yes. However, in Rust, with the concept of undefined memory representation, it would be more like a unit type which spans but does not use one byte _of memory_.

I'm not sure what you mean with undefined memory representation. Are you referring to uninitialized memory? That can take any bit pattern, so it would leave you with no niches at all.

---

<div class="post-metadata">

**Author:** ![cg909](https://avatars.discourse-cdn.com/v4/letter/c/90ced4/32.png) [@cg909](https://internals.rust-lang.org/u/cg909)\
**Post date:** [November 3, 2024, 3:05pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/8 "2024-11-03T15:05:32Z")

</div>

If I understand _gkgoat1_ correctly, the idea is that `n8` is a "padding type" with one type-theoretical value "undefined" that can take any bit-pattern, except you can't rely on the value because the compiler is allowed to take arbitrary values as niches for `Option<n8>` etc.

In contrast, something like

```rust
#[repr(u8)]
enum ZeroByte {
    ZeroByte = 0
}

```

would only have an all-zero byte as a valid representation, but provides every other value as a niche.

---

<div class="post-metadata">

**Author:** ![jdahlstrom](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jdahlstrom/32/3351_2.png) [@jdahlstrom](https://internals.rust-lang.org/u/jdahlstrom)\
**Post date:** [November 3, 2024, 4:29pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/9 "2024-11-03T16:29:45Z")

</div>

I guess the idea is to have a _semantically_ single value, eg. something like

```rust
pub struct Niche(/* exposition only */ u8);

pub const NICHE: Niche = Niche(/* unspecified */);

impl Default for Niche { … }

```

where `NICHE` is the only value of `Niche` that exists from the user point of view. The number of bit patterns is immaterial. But the internal value is made available for the compiler to make use of. The value is not uninitialized, just unspecified.

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [November 3, 2024, 5:06pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/10 "2024-11-03T17:06:37Z")

</div>

The problem with just making a type with 256 niches is that niches of a type are bit-patterns that are _definitely not_ values of the type, so in order to be able to have a value of the type, _at least one_ bit-pattern needs to be one that _is_ a value of the type. So, a 1-byte type with 256 niches is necessarily an uninhabited type because all 256 possible-memory-contents are “not me”.

The goal of this proposal, as I understand it, is to be able to express adding niche space to a containing struct, but you can’t do this with _only_ the current niche system; you’d need the compiler to do something different, more like “use this space freely for the containing enum’s discriminant”, which isn’t making a concrete “is this type / is not this type” distinction, but one up to the containing enum. (And I think that breaks the rule that blindly copying `size_of::<T>()` bytes into a `&mut T` is OK, because you’d start overwriting those spaces. Niches work because if the value is a `T` then you know you _can_ overwrite those spaces.)

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [November 4, 2024, 4:42pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/11 "2024-11-04T16:42:12Z")

</div>

> [@gkgoat1](#):
>
> No, one possible value which is undefined in memory.

That's not possible. One key principle of uninitialized memory in Rust (and elsewhere) is that _it's always okay to initialize uninit memory with some arbitrary value_. It follows that every type that allows a given byte to be uninit, must allow it to have _any_ value.

So 256 niche values is not possible.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [April 28, 2026, 4:43pm UTC](https://internals.rust-lang.org/t/pre-pre-rfc-niche-types/21810/12 "2026-04-28T16:43:12Z")

</div>

This topic was automatically closed 540 days after the last reply. New replies are no longer allowed.
