isaacholt100 / bnum

Arbitrary, fixed size numeric types that extend the functionality of primitive numeric types in Rust.
https://crates.io/crates/bnum
Other
67 stars 8 forks source link

Accessing the raw bytes or internal representation of a BUint/BInt #30

Closed Lonsdaleiter closed 9 months ago

Lonsdaleiter commented 11 months ago

I'm trying to send a BInt to the GPU (I have an equivalent big two's complement integer structure there), but to do that I need to access the raw bytes of a BUint/BInt.

I've looked through the documentation and source of the project, but I can't find a way to access the raw bytes of a BUint/BInt. BUint is a wrapper around [$Digit; N], but it isn't #[repr(transparent)], so I can't transmute BUint to the equivalent array. Is there no way to access the raw bytes or internal representation of either big integer type?

isaacholt100 commented 11 months ago

Hi @Lonsdaleiter, sorry for taking so long to reply to this... to access the underlying representation ([u64; N]) of a BUint, you can use the BUint::digits method (this returns a reference to the array) or From<BUint<N>> is implemented for [u64; N].

To access the raw bytes, it depends whether you want the bytes as a vector (without padding zeros) or as an array of the same byte size as the integer (with padding zeros):

Hopefully this is what you were looking for!

Lonsdaleiter commented 11 months ago

@isaacholt100 Thanks so much for the patient reply! I don't know how I missed those functions they're pretty important.

Relatedly, is there a reason why the BUint and BInt aren't marked #[repr(transparent)]? Getting a reference to the underlying representation is helpful, but if I want to send a tightly packed array of big integers to the GPU, being able to just pass an array of BInts directly through without needing to construct a new array from their underlying representation would be nice.

isaacholt100 commented 11 months ago

Apologies for the late response again, it's been another busy week... to be honest, I think when I originally published bnum I wasn't aware of the different reprs that structs could have. As I've never used them for anything, I'm not that experienced with this stuff - would adding #[repr(transparent)] to the integer types be a breaking change? If not then I'm more than happy to add this for the next release. And if even it is a breaking change, I could still consider it when bnum hits v1. Are there any reasons for leaving it as the default repr? Thanks

Lonsdaleiter commented 11 months ago

I found an official thread discussing what semver guidelines should be for repr changes: https://github.com/rust-lang/cargo/pull/10276.

This person makes the point (which I agree with) that going from #[repr(Rust)] to #[repr(transparent)] should be harmless (going from no guarantee to some guarantee), but going the other way could silently break things (going from some guarantee to no guarantee).

So, I don't think it counts as a breaking change to change from default to transparent.

I'm not aware of any downside #[repr(transparent)] would have -- I don't know of anything that making the guarantee would prevent the compiler from doing but I suppose it's theoretically possible. Still, it'd be useful to be able to treat the wrapper type as its underlying array.

isaacholt100 commented 10 months ago

I see, that makes sense. I think I might have read somewhere that adding #[repr(transparent)] prevents certain optimisations from the compiler, but I'll read into this and check, and do some benchmarks if necessary. Do you mind quickly explaining why adding #[repr(transparent)] is necessary/preferable for your use case? I thought that if the struct has a single field then it wouldn't make a difference, but I could be wrong?

isaacholt100 commented 10 months ago

I've read into this a bit more now, the struct isn't guaranteed to have the same layout as the single field unless it's marked as #[repr(transparent)]. Benchmarks are looking like it doesn't make a difference, I'll need to run through them a few more times just to check. If adding this repr doesn't make a difference to performance, then I can add this to the next version.

isaacholt100 commented 9 months ago

v0.9.0 has just been released, which adds #[repr(transparent)] to bnum integers, so closing this issue. Thanks!