Expand description
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