# try_from_expr
A Rust procedural macro for generating `TryFrom<&syn::Expr>` implementations for
enums. This allows you to parse Rust syntax expressions into strongly-typed enum
values, making it easy to work with configuration DSLs, macro arguments, and
other syntax-based APIs.
## Features
- 🚀 **Automatic Parser Generation** - Derives `TryFrom<&syn::Expr>` for your
enums
- 📦 **Multiple Variant Types** - Supports unit, tuple, and struct variants
- 🎯 **Smart Type Detection** - Automatically detects wrapper vs leaf enums
- 🔧 **Flexible Parsing** - Works with primitives, collections, and custom
types
- 💡 **Helpful Error Messages** - Provides clear error messages for parse
failures
- âš¡ **Zero Runtime Overhead** - All parsing logic is generated at compile
time
## Installation
Add this to your `Cargo.toml`:
```toml
[dependencies]
try_from_expr = "0.1.0"
```
## Quick Start
```rust
use try_from_expr::TryFromExpr;
use syn::Expr;
#[derive(TryFromExpr)]
enum ConfigValue {
Enabled,
Threshold(u32),
Range { min: i32, max: i32 },
}
// Parse from a syn::Expr
let expr: Expr = syn::parse_str("ConfigValue::Threshold(42)").unwrap();
let config = ConfigValue::try_from(&expr).unwrap();
```
## Usage Examples
### Basic Enum with Different Variant Types
```rust
#[derive(TryFromExpr)]
enum Setting {
// Unit variant
Default,
// Tuple variant with single value
Timeout(u64),
// Tuple variant with multiple values
Coordinate(f64, f64),
// Struct variant
Config {
name: String,
value: i32,
enabled: bool,
},
}
// Parse unit variant
let expr = syn::parse_str("Setting::Default").unwrap();
let setting = Setting::try_from(&expr).unwrap();
// Parse tuple variant
let expr = syn::parse_str("Setting::Timeout(5000)").unwrap();
let setting = Setting::try_from(&expr).unwrap();
// Parse struct variant
let expr = syn::parse_str(r#"Setting::Config {
name: "test",
value: 42,
enabled: true
}"#).unwrap();
let setting = Setting::try_from(&expr).unwrap();
```
### Wrapper Enums (Composite Enums)
The macro automatically detects "wrapper" enums that contain other enum types
and generates optimized parsing:
```rust
#[derive(TryFromExpr)]
enum StringConstraint {
MinLength(usize),
MaxLength(usize),
Pattern(String),
}
#[derive(TryFromExpr)]
enum NumberConstraint {
Min(i64),
Max(i64),
Range(i64, i64),
}
#[derive(TryFromExpr)]
enum Constraint {
String(StringConstraint),
Number(NumberConstraint),
Required,
}
// The macro detects this is a wrapper and allows parsing nested enums
let expr = syn::parse_str("Constraint::String(StringConstraint::MinLength(10))").unwrap();
let constraint = Constraint::try_from(&expr).unwrap();
```
### Working with Collections
```rust
#[derive(TryFromExpr)]
enum DataType {
Single(String),
Multiple(Vec<String>),
Mapping(HashMap<String, i32>),
}
// Parse Vec
let expr = syn::parse_str(r#"DataType::Multiple(vec!["a", "b", "c"])"#).unwrap();
let data = DataType::try_from(&expr).unwrap();
// Parse HashMap
let expr = syn::parse_str(r#"DataType::Mapping([("key", 42)])"#).unwrap();
let data = DataType::try_from(&expr).unwrap();
```
### Optional Values
```rust
#[derive(TryFromExpr)]
enum OptionalConfig {
Value(Option<String>),
}
// Explicit Some
let expr = syn::parse_str(r#"OptionalConfig::Value(Some("text"))"#).unwrap();
// Explicit None
let expr = syn::parse_str("OptionalConfig::Value(None)").unwrap();
// Implicit Some (bare value treated as Some)
let expr = syn::parse_str(r#"OptionalConfig::Value("text")"#).unwrap();
```
## Force Mode Selection
By default, the macro automatically detects whether your enum is a wrapper or
leaf enum. You can override this:
```rust
#[derive(TryFromExpr)]
#[try_from_expr(wrapper)] // Force wrapper mode
enum ForceWrapper {
Variant1(CustomType),
Variant2(AnotherType),
}
#[derive(TryFromExpr)]
#[try_from_expr(leaf)] // Force leaf mode
enum ForceLeaf {
Simple,
Complex(String),
}
```
## How It Works
The macro analyzes your enum at compile time and generates a
`TryFrom<&syn::Expr>` implementation that:
1. **Unwraps** any parentheses or group expressions
2. **Matches** the expression type (path, call, struct, literal)
3. **Parses** the variant name and validates it belongs to your enum
4. **Extracts** and parses any parameters or fields
5. **Constructs** the appropriate enum variant
6. **Returns** helpful error messages for any parsing failures
## Supported Types
The macro has built-in support for:
- **Primitives**: `bool`, `char`, `String`, all integer types, `f32`, `f64`
- **Collections**: `Vec<T>`, `HashMap<K, V>`, `BTreeMap<K, V>`, `Option<T>`
- **Special**: `OrderedFloat<T>` from the `ordered-float` crate
- **Custom Types**: Any type that implements `TryFrom<&syn::Expr>`
## Error Handling
The macro provides detailed error messages:
```rust
// Unknown variant
"Unknown variant 'Invalid' for enum 'Setting'. Valid unit variants: Default"
// Wrong number of arguments
"Variant 'Coordinate' expects exactly 2 arguments, but 3 were provided"
// Type parsing failure
"Failed to parse argument 1: expected u32, got string literal"
// Missing required field
"Missing required field 'name' for variant 'Config'"
```
## Project Structure
This workspace contains two crates:
- `try_from_expr` - The main library crate that users import
- `try_from_expr_derive` - The procedural macro implementation
## License
This project is licensed under the MIT license.
## Contributing
Please feel free to submit a Pull Request.