use std::ops::Deref;
use std::sync::Arc;
#[derive(Debug)]
pub struct DerustedConfig {
pub host: String,
pub port: u16,
pub rate_limit_requests_per_minute: usize,
pub max_request_body_size: usize,
}
impl DerustedConfig {
pub fn new() -> Self {
Self {
host: "0.0.0.0".to_string(),
port: 443,
rate_limit_requests_per_minute: 10000,
max_request_body_size: 100 * 1024 * 1024, }
}
}
#[derive(Debug, Clone)]
pub struct AnalyticsLogger {
endpoint: String,
batch_size: usize,
}
impl AnalyticsLogger {
pub fn new(endpoint: &str, batch_size: usize) -> Self {
Self {
endpoint: endpoint.to_string(),
batch_size,
}
}
pub fn log_request(&self, path: &str, latency_ms: u64) {
println!(
"[Analytics] {} - {}ms (batch: {}, endpoint: {})",
path, latency_ms, self.batch_size, self.endpoint
);
}
}
#[derive(Debug, Clone)]
pub struct FeatureFlags {
pub enable_caching: bool,
pub enable_compression: bool,
pub enable_beta_features: bool,
pub max_cache_size_mb: usize,
}
impl Default for FeatureFlags {
fn default() -> Self {
Self {
enable_caching: true,
enable_compression: true,
enable_beta_features: false,
max_cache_size_mb: 512,
}
}
}
pub trait RequestValidator: Send + Sync + std::fmt::Debug {
fn validate_path(&self, path: &str) -> bool;
fn validate_headers(&self, headers: &[(&str, &str)]) -> bool;
}
#[derive(Debug)]
pub struct PathValidator {
blocked_paths: Vec<String>,
}
impl PathValidator {
pub fn new(blocked_paths: Vec<String>) -> Self {
Self { blocked_paths }
}
}
impl RequestValidator for PathValidator {
fn validate_path(&self, path: &str) -> bool {
!self.blocked_paths.iter().any(|blocked| path.starts_with(blocked))
}
fn validate_headers(&self, _headers: &[(&str, &str)]) -> bool {
true }
}
#[derive(Debug)]
pub struct MyAppConfig {
base: DerustedConfig,
pub analytics: Arc<AnalyticsLogger>,
pub features: FeatureFlags,
pub validator: Arc<dyn RequestValidator>,
pub app_name: String,
pub app_version: String,
pub environment: String,
}
impl Deref for MyAppConfig {
type Target = DerustedConfig;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl MyAppConfig {
pub fn new(
base: DerustedConfig,
app_name: &str,
environment: &str,
) -> Self {
Self {
base,
analytics: Arc::new(AnalyticsLogger::new(
"https://analytics.example.com/v1/events",
100,
)),
features: FeatureFlags::default(),
validator: Arc::new(PathValidator::new(vec![
"/admin".to_string(),
"/internal".to_string(),
])),
app_name: app_name.to_string(),
app_version: env!("CARGO_PKG_VERSION").to_string(),
environment: environment.to_string(),
}
}
pub fn with_analytics(mut self, endpoint: &str, batch_size: usize) -> Self {
self.analytics = Arc::new(AnalyticsLogger::new(endpoint, batch_size));
self
}
pub fn with_features(mut self, features: FeatureFlags) -> Self {
self.features = features;
self
}
pub fn with_validator(mut self, validator: Arc<dyn RequestValidator>) -> Self {
self.validator = validator;
self
}
}
fn main() {
println!("=== Custom Config Extension Demo ===\n");
let base_config = DerustedConfig::new();
let config = MyAppConfig::new(base_config, "my-proxy-app", "production")
.with_features(FeatureFlags {
enable_caching: true,
enable_compression: true,
enable_beta_features: false,
max_cache_size_mb: 1024,
})
.with_analytics("https://my-analytics.example.com", 50);
println!("--- Accessing derusted fields (via Deref) ---");
println!("Host: {}", config.host); println!("Port: {}", config.port);
println!("Rate limit: {} req/min", config.rate_limit_requests_per_minute);
println!("Max body size: {} bytes", config.max_request_body_size);
println!("\n--- Accessing custom fields ---");
println!("App name: {}", config.app_name);
println!("App version: {}", config.app_version);
println!("Environment: {}", config.environment);
println!("\n--- Using custom analytics ---");
config.analytics.log_request("/api/users", 42);
config.analytics.log_request("/api/orders", 156);
println!("\n--- Feature flags ---");
println!("Caching enabled: {}", config.features.enable_caching);
println!("Compression enabled: {}", config.features.enable_compression);
println!("Beta features: {}", config.features.enable_beta_features);
println!("Max cache size: {} MB", config.features.max_cache_size_mb);
println!("\n--- Custom request validation ---");
let test_paths = ["/api/users", "/admin/settings", "/public/docs", "/internal/health"];
for path in test_paths {
let allowed = config.validator.validate_path(path);
println!("Path '{}': {}", path, if allowed { "ALLOWED" } else { "BLOCKED" });
}
println!("\n--- Function that expects base config ---");
process_with_base_config(&config);
}
fn process_with_base_config(config: &DerustedConfig) {
println!(
"Processing with base config: {}:{} (rate limit: {})",
config.host, config.port, config.rate_limit_requests_per_minute
);
}