Rust
Async-native Rust SDK built on tokio and reqwest. Optimized for high-throughput backends, web servers (Actix Web, Axum), and microservices with absolute thread-safety.
[dependencies]
toggleai = "0.1.0"
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"The Rust SDK leverages asynchronous design patterns to deliver maximum speed, concurrent safety, and background data synchronization in parallel concurrent runtimes:
⚡ Local In-Memory Evaluation
Upon invoking client.init().await, the SDK downloads the active ruleset from GET /sdk/config and atomic-swaps them locally using lock-free ArcSwap. Subsequent evaluations via client.get_flag_bool() or client.get_flag_value() execute instantly in-memory (sub-millisecond latency)—completely bypassing HTTP overhead on high-frequency paths.
🛰️ Edge Remote Evaluation
For security-sensitive computations requiring real-time server-side validation bypassing cached states, client.evaluate_flag_remote().await makes a direct network call to the edge gateway POST /sdk/evaluate, returning fresh determinations immediately.
use toggleai::{ToggleAIClient, Options, EvaluationContext, LogLevel};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Setup Options
let mut options = Options::default();
options.client_id = "pk_live_xxx".to_string();
options.secret = "sk_live_xxx".to_string();
options.polling_interval_ms = 30000;
// Create client
let mut client = ToggleAIClient::new(options)?;
// Initialize (fetches rules, starts background polling task)
client.init().await?;
// Create evaluation context
let mut attrs = HashMap::new();
attrs.insert("plan".to_string(), serde_json::json!("premium"));
let ctx = EvaluationContext {
user_id: Some("user_123".to_string()),
attributes: Some(attrs),
};
// 1. Evaluate Feature Flag (Synchronous local evaluation)
let is_enabled = client.get_flag_bool("new-checkout", Some(&ctx), false);
if is_enabled {
println!("Show new checkout experience");
}
// 2. Typed Flag Value
let button_color = client.get_flag_value::<String>("button-color", Some(&ctx), "#000000".to_string());
// 3. Remote Config Value
let timeout_ms = client.get_config::<i32>("api_timeout_ms", 5000);
// 4. Thread-Safe Background Logging
let logger = client.get_logger()?;
logger.info("Checkout viewed");
// Close (shuts down scheduled worker tasks and flushes final logs)
client.close();
Ok(())
}The client is fully thread-safe and safe to wrap inside an Arc to share as shared state across multiple web-server connection handlers:
use axum::{routing::get, Router, Extension};
use std::sync::Arc;
use toggleai::{ToggleAIClient, Options, EvaluationContext};
struct AppState {
client: ToggleAIClient,
}
#[tokio::main]
async fn main() {
let mut options = Options::default();
options.client_id = "pk_live_xxx".to_string();
options.secret = "sk_live_xxx".to_string();
let mut client = ToggleAIClient::new(options).unwrap();
client.init().await.unwrap();
let shared_state = Arc::new(AppState { client });
let app = Router::new()
.route("/api/checkout", get(handle_checkout))
.layer(Extension(shared_state));
let listener = tokio::net::TcpListener::bind("127.0.0.1:8080").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
async fn handle_checkout(Extension(state): Extension<Arc<AppState>>) -> &'static str {
let ctx = EvaluationContext {
user_id: Some("u_42".to_string()),
attributes: None,
};
// Thread-safe lock-free local evaluation
let show_new = state.client.get_flag_bool("new-checkout", Some(&ctx), false);
if show_new {
"New Checkout UI"
} else {
"Legacy Checkout UI"
}
}| Field | Type | Default |
|---|---|---|
client_id | String | required |
secret | String | required |
polling_interval_ms | u64 | 30000 |
evaluation_mode | EvaluationMode | EvaluationMode::Local |
disable_cache | bool | false |
default_context | Option<EvaluationContext> | None |
timeout_ms | u64 | 10000 |
| Method | Returns | Description |
|---|---|---|
new(opts) | Result<Self, ToggleAIError> | Instantiate a new client |
init() | async Result<(), ToggleAIError> | Fetch configurations, spawn background polling |
close() | void | Stop polling threads, drop log queues |
refresh() | async Result<(), ToggleAIError> | Manually force ruleset refresh |
get_flag(key, ctx) | Result<FlagEvaluationResult, ...> | Full local evaluation result |
get_flag_bool(key, ctx, default) | bool | In-memory local boolean check |
get_flag_bool_async(key, ctx, default) | async bool | Asynchronous boolean check, server if needed |
get_flag_value<T>(key, ctx, default) | T | In-memory typed flag value |
get_flag_value_async<T>(key, ctx, default) | async T | Asynchronous typed flag value, server if needed |
get_config<T>(key, default) | T | In-memory typed config value |
evaluate_flag_remote(key, ctx) | async Result<...> | Edge server-side evaluation |
evaluate_all_flags_remote(ctx) | async Result<...> | Edge server-side evaluation for all flags |
get_logger() | Result<ToggleAILogger, ...> | Get a cloned concurrency-safe background logger instance |