If so, I found that to_be_bytes is not implemented in traits, but implemented directly for "primitive types", how could I write the function to call to_be_bytes()?
Without loss of generality, what's the general way to call a "non-trait" method on a type T?
This is a misunderstanding; templates will check validity after substituting for a concrete type, whereas generics will do so before substituting.
Which leads me into:
Yup, the idea is that you can constrain types based solely on traits and lifetimes, and can't randomly call methods or access fields (even though they might exist).
Try a crate such as num_traits. The to_[ne/be/le]_bytes methods are only implemented for certain numeric types.
Hi, I checked the crate num_traits, it seems that I can use the trait bounds to create method conditionally, such as method for singed and another method for unsigned, but I didn't find any method like to_[ne/be/le]_bytes. Do you suggest that to create my own trait which implements the to_[ne/be/le]_bytes?
Another question is that is to_[ne/be/le]_bytes implemented on types instead of on traits designed on purpose? Does it have any good to implement them on traits?
Rust traits work only when a trait is explicitly imported or required in a generic context. So if these methods were only in a trait, you'd need something like use std::num::TheTraitWithToBeBytes in every file that uses it.
There's been a proposal to for inherent traits that behave like both methods and traits, but it's nowhere near being a reality.
Where an implementer could substitute Element with Self.
But the compiler warned you in the first instance of the following:
error: generic parameters may not be used in const operations
--> src/lib.rs:2:51
|
2 | fn to_bytes(self) -> [u8; std::mem::size_of::<Self>()];
| ^^^^ cannot perform const operation using `Self`
|
= note: type parameters may not be used in const expressions
error: aborting due to previous error
Which is a current limitation of Rust's const generics. In other words, there is no way to say an equivalent to this in stable rust today.
To do this, I'd probably just stick to native endian and use something like bytemuck, or return a Vec or an ArrayVec or SmallVec.
bytemuck will allow you to get a reference to a slice from a reference to a number. It performs the following conversion: &T -> &[u8] where T: Pod (Plain old data, which isn't implemented for structures with, for example, pointers, such as String).
SmallVec stores a few elements inline before it spills onto the heap.
ArrayVec stores all of its elements in an array (inline) with a hard cap:
let mut av = ArrayVec::<u8, 2>::new();
av.push(12u8);
av.push(34u8);
// Will panic!
av.push(56u8);
Hi, how can I determine the size of the ByteArray here? It looks to me that the code have no idea, I need to be careful about the boundary of the array.
That's not "giving type", that's a trait bound. Here, it serves more as a documentation remainder - in every implementation, ReturnType must be some kind of byte array.
Without a trait bound it's impossible to use it generically, because ReturnType could be a u8, or () or File or whatever else, so it wouldn't have a length or access to bytes in a generic context.
If the current setup works for you, it means your code is hardcoded to know it can only be the u32 type, so it's not using the trait generically.