# Features [![Crate version](https://img.shields.io/crates/v/features.svg)][crate] [![Crate downloads](https://img.shields.io/crates/d/features.svg)][crate] [![Crate license](https://img.shields.io/crates/l/features.svg)][github] [![Documentation](https://img.shields.io/badge/documentation-docs.rs-df3600.svg?style=flat-square)][docs] [![AppVeyor](https://img.shields.io/appveyor/ci/fnichol/features-rs.svg)][build-windows] (Windows) [![Travis](https://img.shields.io/travis/fnichol/features-rs.svg)][build-unix] (Linux and OS X) [build-unix]: https://travis-ci.org/fnichol/features-rs [build-windows]: https://ci.appveyor.com/project/fnichol/features-rs [crate]: https://crates.io/crates/features [docs]: https://docs.rs/features [github]: https://github.com/fnichol/features-rs [lic-apachev2]: https://github.com/fnichol/features-rs/blob/master/LICENSE-APACHE [lic-mit]: https://github.com/fnichol/features-rs/blob/master/LICENSE-MIT ## About `features` is a small library that implements runtime [feature toggles][fowler_toggles] for your library or program allowing behavior to be changed on boot or dynamically at runtime using the same compiled binary artifact. This is different from cargo's [feature][cargo_feature] support which uses conditional compilation. At its core, it is a macro (`features!`) that takes a collection of feature flag names which it uses to generate a module containing a function to enable a feature toggle (`::enable()`), a function to disable a feature toggle (`::disable()`) and a function to check if a feature toggle is enabled (`::is_enabled()`). [fowler_toggles]: https://martinfowler.com/articles/feature-toggles.html [cargo_feature]: http://doc.crates.io/manifest.html#the-features-section ## Example Basic example: ```rust #[macro_use] extern crate bitflags; #[macro_use] extern crate features; features! { pub mod feature { const Alpha = 0b00000001, const Beta = 0b00000010 } } fn main() { assert_eq!(false, feature::is_enabled(feature::Alpha)); assert_eq!(false, feature::is_enabled(feature::Beta)); feature::enable(feature::Beta); assert_eq!(false, feature::is_enabled(feature::Alpha)); assert_eq!(true, feature::is_enabled(feature::Beta)); } ``` Multiple feature sets: ```rust #[macro_use] extern crate bitflags; #[macro_use] extern crate features; features! { pub mod ux { const JsonOutput = 0b10000000, const VerboseOutput = 0b01000000 } } features! { pub mod srv { const Http2Downloading = 0b10000000, const BitTorrentDownloading = 0b01000000 } } fn main() { // Parse CLI args, environment, read config file etc... srv::enable(srv::BitTorrentDownloading); ux::enable(ux::JsonOutput); if srv::is_enabled(srv::Http2Downloading) { println!("Downloading via http2..."); } else if srv::is_enabled(srv::BitTorrentDownloading) { println!("Downloading via bit torrent..."); } else { println!("Downloading the old fashioned way..."); } if ux::is_enabled(ux::VerboseOutput) { println!("COOL"); } } ``` ## Feature Toggle References Here are some articles and projects which insipred the implementation of `features`: * [Feature Toggles](https://martinfowler.com/articles/feature-toggles.html) (Martin Fowler's blog) * [Using Feature Flags to Ship Changes with Confidence](https://blog.travis-ci.com/2014-03-04-use-feature-flags-to-ship-changes-with-confidence/) (TravisCI's blog) * [Feature Toggles are one of the worst kinds of Technical Debt](http://swreflections.blogspot.ca/2014/08/feature-toggles-are-one-of-worst-kinds.html) (excellent cautionary tale and warning) * [Feature toggle](https://en.wikipedia.org/wiki/Feature_toggle) (Wikipedia article) * [Ruby feature gem](https://github.com/mgsnova/feature) (nice prior art) ## License Features is licensed under the Apache License, Version 2.0 and the MIT license. Please read the [LICENSE-APACHE] and [LICENSE-MIT] for details [LICENSE-APACHE]: https://github.com/fnichol/features-rs/blob/master/LICENSE-MIT [LICENSE-MIT]: https://github.com/fnichol/features-rs/blob/master/MIT-MIT