Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
Lonsdaleiter opened this issue Jul 31, 2023 · 7 comments
Closed

Comments

@Lonsdaleiter
Copy link

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
Copy link
Owner

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):

  • To access the bytes as a vector, use the to_radix_{be, le} methods, specifying the radix argument as 256.
  • To access the bytes as an array:
    • If you are using the nightly compiler and have the nightly crate feature enabled, use the to_{be, le, ne}_bytes methods.
    • If you aren't using nightly, use the As trait to cast the BInt<N> to a BUintD8<N * 8> (you need to know the concrete value of N here, it can't be a const-generic), then use the methods mentioned above to access the underlying representation of the BUintD8 as an array of bytes.

Hopefully this is what you were looking for!

@Lonsdaleiter
Copy link
Author

@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
Copy link
Owner

isaacholt100 commented Aug 12, 2023

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
Copy link
Author

I found an official thread discussing what semver guidelines should be for repr changes: rust-lang/cargo#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
Copy link
Owner

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
Copy link
Owner

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
Copy link
Owner

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants