assert_has_field

Macro assert_has_field 

Source
macro_rules! assert_has_field {
    (@ASSERT $unreachable_obj:ident, $field:ident) => { ... };
    (@ASSERT $unreachable_obj:ident, $field:ident : $field_ty:ty) => { ... };
    (@ASSERT $unreachable_obj:ident, $field:ident :~ $field_ty:ty) => { ... };
    (
        $struct:ty,
        $field:ident
            $($rest:tt)*
    ) => { ... };
}
Expand description

This macro performs a compile-time check if a struct has a specific field.

§Syntax

The macro offers three syntaxes for checking if a struct has a field

  1. assert_has_field!(Struct, field); - checks if the struct has a field with the given name.
  2. assert_has_field!(Struct, field: Type); - checks if the struct has a field with the given name and type.
  3. assert_has_field!(Struct, field :~ Type); - checks if the struct has a field with the given name and type that can be coerced to the specified type Type.

§Examples

use assert_has_field::assert_has_field;

#[allow(dead_code)]
struct Point {
    x: u64,
    y: u64,
}

// This will compile because `Point` has a field `x`.
assert_has_field!(Point, x);

If the field is not present, the macro will cause a compile-time error.

use assert_has_field::assert_has_field;

#[allow(dead_code)]
struct Point {
   x: u64,
   y: u64,
}

// This will cause a compile-time error because `Point` does not have a field `a`.
assert_has_field!(Point, a);

You can also specify the type of the field to ensure it matches a specific type.

use assert_has_field::assert_has_field;

#[allow(dead_code)]
struct Point {
   x: u64,
   y: u64,
}

// This will compile because `Point` has a field `x` of type `u64`.
assert_has_field!(Point, x: u64);

Note, however, that : syntax in this macro asserts the exact type of the field, preventing any coercion to minimize the human error.

The following code will not compile:

use assert_has_field::assert_has_field;

struct Wrapper<T>(T);

impl<T> core::ops::Deref for Wrapper<T> {
  type Target = T;

 fn deref(&self) -> &Self::Target {
     &self.0
 }
}

#[allow(dead_code)]
struct Point2 {
   x: &'static Wrapper<u64>,
  y: u64,
}

// This will cause a compile-time error because `Point2`'s field `x` is of type
// `&'static Wrapper<u64>`, not `&'static u64`.
assert_has_field!(Point2, x: &'static u64);

Additionally, you can use the made-up :~ syntax to assert that the field can be coerced to the specified type.

use assert_has_field::assert_has_field;

#[allow(dead_code)]
struct Wrapper<T>(T);

impl<T> core::ops::Deref for Wrapper<T> {
   type Target = T;

  fn deref(&self) -> &Self::Target {
      &self.0
  }
}

#[allow(dead_code)]
struct Point2 {
    x: &'static Wrapper<u64>,
    y: u64,
}

// This will compile because `Point2` has a field `x` that can be coerced to `&'static u64`.
assert_has_field!(Point2, x :~ &'static u64);

§On real use-cases

Let’s say that you’re writing a backend server and have a DTO, which is meant to be used on the frontend. Assume that this DTO aggregates different kinds of data that pertains to a candidate. You may be in a situation where candidate_id is stored in one of the fields-structures. You can use assert_has_field to document that expectation and future-proof the type in case the field-structure that used to store candidate_id is removed entirely or modified in a way that moves or removes the candidate_id.