[][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