Skip to main content

Procedural Macros

toggly-macros adds declarative gates around the same client's local evaluations. Macros do not initialize a client, authenticate a user, fetch a separate context or assign variants.

Installation​

[dependencies]
toggly = "0.6"
toggly-macros = "0.6"

Use these functions from an async application with an already initialized client, such as the quick start.

#[feature_flag] Attribute​

With Custom Client​

With Custom Context​

With Fallback​

Specify the feature key, client expression, context expression and compatible fallback explicitly:

use toggly::{EvalContext, TogglyClient};
use toggly_macros::feature_flag;

fn classic_dashboard() -> &'static str { "Classic dashboard" }

#[feature_flag(
feature = "new-dashboard",
client = "client",
context = "context",
fallback = "classic_dashboard()"
)]
pub async fn dashboard(client: &TogglyClient, context: EvalContext) -> &'static str {
"New dashboard"
}

When the flag is false, the macro returns the fallback before executing the function body. Evaluation errors are converted to false. Without an explicit client expression, the macro expects a variable named toggly_client; without context, it uses EvalContext::default(). Explicit parameters make dependencies and ownership clear.

Negated Check​

use toggly::{EvalContext, TogglyClient};
use toggly_macros::feature_flag;

#[feature_flag(
feature = "new-dashboard", client = "client", context = "context",
negate = true, fallback = "false"
)]
pub async fn show_classic(client: &TogglyClient, context: EvalContext) -> bool {
true
}

Full Example​

Call dashboard(&client, context).await from your async handler, then render the returned text. Keep client initialization and shutdown at application scope. For errors that must be propagated rather than converted to a fallback, call client.is_enabled(...).await? directly instead of using this attribute.

#[derive(FeatureFlags)] Derive Macro​

Generated Methods​

Usage​

use toggly::{EvalContext, TogglyClient};
use toggly_macros::FeatureFlags;

#[derive(FeatureFlags)]
pub enum Features {
#[toggly(key = "new-dashboard")]
NewDashboard,
#[toggly(key = "api-v2")]
ApiV2,
}

pub async fn check_features(client: &TogglyClient, context: EvalContext)
-> toggly::Result<bool>
{
println!("Checking {}", Features::NewDashboard.key());
Features::NewDashboard.is_enabled(client, context).await
}

The derive generates key(), default_value(), is_enabled(...) and is_disabled(...). Use #[toggly(...)], not #[feature(...)].

With Default Values​

use toggly_macros::FeatureFlags;

#[derive(FeatureFlags)]
pub enum Metadata {
#[toggly(key = "optional-banner", default = true)]
OptionalBanner,
}

Metadata::OptionalBanner.default_value() returns metadata for application code. It does not override the client's evaluation of an undefined flag: generated is_enabled delegates to the client. Do not rely on the derive's default as a missing-flag fallback.

feature_gate! Macro​

The expression macro selects a block. Both branches must have compatible Rust result types:

use toggly::{EvalContext, TogglyClient};
use toggly_macros::feature_gate;

pub async fn label(client: &TogglyClient, context: EvalContext) -> &'static str {
feature_gate!(client, "new-dashboard", context, {
"New dashboard"
}, {
"Classic dashboard"
})
}

Without Fallback​

Omit the second block only for unit-returning work. A false result executes no enabled block. Like the attribute macro, evaluation errors become false.

In Match Arms​

A macro expression can be placed wherever its resulting Rust type is valid. It still awaits evaluation, so the enclosing function must be async.

Best Practices​

Keep feature keys in an enum when useful, pass context explicitly, and give disabled paths meaningful product behavior. Multi-key gates remain a client API; feature_gate! accepts one literal key.

Limitations​

These macros require an async context and an available client. They do not supply a public custom-filter interface or variant assignment. Derive defaults are metadata; macros do not replace authentication, request mapping or client lifecycle.