Reputation: 2020
I'm working on porting a Typescript library which has this type alias and function:
type GlkTypedArray = Uint8Array | Uint32Array
get_buffer(buf: GlkTypedArray): number
Pretty straight forward, it accepts either a Uint8Array
or a Uint32Array
.
I'm now trying to do the same in Rust, via a trait that is defined only for u8
and u32
:
trait GlkInt: Sized {}
impl GlkInt for u8 {}
impl GlkInt for u32 {}
fn get_buffer(buf: &mut [dyn GlkInt]) -> u32;
But unfortunately it's not allowing this, saying that the trait is not Sized
, even though I thought that trait definition meant it would be.
error[E0277]: the size for values of type `dyn misc::GlkInt` cannot be known at compilation time
--> remglk/src/glkapi/streams.rs:18:29
|
18 | fn get_buffer(buf: &mut [dyn GlkInt]) -> u32;
| ^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn misc::GlkInt`
= note: slice and array elements must have `Sized` type
error[E0038]: the trait `misc::GlkInt` cannot be made into an object
--> remglk/src/glkapi/streams.rs:18:30
|
18 | fn get_buffer(buf: &mut [dyn GlkInt]) -> u32;
| ^^^^^^^^^^ `misc::GlkInt` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> remglk/src/common/misc.rs:13:19
|
13 | pub trait GlkInt: Sized {}
| ------ ^^^^^ ...because it requires `Self: Sized`
| |
| this trait cannot be made into an object...
Do I need to do something else, or is this whole approach not going to work? What else can I try?
Upvotes: 0
Views: 676
Reputation: 27537
The size of elements of an array/slice need to be known at compile time so the compiler can calculate the distance between 2 items for indexing.
a dyn GlkInt
would be either 1 or 4 bytes wide so there is no way to know the size.
You can either just do stattic dispatch using a generic type in wihch case you probably want to require more traits on your generic (From<u8>
, Into<u32>
come to mind):
trait GlkInt {}
impl GlkInt for u8 {}
impl GlkInt for u32 {}
fn get_buffer<T: GlkInt>(buf: &mut [T]) -> u32 {
0
}
Or use an enum and implement the different code paths yourself.
use GlkSlice::*;
enum GlkSlice<'a> {
U8(&'a mut [u8]),
U32(&'a mut [u32]),
}
fn get_buffer(buf: GlkSlice<'_>) -> u32 {
match buf {
U8(buf) => buf[0] as u32,
U32(buf) => buf[0],
}
}
Upvotes: 5