| Crates.io | try_from_expr |
| lib.rs | try_from_expr |
| version | 0.1.1 |
| created_at | 2025-08-17 02:23:47.273337+00 |
| updated_at | 2025-12-24 20:11:47.262674+00 |
| description | A procedural macro for generating TryFrom<&syn::Expr> implementations for enums |
| homepage | |
| repository | https://github.com/rymskip/try_from_expr |
| max_upload_size | |
| id | 1799054 |
| size | 20,573 |
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.
TryFrom<&syn::Expr> for your
enumsAdd this to your Cargo.toml:
[dependencies]
try_from_expr = "0.1.0"
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();
#[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();
The macro automatically detects "wrapper" enums that contain other enum types and generates optimized parsing:
#[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();
#[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();
#[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();
By default, the macro automatically detects whether your enum is a wrapper or leaf enum. You can override this:
#[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),
}
The macro analyzes your enum at compile time and generates a
TryFrom<&syn::Expr> implementation that:
The macro has built-in support for:
bool, char, String, all integer types, f32, f64Vec<T>, HashMap<K, V>, BTreeMap<K, V>, Option<T>OrderedFloat<T> from the ordered-float crateTryFrom<&syn::Expr>The macro provides detailed error messages:
// 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'"
This workspace contains two crates:
try_from_expr - The main library crate that users importtry_from_expr_derive - The procedural macro implementationThis project is licensed under the MIT license.
Please feel free to submit a Pull Request.