concrete_type_rules/lib.rs
1#![doc(html_root_url = "https://docs.rs/concrete-type-rules")]
2#![warn(missing_docs)]
3
4//! # Concrete Type Rules
5//!
6//! Utilities and extensions for working with the `concrete-type` crate.
7//!
8//! This crate provides additional tools for composing multiple concrete types together,
9//! including macros for generating combined matchers that can handle multiple enum types
10//! at once.
11//!
12//! ## Features
13//!
14//! - `gen_match_concretes_macro!` - Generates macros for matching multiple enum instances
15//! simultaneously, with support for 2-5 enum types.
16//!
17//! ## Examples
18//!
19//! ### Combined Matcher for Two Enum Types
20//!
21//! ```rust,ignore
22//! use concrete_type::Concrete;
23//! use concrete_type_rules::gen_match_concretes_macro;
24//!
25//! #[derive(Concrete)]
26//! enum Exchange {
27//! #[concrete = "exchanges::Binance"]
28//! Binance,
29//! }
30//!
31//! #[derive(Concrete)]
32//! enum Strategy {
33//! #[concrete = "strategies::StrategyA"]
34//! StrategyA,
35//! }
36//!
37//! mod exchanges {
38//! pub struct Binance;
39//! }
40//!
41//! mod strategies {
42//! pub struct StrategyA;
43//! }
44//!
45//! // Generate a combined matcher macro
46//! gen_match_concretes_macro!(Exchange, Strategy);
47//!
48//! // Now you can use the generated macro with both enum instances
49//! let exchange = Exchange::Binance;
50//! let strategy = Strategy::StrategyA;
51//!
52//! // This uses a single match expression for both enums
53//! let result = match_exchange_strategy!(exchange, strategy; E, S => {
54//! // E is exchanges::Binance, S is strategies::StrategyA
55//! format!("{} + {}", std::any::type_name::<E>(), std::any::type_name::<S>())
56//! });
57//! ```
58//!
59//! ### Using With More Enum Types
60//!
61//! ```rust,ignore
62//! // For 3 enum types:
63//! gen_match_concretes_macro!(Exchange, Strategy, Market);
64//!
65//! // Generated macro name combines all enum names in snake_case
66//! // E.g., match_exchange_strategy_market!
67//!
68//! // For 4 or 5 enum types:
69//! gen_match_concretes_macro!(Exchange, Strategy, Market, Asset, TimeFrame);
70//! ```
71
72/// A macro that generates a combined matcher macro for multiple concrete enums.
73///
74/// This macro creates a new macro that allows you to match multiple enum instances
75/// simultaneously, providing type parameters for each concrete type associated with
76/// the enum variants.
77///
78/// # Arguments
79///
80/// * First argument: First enum type name
81/// * Second argument: Second enum type name
82/// * Optionally: Third, fourth, and fifth enum type names
83///
84/// The generated macro will be named using the snake_case of all provided enum names,
85/// joined with underscores and prefixed with "match_".
86///
87/// # Generated Macro Usage
88///
89/// The generated macro accepts:
90///
91/// * Enum instances as positional parameters (one for each enum type)
92/// * Type parameters and a code block after a semicolon
93///
94/// Inside the code block, each type parameter is aliased to the concrete type
95/// associated with the corresponding enum variant.
96///
97/// # Examples
98///
99/// ```rust,ignore
100/// use concrete_type::Concrete;
101/// use concrete_type_rules::gen_match_concretes_macro;
102///
103/// #[derive(Concrete, Clone, Copy)]
104/// enum Exchange {
105/// #[concrete = "BinanceType"]
106/// Binance,
107/// }
108///
109/// #[derive(Concrete)]
110/// enum Strategy {
111/// #[concrete = "StrategyAType"]
112/// StrategyA,
113/// }
114///
115/// struct BinanceType;
116/// struct StrategyAType;
117///
118/// // Generate a combined matcher macro
119/// gen_match_concretes_macro!(Exchange, Strategy);
120///
121/// // Now you can use the generated macro
122/// let exchange = Exchange::Binance;
123/// let strategy = Strategy::StrategyA;
124///
125/// let result = match_exchange_strategy!(exchange, strategy; E, S => {
126/// // Here E is BinanceType and S is StrategyAType
127/// format!("{}", std::any::type_name::<(E, S)>())
128/// });
129/// ```
130#[macro_export]
131macro_rules! gen_match_concretes_macro {
132 // For 2 enum types
133 ($first_enum:ident, $second_enum:ident) => {
134 paste::paste! {
135 #[macro_export]
136 macro_rules! [<match_ $first_enum:snake _ $second_enum:snake>] {
137 ($first_var:expr, $second_var:expr; $first_type:ident, $second_type:ident => $code_block:block) => {
138 [<$first_enum:snake>]!($first_var; $first_type => {
139 [<$second_enum:snake>]!($second_var; $second_type => {
140 $code_block
141 })
142 })
143 };
144 }
145 }
146 };
147
148 // For 3 enum types
149 ($first_enum:ident, $second_enum:ident, $third_enum:ident) => {
150 paste::paste! {
151 #[macro_export]
152 macro_rules! [<match_ $first_enum:snake _ $second_enum:snake _ $third_enum:snake>] {
153 ($first_var:expr, $second_var:expr, $third_var:expr; $first_type:ident, $second_type:ident, $third_type:ident => $code_block:block) => {
154 [<$first_enum:snake>]!($first_var; $first_type => {
155 [<$second_enum:snake>]!($second_var; $second_type => {
156 [<$third_enum:snake>]!($third_var; $third_type => {
157 $code_block
158 })
159 })
160 })
161 };
162 }
163 }
164 };
165
166 // For 4 enum types
167 ($first_enum:ident, $second_enum:ident, $third_enum:ident, $fourth_enum:ident) => {
168 paste::paste! {
169 #[macro_export]
170 macro_rules! [<match_ $first_enum:snake _ $second_enum:snake _ $third_enum:snake _ $fourth_enum:snake>] {
171 ($first_var:expr, $second_var:expr, $third_var:expr, $fourth_var:expr;
172 $first_type:ident, $second_type:ident, $third_type:ident, $fourth_type:ident => $code_block:block) => {
173 [<$first_enum:snake>]!($first_var; $first_type => {
174 [<$second_enum:snake>]!($second_var; $second_type => {
175 [<$third_enum:snake>]!($third_var; $third_type => {
176 [<$fourth_enum:snake>]!($fourth_var; $fourth_type => {
177 $code_block
178 })
179 })
180 })
181 })
182 };
183 }
184 }
185 };
186
187 // For 5 enum types
188 ($first_enum:ident, $second_enum:ident, $third_enum:ident, $fourth_enum:ident, $fifth_enum:ident) => {
189 paste::paste! {
190 #[macro_export]
191 macro_rules! [<match_ $first_enum:snake _ $second_enum:snake _ $third_enum:snake _ $fourth_enum:snake _ $fifth_enum:snake>] {
192 ($first_var:expr, $second_var:expr, $third_var:expr, $fourth_var:expr, $fifth_var:expr;
193 $first_type:ident, $second_type:ident, $third_type:ident, $fourth_type:ident, $fifth_type:ident => $code_block:block) => {
194 [<$first_enum:snake>]!($first_var; $first_type => {
195 [<$second_enum:snake>]!($second_var; $second_type => {
196 [<$third_enum:snake>]!($third_var; $third_type => {
197 [<$fourth_enum:snake>]!($fourth_var; $fourth_type => {
198 [<$fifth_enum:snake>]!($fifth_var; $fifth_type => {
199 $code_block
200 })
201 })
202 })
203 })
204 })
205 };
206 }
207 }
208 };
209}