concrete-type 0.1.0

A procedural macro crate for mapping enum variants to concrete types, enabling type-level programming based on runtime values
Documentation
concrete-type-0.1.0 has been yanked.

concrete-type

Crates.io Documentation MIT License

A Rust procedural macro library for mapping enum variants to concrete types, enabling type-level programming based on runtime enum values.

Table of Contents

Overview

concrete-type provides procedural macros that create a relationship between enum variants and specific concrete types. This enables:

  • Type-level programming with enums
  • Executing code with concrete type knowledge at compile time based on runtime enum values
  • Generating helpful utility methods and macros for working with the concrete types
  • Optionally carrying configuration data with enum variants

Installation

Add this to your Cargo.toml:

[dependencies]
concrete-type = "0.1.0"

Features

#[derive(Concrete)]

  • Map enum variants to concrete types with #[concrete = "path::to::Type"] attribute
  • Generated methods:
    • concrete_type_id(): Returns the TypeId of the concrete type for a variant
    • concrete_type_name(): Returns the name of the concrete type as a string
    • with_concrete_type(): Executes a function with knowledge of the concrete type
  • Auto-generated macros for type-level dispatch using the snake_case name of the enum

#[derive(ConcreteConfig)]

  • Map enum variants with configuration data to concrete types
  • Each variant must have a single tuple field containing the configuration
  • Generated methods:
    • concrete_type_id(): Returns the TypeId of the concrete type for a variant
    • concrete_type_name(): Returns the name of the concrete type as a string
    • config(): Returns a reference to the configuration data
  • Auto-generated macros for type-level dispatch with access to both the concrete type and config data

Examples

Basic Usage

use concrete_type::Concrete;

#[derive(Concrete)]
enum Exchange {
    #[concrete = "exchanges::Binance"]
    Binance,
    #[concrete = "exchanges::Okx"]
    Okx,
}

// 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()
});

Enums with Config Data

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;

    impl ExchangeApi for Binance {
        type Config = BinanceConfig;
        fn new(_: Self::Config) -> Self { Self }
        fn name(&self) -> &'static str { "binance" }
    }

    pub struct Okx;
    pub struct OkxConfig;

    impl ExchangeApi for Okx {
        type Config = OkxConfig;
        fn new(_: Self::Config) -> Self { Self }
        fn name(&self) -> &'static str { "okx" }
    }
}

// Define the exchange config enum with concrete type mappings and config data
#[derive(ConcreteConfig)]
enum ExchangeConfig {
    #[concrete = "exchanges::Binance"]
    Binance(exchanges::BinanceConfig),
    #[concrete = "exchanges::Okx"]
    Okx(exchanges::OkxConfig),
}

// Import the trait for access to its methods
use exchanges::ExchangeApi;

// Using the auto-generated exchange_config! macro:
let config = ExchangeConfig::Binance(exchanges::BinanceConfig);
let name = exchange_config!(config; (Exchange, config_param) => {
    // Inside this block:
    // - Exchange is aliased to exchanges::Binance
    // - config_param is the BinanceConfig instance
    Exchange::new(config_param).name()
});

Parameterized Types

For more complex use cases, you can also use multiple enums together:

use concrete_type::Concrete;
use std::marker::PhantomData;

// Define enums that map to concrete types
#[derive(Concrete, Clone, Copy)]
enum Exchange {
    #[concrete = "exchanges::Binance"]
    Binance,
    #[concrete = "exchanges::Okx"]
    Okx,
}

#[derive(Concrete)]
enum Strategy {
    #[concrete = "strategies::StrategyA"]
    StrategyA,
    #[concrete = "strategies::StrategyB"]
    StrategyB,
}

// A struct with type parameters that will be resolved at runtime
#[derive(Concrete)]
struct TradingSystem<E, S> {
    phantom: PhantomData<(E, S)>,
}

// Later use multiple enum values together:
let exchange = Exchange::Okx;
let strategy = Strategy::StrategyB;

let name = trading_system!(exchange, strategy; (E, S) => {
    // Here E is exchanges::Okx and S is strategies::StrategyB
    TradingSystem::<E, S>::new().name()
});

License

MIT