I have a generic function serialize
that serializes a struct implementing serde::Serialize
together with a custom trait MaxSize
to a byte buffer. The MaxSize
trait is implemented with a derive macro, and has an associated constant MAX_SIZE
that gets filled in with the maximum possible size the struct serializes to.
I want to get an error at compile time if serialize
is called on a struct whose MAX_SIZE
is larger than some constant, MAX_ALLOWED_SIZE
. (The idea is to prevent creating structs that could exceed the max UDP datagram size when serialized.) How do I do this? I've tried the following (omitting the derive macro here and instead just filling in MAX_SIZE
for the example struct manually for simplicity) (playground link):
const MAX_ALLOWED_SIZE: usize = 100;
trait MaxSize {
const MAX_SIZE: usize;
}
#[derive(serde::Serialize)]
struct ExampleStruct {
a: f64,
}
// (This would actually be implemented using a derive macro.)
impl MaxSize for ExampleStruct {
const MAX_SIZE: usize = 7;
}
fn serialize<T: serde::Serialize MaxSize>(data: &T, buf: &mut [u8]) {
const _: () = assert!(T::MAX_SIZE < MAX_ALLOWED_SIZE);
// <code to actually serialize>
}
fn main() {
serialize(&ExampleStruct {a: 6.}, &mut [0u8; MAX_ALLOWED_SIZE]);
}
I get the following error:
error[E0401]: can't use generic parameters from outer function
--> src/main.rs:18:27
|
17 | fn serialize<T: serde::Serialize MaxSize>(data: &T, buf: &mut [u8]) {
| - type parameter from outer function
18 | const _: () = assert!(T::MAX_SIZE < MAX_ALLOWED_SIZE);
| ^^^^^^^^^^^ use of generic parameter from outer function
CodePudding user response:
On stable:
struct Const<T>(std::marker::PhantomData<T>);
impl<T: MaxSize> Const<T> {
const C: () = assert!(T::MAX_SIZE < MAX_ALLOWED_SIZE);
}
fn serialize<T: serde::Serialize MaxSize>(data: &T, buf: &mut [u8]) {
[Const::<T>::C; 1];
// <code to actually serialize>
}
On nightly:
#![feature(inline_const)]
fn serialize<T: serde::Serialize MaxSize>(data: &T, buf: &mut [u8]) {
const { assert!(T::MAX_SIZE < MAX_ALLOWED_SIZE) };
// <code to actually serialize>
}
Note that both generate a post-monomorphization error, meaning they'll succeed cargo check
but fail cargo build
, and so are discouraged to use (but can be used nonetheless).