Custom Auto Traits

Recently I wanted make a function that accepts an object, but only if it has a certain size or smaller.

fn constraint_fn<T>(t: T) {/*only compiles if mem::size_of<T> <= SIZE*/}

This doesn't seem to be possible: https://users.rust-lang.org/t/compile-time-generic-type-size-check/41642

The way Rust handles constraint generic types is by using traits. But for this constraint I would need an conditional auto trait:

fn constraint_fn<T : Size<SIZE>>(t: T) {/*only compiles if mem::size_of<T> <= SIZE*/}

with Size:

#[auto_trait]  //label that it should be an auto trait
trait Size<const SIZE: usize> {
      #[auto_trait_cond] //add condition for auto derive
      const fn condition<T>() {
             mem::size_of<T> <= SIZE
      }
}

The condition would be checked when used on an actual type (when it is checked if a concrete type implements the trait constraint).

Is there already a proposal for something similar? Or is there a better/other way to solve my issue?

This is way beyond anything Rust is likely to have in the forseeable future. I suspect similar ideas are covered somewhere in "The pi type trilogy" of exceptionally ambitious RFCs that were unsurprisingly postponed in favor of a much more minimal const generics RFC that we're still in the process of implementing. I'm fairly sure they at least discuss the difficulties of allowing arbitrary user code to influence trait resolution like this.

That aside, what is the reason you don't want any larger types in this function? I can easily imagine reasons to put size assertions or size-checking unit tests within your own codebase (and that's already commonplace in some projects like servo), but for a public API I'm not aware of any use cases, since there are no operations you can perform on sizeN types that you can't also perform on sizeN+1 types.

1 Like

With just const generics, this could potentially be formulated as

trait Small<const SIZE: usize> {}

trait True {}
struct Condition<const B: bool>;
impl True for Condition<true> {}

impl<T: Sized, const SIZE: usize> Small<SIZE> for T
where Condition<{mem::size_of::<T>() < SIZE}>: True {}

This is definitely far from working and out of scope for the minimal const generics, but is just provided here to show how this constraint could potentially be written. (If this pattern became widespread, we'd probably want to make a boolean directly in a where predicate work, rather than requiring the struct Condition indirection.)

3 Likes

I'm trying to create a Box-like structure based on the fixed sized traits idea:

When creating such a trait object the size of the value can't be bigger than the size of the fixed sized trait.

That's much better syntax than what I proposed. It would be nice to have this in Rust :smile: