mopa 0.1.0

My Own Personal Any: get your own Any with additional functionality
mopa 0.1.0

[![Build Status](](

<!-- The rest of this section comes straight from the crate docs from the source. -->

**MOPA: My Own Personal Any.** A macro to implement all the `Any` methods on your own trait.

You like `Any`—its ability to store any `'static` type as a trait object and then downcast it
back to the original type is very convenient, and in fact you need it for whatever misguided
reason. But it’s not enough. What you *really* want is your own trait object type with `Any`’s
functionality glued onto it. Maybe you have a `Person` trait and you want your people to be
able to do various things, but you also want to be able to conveniently downcast the person to
its original type, right? Alas, you can’t write a type like `Box<Person + Any>` (at present,
anyway). So what do you do instead? Do you give up? No, no! No, no! Enter MOPA.

> There once was a quite friendly trait  
> Called `Person`, with much on its plate.  
>     “I need to be `Any`  
>     To downcast to `Benny`—  
> But I’m not, so I guess I’ll just wait.”

A pitiful tale, isn’t it? Especially given that there was a bear chasing it with intent to eat
it. Fortunately now you can *mopafy* `Person` in two simple steps:

1. Make `Any` a supertrait of `Person`;
2. `mopafy!(Person);`.

And lo, you can now write `<Benny>()` and `person.downcast_ref::<Benny>()` and so on
to your heart’s content. Simple, huh?

Oh, by the way, it was actually the person on the bear’s plate. There wasn’t really anything on
`Person`’s plate after all.


extern crate mopa;

use std::any::Any;

struct Bear {
    // This might be a pretty fat bear.
    fatness: u16,

impl Bear {
    fn eat(&mut self, person: Box<Person>) {
        self.fatness = (self.fatness as i16 + person.weight()) as u16;

trait Person: Any {
    fn panic(&self);
    fn yell(&self) { println!("Argh!"); }
    fn sleep(&self);
    fn weight(&self) -> i16;


struct Benny {
    // (Benny is not a superhero. He can’t carry more than 256kg of food at once.)
    kilograms_of_food: u8,

impl Person for Benny {
    fn panic(&self) { self.yell() }
    fn sleep(&self) { /* ... */ }
    fn weight(&self) -> i16 {
        // Who’s trying to find out? I’m scared!
        self.kilograms_of_food as i16 + 60

struct Chris;

impl Chris {
    // Normal people wouldn’t be brave enough to hit a bear but Chris might.
    fn hit(&self, bear: &mut Bear) {
        println!("Chris hits the bear! How brave! (Or maybe stupid?)");
        // Meh, boundary conditions, what use are they in examples?
        // Chris clearly hits quite hard. Poor bear.
        bear.fatness -= 1;

impl Person for Chris {
    fn panic(&self) { /* ... */ }
    fn sleep(&self) { /* ... */ }
    fn weight(&self) -> i16 { -5 /* antigravity device! cool! */ }

fn simulate_simulation(person: Box<Person>, bear: &mut Bear) {
    if<Benny>() {
        // None of the others do, but Benny knows this particular
        // bear by reputation and he’s *really* going to be worried.
    // If it happens to be Chris, he’ll hit the bear.
    person.downcast_ref::<Chris>().map(|chris| chris.hit(bear));;

fn main() {
    let mut bear = Bear { fatness: 10 };
    simulate_simulation(box Benny { kilograms_of_food: 5 }, &mut bear);
    simulate_simulation(box Chris, &mut bear);

Now *should* you do something like this? Probably not. Enums are probably a better solution for
this particular case as written; frankly I believe that almost the only time you should
downcast an Any trait object (or a mopafied trait object) is with a generic parameter, when
producing something like `AnyMap`, for example. If you control *all* the code, `Any` trait
objects are probably not the right solution; they’re good for cases with user-defined
types across a variety of libraries. But the question of purpose and suitability is open, and I
don’t have a really good example of such a use case here at present. TODO.


Cargo all the way.


[Chris Morgan]( ([chris-morgan]( is the primary author and maintainer of this library.


This library is distributed under similar terms to Rust: dual licensed under the MIT license and the Apache license (version 2.0).