nonmax icon indicating copy to clipboard operation
nonmax copied to clipboard

Possibility to be zero-cost on some platforms

Open ickk opened this issue 1 year ago • 4 comments

It would be possible (maybe slightly cursed?) to implement NonMaxU32 (and larger) in terms of some stable standard library type that already has a niche at u32::MAX, removing the run-time costs.

There unfortunately are not a lot of these, but I found std::os::fd::BorrowedFd which is available in std on Unix platforms & WASI and has been stable since 1.63.0.

Proof of concept

ickk avatar Sep 05 '24 03:09 ickk

I'm not sure what you mean by 'and larger' as to my knowledge you can't construct larger types out of the smaller niched types because you will end up with too many niches? However there are still a few platform specific types available, all in std since 1.63:

13ros27 avatar Oct 08 '24 14:10 13ros27

@13ros27

However there are still a few platform specific types available

You're correct, I think the reason I didn't initially consider these was because their width changes depending on the platform's usize, so in practice you'll miss out on NonMaxU32 (which is what I was interested in) - but if this hack was to be deemed "ethical" it's probably still worth implementing NonMaxUsize and potentially NonMaxU64/NonMaxU32 in terms of those types where appropriate

I'm not sure what you mean by 'and larger'

~~It is possible to make larger types by composing a smaller non-max with normal primitives; i.e.~~

#[repr(C, align(8))]
pub struct NonMaxU64 {
  hi: NonMaxU32,
  lo: u32,
}

~~but the order of the fields probably needs to change based on the target platform's endianness (can be done with a cfg).~~ ~~Proof of concept~~

~~What would be really great is if we found a natural NonMaxU8-like type somewhere in core or std, since then we could use it to build everything, but I never found such a type~~

ickk avatar Oct 08 '24 19:10 ickk

Unfortunately combining types like this doesn't work because it will then have u32::MAX niches, for example assert_eq!(Some(0xFF_FF_FF_FF), dbg!(NonMaxU64::new(0xFF_FF_FF_FF)).map(|nm| nm.get())); fails. This is clearer to see if we reorder the fields at which point all the niches stack up at the end and size_of::<Option<Option<NonMaxU64>>>() becomes 8 rather than 16.

As an aside we can make NonMaxU8 by making an enum with 255 variants, see #18

13ros27 avatar Oct 08 '24 21:10 13ros27

You're right, that's my mistake

ickk avatar Oct 08 '24 22:10 ickk