Crates.io | feattle |
lib.rs | feattle |
version | 2.0.0 |
source | src |
created_at | 2020-10-11 22:04:22.459278 |
updated_at | 2024-06-26 08:23:09.019724 |
description | Featture toggles for Rust, extensible and with background synchronization and administration UI |
homepage | |
repository | https://github.com/sitegui/feattle-rs |
max_upload_size | |
id | 298455 |
size | 96,454 |
Featture toggles for Rust (called "feattles", for short), extensible and with background synchronization and administration UI.
bool
, but can also be lists, maps and arbitrary tpes (
(through the [FeattleValue
] trait).use feattle::*;
use std::sync::Arc;
/// A struct with your feature toggles: you can use primitive types (like `bool`, `i32`, etc),
/// standard collections (like `Vec`, `BTreeSet`, etc) or any arbitrary type that implements
/// the required trait.
feattles! {
struct MyFeattles {
/// Is this usage considered cool?
is_cool: bool = true,
/// Limit the number of "blings" available.
/// This will not change the number of "blengs", though!
max_blings: i32,
/// List the actions that should not be available
blocked_actions: Vec<String>,
}
}
#[tokio::main]
async fn main() {
// Store their values and history in AWS' S3
use std::future::IntoFuture;
use std::time::Duration;
use tokio::net::TcpListener;
let config = aws_config::load_from_env().await;
let persistence = Arc::new(S3::new(
&config,
"my-bucket".to_owned(),
"some/s3/prefix/".to_owned(),
));
// Create a new instance
let my_feattles = Arc::new(MyFeattles::new(persistence));
// Poll the storage in the background
BackgroundSync::new(&my_feattles).start().await;
// Start the admin UI with `warp`
let admin_panel = Arc::new(AdminPanel::new(my_feattles.clone(), "Project Panda - DEV".to_owned()));
tokio::spawn(run_warp_server(admin_panel.clone(), ([127, 0, 0, 1], 3030)));
// Or serve the admin panel with `axum`
let router = axum_router(admin_panel);
let listener = TcpListener::bind(("127.0.0.1", 3031)).await.unwrap();
tokio::spawn(axum::serve(listener, router.into_make_service()).into_future());
// Read values (note the use of `*`)
assert_eq!(*my_feattles.is_cool(), true);
assert_eq!(*my_feattles.max_blings(), 0);
assert_eq!(*my_feattles.blocked_actions(), Vec::<String>::new());
}
You can run a full example locally with: cargo run --example full --features='s3 uuid warp axum'
.
With this code, you'll get an Web Admin UI like:
You can use the UI to edit the current values and see their change history. For example, this
is what you can expect when editing an enum
:
It also supports complex types with a JSON editor and helpful error diagnostics:
The macro will generate a struct with the given name and visibility modifier (assuming private
by default). The generated struct implements [Feattles
] and also exposes one method for each
feattle.
The methods created for each feattle allow reading their current value. For example, for a
feattle is_cool: bool
, there will be a method like
pub fn is_cool(&self) -> MappedRwLockReadGuard<bool>
. Note the use of
[parking_lot::MappedRwLockReadGuard
] because the interior of the struct is stored behind a RwLock
to
control concurrent access.
A feattle is created with the syntax $key: $type [= $default]
. You can use doc coments (
starting with ///
) to describe nicely what they do in your system. You can use any type that
implements [FeattleValue
] and optionally provide a default. If not provided, the default
will be created with Default::default()
.
As of this release, the MSRV is 1.76.0, as tested in the CI. A patch release will never require a newer MSRV.
You can easily declare feattles with your custom types, use another persistance storage logic or Web Framework (or any at all). For some out-of-the-box functionality, you can activate these cargo features:
uuid::Uuid
].RusotoS3
] to integrate with AWS' S3S3
] to integrate with AWS' S3run_warp_server
] for a read-to-use integration with [warp
]axum_router
] for a read-to-use integration with [axum
]This crate is a simple re-export of these three components:
Having them separate allows for leaner lower-level integration. If you're creating a crate to
provide a different storage or admin, you just need feattle-core
.
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
See CONTRIBUTING.md.