I have a function similar to the one below:
fn write( data: u8, buf: &mut dyn Write )
{
let bytes = data.to_ne_bytes();
buf.write(&bytes);
}
I would like to have this function for all the fixed sized types u8, i8, u16, i16 etc., similar to overloading in C . Is there a way to do that with generics in Rust?
I have tried the following, however, it does not compile:
use fixed::traits::Fixed;
fn write<T: Fixed<Bytes = [u8]> Sized>( data: T, buf: &mut dyn Write )
{
let bytes = data.to_ne_bytes();
buf.write(&bytes);
}
I get the following error:
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
4 | let bytes = data.to_ne_bytes();
| ^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[u8]`
= note: all local variables must have a statically known size
= help: unsized locals are gated as an unstable feature
I also tried something like this:
fn write<T: Fixed<Bytes = [u8]> Sized>( data: T, buf: &mut dyn Write )
{
let bytes:[u8; mem::size_of_val(data)] = data.to_ne_bytes();
buf.write(&bytes);
}
Unfortunately that doesnt work either. I get this compile error:
error[E0435]: attempt to use a non-constant value in a constant
|
146 | fn write<T: Fixed<Bytes = [u8]> Sized>( data: T, buf: &mut dyn Write )
| ---- this would need to be a `const`
...
149 | let bytes:[u8; mem::size_of_val(data)] = data.to_ne_bytes();
| ^^^^
Edit:
The suggested duplicate is not usable in my case. The trait that is used there does not allow me to have a type where its size is known at compile time
CodePudding user response:
Here's an example using a custom trait:
use std::io::Write;
trait ToBytes {
type Output;
fn to_ne_bytes(self) -> Self::Output;
// TODO: maybe add to_le_bytes and/or to_be_bytes?
}
impl ToBytes for u8 {
type Output = [u8; 1];
fn to_ne_bytes(self) -> Self::Output {
[self]
}
}
impl ToBytes for u16 {
type Output = [u8; 2];
fn to_ne_bytes(self) -> Self::Output {
self.to_ne_bytes()
}
}
impl ToBytes for u32 {
type Output = [u8; 4];
fn to_ne_bytes(self) -> Self::Output {
self.to_ne_bytes()
}
}
impl ToBytes for u64 {
type Output = [u8; 8];
fn to_ne_bytes(self) -> Self::Output {
self.to_ne_bytes()
}
}
// TODO: signed integers
fn write<T>(data: T, buf: &mut dyn Write)
where
T: ToBytes,
<T as ToBytes>::Output: AsRef<[u8]>,
{
let bytes = data.to_ne_bytes();
buf.write(bytes.as_ref());
}
fn main() {
let x: u8 = 5;
let mut buf: Vec<u8> = Vec::new();
write(x, &mut buf);
}
CodePudding user response:
Assuming the implementers of Fixed
set Bytes
to be fixed-size u8
arrays, you can use const generics and make write
generic over the size of the u8
array in Bytes
:
fn write<const N: usize, T: Fixed<Bytes = [u8; N]>>(data: T, buf: &mut dyn Write) {
let bytes = data.to_ne_bytes();
buf.write(&bytes);
}