Skip to main content

dispatch

Attribute Macro dispatch 

Source
#[dispatch]
Expand description

Implements a #[dispatchable] trait for an enum by forwarding every method to whichever variant the value holds, or forwards the methods of an inherent impl block of such an enum.

On an enum, each attribute names one trait, with its generic arguments when it has any, followed by options; several attributes dispatch several traits, and a bare #[dispatch] only registers the enum. Every variant must hold exactly one unnamed field whose type implements the trait. The enum also gets a From<Payload> impl for every payload type that appears in exactly one variant.

ⓘ
#[whichever::dispatch(Shape)]
#[whichever::dispatch(Encoder<Json>, Error = EncodeError)]
pub enum AnyShape {
    Circle(Circle),
    #[dispatch(deref)]
    Square(Box<Square>),
}

Options, after the trait path:

  • Name = Type: the associated type Name of the enum’s impl, instead of the first variant’s. Methods returning Self::Name are converted with Into, methods returning Result<_, Self::Name> with map_err(Into::into).
  • mismatch(method = expr, ..): the result of method when its Self arguments hold a different variant than self.
  • from = false: no From<Payload> impls.
  • try_from = true: a TryFrom<Enum> for Payload impl per payload type, returning the enum unchanged when it holds another variant.

The one variant option, #[dispatch(deref)], calls the trait on what the payload dereferences to, for Box<T>, Rc<T>, Arc<T>, &T and &mut T payloads; such a variant cannot take part in a method that returns Self.

On an inherent impl block of a dispatch enum, in the same crate, every method carrying #[dispatch(..)] is forwarded to the named variants’ own method of the same name, and the body is what the other variants return. * names every variant; the method then has no fallback and is written without a body:

ⓘ
#[whichever::dispatch]
impl AnyShape {
    /// Only circles have a radius.
    #[dispatch(Circle, with = Some)]
    pub fn radius(&self) -> Option<f64> {
        None
    }

    #[dispatch(*)]
    pub fn perimeter(&self) -> f64;
}

Method options: with = path wraps each forwarded result in a call to path, and call = name forwards to a payload method of another name. Methods without the attribute are left as they are.