{"id":20483458,"url":"https://github.com/chris-morgan/mopa","last_synced_at":"2025-04-05T09:08:53.726Z","repository":{"id":25382977,"uuid":"28811348","full_name":"chris-morgan/mopa","owner":"chris-morgan","description":"MOPA: My Own Personal Any. A macro to implement all the `Any` methods on your own trait.","archived":false,"fork":false,"pushed_at":"2023-01-10T12:16:49.000Z","size":54,"stargazers_count":114,"open_issues_count":7,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-29T08:08:13.966Z","etag":null,"topics":["rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chris-morgan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-01-05T12:16:57.000Z","updated_at":"2025-01-23T01:16:53.000Z","dependencies_parsed_at":"2023-01-14T02:39:04.706Z","dependency_job_id":null,"html_url":"https://github.com/chris-morgan/mopa","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-morgan%2Fmopa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-morgan%2Fmopa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-morgan%2Fmopa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-morgan%2Fmopa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chris-morgan","download_url":"https://codeload.github.com/chris-morgan/mopa/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247312081,"owners_count":20918344,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["rust"],"created_at":"2024-11-15T16:17:25.698Z","updated_at":"2025-04-05T09:08:53.619Z","avatar_url":"https://github.com/chris-morgan.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"MOPA: My Own Personal Any\n=========================\n\n[![Build Status](https://travis-ci.org/chris-morgan/mopa.svg?branch=master)](https://travis-ci.org/chris-morgan/mopa)\n\n\u003c!-- The rest of this section comes straight from the crate docs from the source. --\u003e\n\nA macro to implement all the `Any` methods on your own trait.\n\nYou like `Any`—its ability to store any `'static` type as a trait object and then downcast it\nback to the original type is very convenient, and in fact you need it for whatever misguided\nreason. But it’s not enough. What you *really* want is your own trait object type with `Any`’s\nfunctionality glued onto it. Maybe you have a `Person` trait and you want your people to be\nable to do various things, but you also want to be able to conveniently downcast the person to\nits original type, right? Alas, you can’t write a type like `Box\u003cPerson + Any\u003e` (at present,\nanyway). So what do you do instead? Do you give up? No, no! No, no! Enter MOPA.\n\n\u003e There once was a quite friendly trait  \n\u003e Called `Person`, with much on its plate.  \n\u003e     “I need to be `Any`  \n\u003e     To downcast to `Benny`—  \n\u003e But I’m not, so I guess I’ll just wait.”\n\nA pitiful tale, isn’t it? Especially given that there was a bear chasing it with intent to eat\nit. Fortunately now you can *mopafy* `Person` in three simple steps:\n\n1. Add the `mopa` crate to your `Cargo.toml` as usual and your crate root like so:\n\n   ```rust\n   #[macro_use]\n   extern crate mopa;\n   ```\n\n2. Make `Any` (`mopa::Any`, not `std::any::Any`) a supertrait of `Person`;\n\n3. `mopafy!(Person);`.\n\nAnd lo, you can now write `person.is::\u003cBenny\u003e()` and `person.downcast_ref::\u003cBenny\u003e()` and so on\nto your heart’s content. Simple, huh?\n\nOh, by the way, it was actually the person on the bear’s plate. There wasn’t really anything on\n`Person`’s plate after all.\n\n```rust\n#[macro_use]\nextern crate mopa;\n\nstruct Bear {\n    // This might be a pretty fat bear.\n    fatness: u16,\n}\n\nimpl Bear {\n    fn eat(\u0026mut self, person: Box\u003cPerson\u003e) {\n        self.fatness = (self.fatness as i16 + person.weight()) as u16;\n    }\n}\n\ntrait Person: mopa::Any {\n    fn panic(\u0026self);\n    fn yell(\u0026self) { println!(\"Argh!\"); }\n    fn sleep(\u0026self);\n    fn weight(\u0026self) -\u003e i16;\n}\n\nmopafy!(Person);\n\nstruct Benny {\n    // (Benny is not a superhero. He can’t carry more than 256kg of food at once.)\n    kilograms_of_food: u8,\n}\n\nimpl Person for Benny {\n    fn panic(\u0026self) { self.yell() }\n    fn sleep(\u0026self) { /* ... */ }\n    fn weight(\u0026self) -\u003e i16 {\n        // Who’s trying to find out? I’m scared!\n        self.yell();\n        self.kilograms_of_food as i16 + 60\n    }\n}\n\nstruct Chris;\n\nimpl Chris {\n    // Normal people wouldn’t be brave enough to hit a bear but Chris might.\n    fn hit(\u0026self, bear: \u0026mut Bear) {\n        println!(\"Chris hits the bear! How brave! (Or maybe stupid?)\");\n        // Meh, boundary conditions, what use are they in examples?\n        // Chris clearly hits quite hard. Poor bear.\n        bear.fatness -= 1;\n    }\n}\n\nimpl Person for Chris {\n    fn panic(\u0026self) { /* ... */ }\n    fn sleep(\u0026self) { /* ... */ }\n    fn weight(\u0026self) -\u003e i16 { -5 /* antigravity device! cool! */ }\n}\n\nfn simulate_simulation(person: Box\u003cPerson\u003e, bear: \u0026mut Bear) {\n    if person.is::\u003cBenny\u003e() {\n        // None of the others do, but Benny knows this particular\n        // bear by reputation and he’s *really* going to be worried.\n        person.yell()\n    }\n    // If it happens to be Chris, he’ll hit the bear.\n    person.downcast_ref::\u003cChris\u003e().map(|chris| chris.hit(bear));\n    bear.eat(person);\n}\n\nfn main() {\n    let mut bear = Bear { fatness: 10 };\n    simulate_simulation(Box::new(Benny { kilograms_of_food: 5 }), \u0026mut bear);\n    simulate_simulation(Box::new(Chris), \u0026mut bear);\n}\n```\n\nNow *should* you do something like this? Probably not. Enums are probably a better solution for\nthis particular case as written; frankly I believe that almost the only time you should\ndowncast an `Any` trait object (or a mopafied trait object) is with a generic parameter, when\nproducing something like `AnyMap`, for example. If you control *all* the code, `Any` trait\nobjects are probably not the right solution; they’re good for cases with user-defined\ntypes across a variety of libraries. But the question of purpose and suitability is open, and I\ndon’t have a really good example of such a use case here at present. TODO.\n\nUsage\n-----\n\nCargo all the way. http://crates.io/crates/mopa\n\nAuthor\n------\n\n[Chris Morgan](https://chrismorgan.info/) ([chris-morgan](https://github.com/chris-morgan)) is the primary author and maintainer of this library.\n\nLicense\n-------\n\nThis library is distributed under similar terms to Rust: dual licensed under the MIT license and the Apache license (version 2.0).\n\nSee LICENSE-APACHE, LICENSE-MIT, and COPYRIGHT for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchris-morgan%2Fmopa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchris-morgan%2Fmopa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchris-morgan%2Fmopa/lists"}