[][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");
}

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)
  • constants

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.
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