Crates.io | concrete-type |
lib.rs | concrete-type |
version | |
source | src |
created_at | 2025-04-09 22:40:49.890885+00 |
updated_at | 2025-04-13 14:57:52.059232+00 |
description | A procedural macro crate for mapping enum variants to concrete types, enabling type-level programming based on runtime values |
homepage | |
repository | https://github.com/justastream/concrete-type |
max_upload_size | |
id | 1627384 |
Cargo.toml error: | TOML parse error at line 18, column 1 | 18 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include` |
size | 0 |
A procedural macro library for mapping enum variants to concrete types, enabling type-level programming based on runtime enum values.
concrete-type
provides procedural macros that create a relationship between enum variants and specific concrete types.
This enables:
Add this to your Cargo.toml
:
[dependencies]
concrete-type = "0.2.0"
#[derive(Concrete)]
The Concrete
derive macro is designed for enums where each variant maps to a specific concrete type.
#[concrete = "path::to::Type"]
attributeExample:
#[derive(Concrete)]
enum StrategyKind {
#[concrete = "strategies::StrategyA"]
StrategyA,
#[concrete = "strategies::StrategyB"]
StrategyB,
}
// Generated macro is named 'strategy_kind!'
#[derive(ConcreteConfig)]
The ConcreteConfig
derive macro is designed for enums where each variant has associated configuration data and maps to a specific concrete type.
config()
: Returns a reference to the configuration dataExample:
#[derive(ConcreteConfig)]
enum ExchangeConfig {
#[concrete = "exchanges::Binance"]
Binance(exchanges::BinanceConfig),
}
// Generated macro is named 'exchange_config!'
use concrete_type::Concrete;
#[derive(Concrete, Clone, Copy)]
enum Exchange {
#[concrete = "exchanges::Binance"]
Binance,
#[concrete = "exchanges::Coinbase"]
Coinbase,
}
mod exchanges {
pub struct Binance;
pub struct Coinbase;
impl Binance {
pub fn new() -> Self { Binance }
pub fn name(&self) -> &'static str { "binance" }
}
impl Coinbase {
pub fn new() -> Self { Coinbase }
pub fn name(&self) -> &'static str { "coinbase" }
}
}
// Use the auto-generated 'exchange!' macro to work with concrete types
let exchange = Exchange::Binance;
let name = exchange!(exchange; ExchangeImpl => {
// Here, ExchangeImpl is aliased to the concrete type (exchanges::Binance)
let instance = ExchangeImpl::new();
instance.name()
});
assert_eq!(name, "binance");
use concrete_type::ConcreteConfig;
// Define concrete types and configuration types
mod exchanges {
pub trait ExchangeApi {
type Config;
fn new(config: Self::Config) -> Self;
fn name(&self) -> &'static str;
}
pub struct Binance;
pub struct BinanceConfig {
pub api_key: String,
}
impl ExchangeApi for Binance {
type Config = BinanceConfig;
fn new(_: Self::Config) -> Self { Self }
fn name(&self) -> &'static str { "binance" }
}
}
// Define the enum with concrete type mappings and config data
#[derive(ConcreteConfig)]
enum ExchangeConfig {
#[concrete = "exchanges::Binance"]
Binance(exchanges::BinanceConfig),
}
// Using the auto-generated macro with access to both type and config
let config = ExchangeConfig::Binance(
exchanges::BinanceConfig { api_key: "secret".to_string() }
);
let name = exchange_config!(config; (Exchange, cfg) => {
// Inside this block:
// - Exchange is the concrete type (exchanges::Binance)
// - cfg is the configuration instance (BinanceConfig)
use exchanges::ExchangeApi;
Exchange::new(cfg).name()
});
Contributions are welcome! Please feel free to submit a Pull Request.
MIT