{"id":22780043,"url":"https://github.com/sitegui/feattle-rs","last_synced_at":"2025-04-22T19:24:24.546Z","repository":{"id":57628221,"uuid":"287936103","full_name":"sitegui/feattle-rs","owner":"sitegui","description":"Feature toggles for Rust, extensible and with background synchronization and administration UI","archived":false,"fork":false,"pushed_at":"2025-04-17T07:23:32.000Z","size":784,"stargazers_count":24,"open_issues_count":8,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-17T20:40:59.401Z","etag":null,"topics":["crate","feature-toggle","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sitegui.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-16T12:06:53.000Z","updated_at":"2025-04-17T07:23:35.000Z","dependencies_parsed_at":"2024-06-24T10:13:55.347Z","dependency_job_id":"b334087a-d978-40ea-b9ef-764276eaf626","html_url":"https://github.com/sitegui/feattle-rs","commit_stats":{"total_commits":106,"total_committers":3,"mean_commits":"35.333333333333336","dds":0.6320754716981132,"last_synced_commit":"4a885596c31ea3a475ce3fd7be1dd0d44cdfd131"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitegui%2Ffeattle-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitegui%2Ffeattle-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitegui%2Ffeattle-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sitegui%2Ffeattle-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sitegui","download_url":"https://codeload.github.com/sitegui/feattle-rs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249473539,"owners_count":21278318,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["crate","feature-toggle","rust"],"created_at":"2024-12-11T20:12:07.256Z","updated_at":"2025-04-22T19:24:24.535Z","avatar_url":"https://github.com/sitegui.png","language":"Rust","readme":"# feattle\n\n[![Crates.io](https://img.shields.io/crates/v/feattle.svg)](https://crates.io/crates/feattle)\n[![Docs.rs](https://docs.rs/feattle/badge.svg)](https://docs.rs/feattle)\n[![CI](https://github.com/sitegui/feattle-rs/workflows/Continuous%20Integration/badge.svg)](https://github.com/sitegui/feattle-rs/actions)\n[![Coverage Status](https://coveralls.io/repos/github/sitegui/feattle-rs/badge.svg?branch=master)](https://coveralls.io/github/sitegui/feattle-rs?branch=master)\n\nFeatture toggles for Rust  (called \"feattles\", for short), extensible and with background\nsynchronization and administration UI.\n\n### Features\n- Feature toggles that synchronize automatically with a backing storage\n- Feature toggles can be as simple `bool`, but can also be lists, maps and arbitrary tpes (\n  (through the [`FeattleValue`] trait).\n- Web UI with documentation, change history, validation\n- JSON API to read and set the toggles\n- Modular and extensible: use as much or as little of the bundled features as you want. Want to\n  use a different Web UI? A different storage layer? No problem.\n\n### Example\n\n```rust\nuse feattle::*;\nuse std::sync::Arc;\n\n/// A struct with your feature toggles: you can use primitive types (like `bool`, `i32`, etc),\n/// standard collections (like `Vec`, `BTreeSet`, etc) or any arbitrary type that implements\n/// the required trait.\nfeattles! {\n    struct MyFeattles {\n        /// Is this usage considered cool?\n        is_cool: bool = true,\n        /// Limit the number of \"blings\" available.\n        /// This will not change the number of \"blengs\", though!\n        max_blings: i32,\n        /// List the actions that should not be available\n        blocked_actions: Vec\u003cString\u003e,\n    }\n}\n\n#[tokio::main]\nasync fn main() {\n    // Store their values and history in AWS' S3\n    use std::future::IntoFuture;\n    use std::time::Duration;\n    use tokio::net::TcpListener;\n    let config = aws_config::load_from_env().await;\n    let persistence = Arc::new(S3::new(\n        \u0026config,\n        \"my-bucket\".to_owned(),\n        \"some/s3/prefix/\".to_owned(),\n    ));\n\n    // Create a new instance\n    let my_feattles = Arc::new(MyFeattles::new(persistence));\n\n    // Poll the storage in the background\n    BackgroundSync::new(\u0026my_feattles).start().await;\n\n    // Start the admin UI with `warp`\n    let admin_panel = Arc::new(AdminPanel::new(my_feattles.clone(), \"Project Panda - DEV\".to_owned()));\n    tokio::spawn(run_warp_server(admin_panel.clone(), ([127, 0, 0, 1], 3030)));\n\n    // Or serve the admin panel with `axum`\n    let router = axum_router(admin_panel);\n    let listener = TcpListener::bind((\"127.0.0.1\", 3031)).await.unwrap();\n    tokio::spawn(axum::serve(listener, router.into_make_service()).into_future());\n\n    // Read values (note the use of `*`)\n    assert_eq!(*my_feattles.is_cool(), true);\n    assert_eq!(*my_feattles.max_blings(), 0);\n    assert_eq!(*my_feattles.blocked_actions(), Vec::\u003cString\u003e::new());\n}\n```\n\nYou can run a full example locally with: `cargo run --example full --features='s3 uuid warp axum'`.\n\nWith this code, you'll get an Web Admin UI like:\n\n![Home Web Admin UI](https://raw.githubusercontent.com/sitegui/feattle-rs/master/imgs/home.png)\n\nYou can use the UI to edit the current values and see their change history. For example, this\nis what you can expect when editing an `enum`:\n\n![Edit enum](https://raw.githubusercontent.com/sitegui/feattle-rs/master/imgs/edit_enum.png)\n\nIt also supports complex types with a JSON editor and helpful error diagnostics:\n\n![Edit JSON](https://raw.githubusercontent.com/sitegui/feattle-rs/master/imgs/edit_json.png)\n\n## How it works\n\nThe macro will generate a struct with the given name and visibility modifier (assuming private\nby default). The generated struct implements [`Feattles`] and also exposes one method for each\nfeattle.\n\nThe methods created for each feattle allow reading their current value. For example, for a\nfeattle `is_cool: bool`, there will be a method like\n`pub fn is_cool(\u0026self) -\u003e MappedRwLockReadGuard\u003cbool\u003e`. Note the use of\n[`parking_lot::MappedRwLockReadGuard`] because the interior of the struct is stored behind a `RwLock` to\ncontrol concurrent access.\n\nA feattle is created with the syntax `$key: $type [= $default]`. You can use doc coments (\nstarting with `///`) to describe nicely what they do in your system. You can use any type that\nimplements [`FeattleValue`] and optionally provide a default. If not provided, the default\nwill be created with `Default::default()`.\n\n## Minimum supported Rust version\n\nAs of this release, the MSRV is 1.82.0, as tested in the CI. A patch release will never require\na newer MSRV.\n\n## Optional features\n\nYou can easily declare feattles with your custom types, use another persistance storage logic\nor Web Framework (or any at all). For some out-of-the-box functionality, you can activate these\ncargo features:\n\n- **uuid**: will add support for [`uuid::Uuid`].\n- **rusoto_s3**: provides [`RusotoS3`] to integrate with AWS' S3\n- **aws_sdk_s3**: provides [`S3`] to integrate with AWS' S3\n- **warp**: provides [`run_warp_server`] for a read-to-use integration with [`warp`]\n- **axum**: provides [`axum_router`] for a read-to-use integration with [`axum`]\n\n### Crate's organization\n\nThis crate is a simple re-export of these three components:\n\n* `feattle-core`: [![Crates.io](https://img.shields.io/crates/v/feattle-core.svg)](https://crates.io/crates/feattle-core)\n* `feattle-sync`: [![Crates.io](https://img.shields.io/crates/v/feattle-sync.svg)](https://crates.io/crates/feattle-sync)\n* `feattle-ui`: [![Crates.io](https://img.shields.io/crates/v/feattle-ui.svg)](https://crates.io/crates/feattle-ui)\n\nHaving them separate allows for leaner lower-level integration. If you're creating a crate to\nprovide a different storage or admin, you just need `feattle-core`.\n\n## License\n\nLicensed under either of\n\n * Apache License, Version 2.0\n   ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)\n * MIT license\n   ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n\n## Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be\ndual licensed as above, without any additional terms or conditions.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsitegui%2Ffeattle-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsitegui%2Ffeattle-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsitegui%2Ffeattle-rs/lists"}