the problem is that C is a compile-time constant however in your function as_bytes you are trying to return 2 different things based on some runtime logic. in case of 3, you are returning a [u8;3] on the other part [u8;4]. but C can be either 3 or 4 at runtime on a thing you can do is to pad your array to always have 4 elements
The number of bytes returned by a function must be known ahead of time to the caller of the function, as a compile-time constant. This is a hard limitation of the calling convention, so you can never make the size decision in the function body.
This should work:
pub trait ToBytes {
type Array;
fn to_bytes(&self) -> Self::Array;
}
impl ToBytes for Pixel<3> {}
impl ToBytes for Pixel<4> {}
You'll probably want/need different implementations for different (compile-time-determined) values of the const parameter. Here's a few examples of various degrees of abstraction. Using a trait will make it easier to be generic in places that are somewhat agnostic about the how many channels you have, but need access to the channels. E.g.
// If you've only implemented `AsBytes` for `Pixel<3>` and `Pixel<4>`,
// you won't be able to pass anything but those two into `f`
fn f<P: AsBytes>(pixels: Vec<P>) { /* ... */ }
You could optimize for writing/code-size by pulling some tricks using From to go from four channels to three or something, and leaning on optimization, but I don't know that it's worth it.