[−][src]Crate overrider
overrider
is a crate for making dynamic compilation easier.
About
overrider
aims to bring the override
keyword of some other programming languages,
such as Java and Python, to Rust. With this crate, a base implimentation of a function,
method, or other item can be defined and then later overriden. All of this happens at
compilation time.
overrider
also allows for defining flags
. By parsing flags with clap
in a
lazy_static
, highly efficient switching of functionality due to input flags
can be achieved.
Quick Example
The following code shows how overrider
is used in src
file:
use overrider::*; #[default] fn main() { println!("This is the base implimentation"); } #[override_default] fn main() { println!("This is the overriden implimentation"); }
Easy as that. If the second implimentation is included, the output changes.
How about with flags?
use overrider::*; use clap::{Arg, ArgMatches, App}; use lazy_static::lazy_static; lazy_static! { static ref CLAP_FLAGS: ArgMatches<'static> = { App::new("Overrider example - flag") .arg(Arg::with_name("change").long("change")) .get_matches() }; } #[default] fn main() { println!("Nothing to see here"); } #[override_flag(flag = change)] fn main() { println!("I'll be printed if you call this program with --change"); }
Flags can also be inverted if you want it to override the basic functionality, but be disabled on a flag input. For example
use clap::{Arg, ArgMatches, App};
lazy_static::lazy_static! {
static ref CLAP_FLAGS: ArgMatches<'static> = {
App::new("Overrider example - flag")
.version(env!("CARGO_PKG_VERSION"))
.arg(Arg::with_name("disable")
.long("disable"))
.get_matches()
};
}
#[default]
fn main() {
println!("This is the old default");
}
#[override_flag(flag = disable, invert = true)]
fn main() {
println!("This is the new default, pass --disable to turn off");
}```
### CAUTION
The invert flag causes undefined behavior when multiple override points for the same
item exists.
## Why not traits?
Rust has a powerful trait system which allows somewhat similar functionality.
However, it does not allow multiple, concurrent definitions without conflict.
Additionally, traits do not have built in support for flags.
## Impl
Due to limitations of `proc_macro`, all `overrider` flags __must__ be attached to
the ouside of an `impl` block, __not__ the inside.
The following is correct:
#[default] impl Foo { fn bar(){} }
The following is __not__ correct;
impl Foo { #[default] fn bar(){} }
Currently, `overrider` allows for the following items inside an `impl` block to
be manipulated:
- `fn` (methods)
- `const`ants
# Building
Because of limitations in `proc_macro`, `overrider` **will not work** without
it's sister crate `overrider_build`. This is because `overrider_build` parses
Rust files, supplying the `rustc` configuration flags nessicary for conditional
compilation. For the above files, placing this code in `build.rs` will do the trick:
fn main() { overrider_build::watch_files(vec!["src/main.rs"]); }
For more information, see the `overrider_build` documentation.
# More examples
Additional examples, verified to work, can be seen
[online](https://github.com/Shizcow/overrider-rs/tree/master/examples).
Try cloning the repository and running examples with `cargo run -p EXAMPLE_NAME`
Attribute Macros
default | Marks an item as the base implimentation |
override_default | Replaces (overrides) base implimentation |
override_final | Throw a compiler error to help ensure this item gets compiled |
override_flag | Override a base implimentation, but only when runtime is called with certain flags |