{"id":20410909,"url":"https://github.com/mintlu8/macroex","last_synced_at":"2026-04-17T22:01:46.364Z","repository":{"id":202834467,"uuid":"708124229","full_name":"mintlu8/macroex","owner":"mintlu8","description":"An extractor based low level macro parsing crate that provides high level parsing support through derive macros.","archived":false,"fork":false,"pushed_at":"2023-11-27T02:29:37.000Z","size":61,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-25T07:35:47.795Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mintlu8.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-21T15:44:08.000Z","updated_at":"2023-10-22T00:28:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"74d618a4-97aa-4d6e-803d-2c99875b8a31","html_url":"https://github.com/mintlu8/macroex","commit_stats":null,"previous_names":["mintlu8/macroex"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mintlu8/macroex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mintlu8%2Fmacroex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mintlu8%2Fmacroex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mintlu8%2Fmacroex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mintlu8%2Fmacroex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mintlu8","download_url":"https://codeload.github.com/mintlu8/macroex/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mintlu8%2Fmacroex/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31947760,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-17T17:29:20.459Z","status":"ssl_error","status_checked_at":"2026-04-17T17:28:47.801Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T05:49:01.456Z","updated_at":"2026-04-17T22:01:46.303Z","avatar_url":"https://github.com/mintlu8.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# macroex\n\n[![Crates.io](https://img.shields.io/crates/v/macroex.svg)](https://crates.io/crates/macroex)\n[![Docs](https://docs.rs/macroex/badge.svg)](https://docs.rs/macroex/latest/macroex/)\n\nAn extractor based low level macro parsing crate\nthat provides high level parsing support through derive macros.\n\n## `FromMacro` and `Extractor`\n\n`FromMacro` is the bread and butter of this crate.\n`FromMacro` provides a `from_one` and a `from_many` function\nthat parses a `TokenTree` and a `TokenStream` respectively.\n\nWe can mostly assume `from_many` will contain two or more `TokenTrees`. If not\nthat is considered a bug in an extractor.\n\nAll implementors of `FromMacro` are `Extractors` of one `TokenTree`. When used on a\n`TokenStream` iterator directly, they will consume a single `TokenTree`\nand try to parse it using `from_one`.\n\n```rust\nlet mut iter = quote!{45, Hello; true false}.into_iter();\nlet a: i32 = iter.extract()?;\nlet b: Punct = iter.extract()?;\n// Extracts a string value from an ident\nlet IdentString(c) = iter.extract()?;\n// Validates a semicolon\nlet d: PunctOf\u003c';'\u003e = iter.extract()?;\nlet e: bool = iter.extract()?;\n// Validates a false literal\nlet f: LitFalse = iter.extract()?;\n```\n\nThis is pretty great! As most things can be represented as a single `TokenTree`.\n\n```rust\n// This is a single TokenTree::Group\n{\n    name: \"Tom\".\n    age: 45,\n    children: [\n        \"Tim\", \"Tam\"\n    ],\n}\n```\n\nHowever there are other things one `TokenTree` cannot account for.\n\n```rust\n// This fails because -45 is two tokens\nlet a: i32 = quote!{-45}.into_iter().extract().unwrap();\n```\n\nWrapping `FromMacro` implementers in other `Extractors`\nallow `FromMacro` implementors to parse additional `TokenTrees` and\npotentially utilize the `from_many` method\nif more than one `TokenTree` is matched.\n\n```rust\n// Note -45 is two tokens\nlet mut iter = quote!{-45}.into_iter();\n// All extracts everything from a stream\nlet All(a) = iter.extract()?;\nassert_eq!(a, -45i32);\n\nlet mut iter = quote!{-45, 21, 9.5,}.into_iter();\n// CommaExtractor extracts until a comma or end of stream is found.\nlet CommaExtractor(a) = iter.extract()?;\nlet CommaExtractor(b) = iter.extract()?;\nlet CommaExtractor(c) = iter.extract()?;\n// EndOfStream is a unit struct extractor and this asserts iter is empty\nlet EndOfStream = iter.extract()?;\nassert_eq!(a, -45);\nassert_eq!(b, 21);\nassert_eq!(c, 9.5);\n```\n\n## Derive\n\nWe provide derive macro `FromMacro`\nand `FromAttrs` that functions similarly to\nto `serde::Deserialize`. This enables ergonomic\nparsing for structs and enums following a specific data format.\n\n`FromMacro` parses syntax similar to native rust,\nwhile `FromAttrs` parses syntax commonly used in macro attributes.\n\n### Why not `serde_tokenstream`?\n\nSince we do not use the `serde` data model. Our data model is much more powerful in the macro context.\nWe are allowed to extract all `FromMacro` implementors,\nincluding `TokenStream`, `Ident`, `Group`, etc.\n\n## FromMacro\n\n`FromMacro` parses syntax similar to native rust.\n\n| Type | `from_one` | `from_many` |\n| --- | --- | --- |\n| Unit Struct | `StructName` | -- |\n| Tuple Struct | `(tuple, ..)` | `StructName (tuple, ..)` |\n| Named Struct | `{field: value, ..}` | `StructName {field: value, ..}` |\n| Unit Enum Variant | `VariantName` | -- |\n| Tuple Enum Variant | -- | `VariantName (tuple, ..)` |\n| Named Enum Variant | -- | `VariantName {field: value, ..}` |\n\n### Examples\n\n| Type | Rust Type | `from_one` | `from_many` |\n| --- | --- | --- | --- |\n| Unit Struct | `struct Red;` | `Red` | -- |\n| Tuple Struct | `struct Vec2 (i32, i32)` | `(4, 5)` | `Vec2 (4, 5)` |\n| Named Struct | `struct Vec2 {x: i32, y: i32}` | `{x: 4, y: 5}` | `Vec2 {x: 4, y: 5}` |\n| Unit Variant | `enum Color {Black, White}` | `Black` | -- |\n| Tuple Variant | `enum Animals {Dog(String), Sheep(usize)}` | -- | `Dog (\"Rex\")` |\n| Named Variant | `enum Shapes {Square {x: f32}, Rect {x: f32, y: f32}}` | -- | `Rect {x: 4, y: 5}` |\n\n#### Use Case\n\nSince we are likely to be parsing configurations in macros,\nwe supply a `Default::default()` value if a field is not found.\n\nYou are required to opt **out** of this with `#[macroex(required)]` if\nyour type does not implement `Default`.\n\n```rust\n#[derive(FromMacro)]\npub struct Person {\n    pub name: String,\n    pub age: i32,\n    pub height: f32,\n    // This works as long as Gender implements `FromMacro` and `Default`\n    pub gender: Gender,\n    // Using Option is idiomatic to handle the default case.\n    pub hair_color: Option\u003cNumberList\u003c[f32;4]\u003e\u003e,\n    // We can extract macro based things\n    pub do_something: Option\u003cTokenStream\u003e,\n}\n```\n\nExample macro input:\n\n```rust\nperson! {\n    name: \"Lina\",\n    age: 23,\n    gender: Female,\n    hair_color: [0.7, 0.4, 0],\n    do_something: {\n        let w = \"world\";\n        println!(\"Hello, {}!\", w)\n    },\n}\n```\n\n#### Attributes\n\nThe `FromMacro` macro supports the following attributes:\n\n```rust\n#[derive(FromMacro)]\n// We use the same casing names as serde.\n#[macroex(rename_all=\"SCREAMING-KEBAB-CASE\")]\npub struct Animal {\n    // Errors if not specified.\n    #[macroex(required)]\n    pub name: String,\n    // Evaluate an expression instead of `Default::default()`\n    #[macroex(default=\"0.0\")]\n    pub height: f32,\n    #[macroex(default=r#\"\"dog\".to_owned()\"#)]\n    pub species: String,\n    // Take strings as inputs, and collects them into a vec.\n    #[macroex(repeat)]\n    // and rename \"nicknames\" to \"nickname\" during parsing.\n    #[macroex(rename=\"nickname\")]\n    pub nicknames: Vec\u003cString\u003e,\n}\n```\n\n## FromAttrs\n\n`FromAttrs`\nGenerates a simple `FromMacro` implementation for syntax commonly associated with macro attributes.\n\nThis macro is only allowed on named structs and supports 3 basic syntax:\n\n* `.., name, ..` parses to `name: true`, which matches a boolean value.\n* `.., name = expr, ..` parses to `name: expr`\n* `.., name(..), ..` parses to `name: T{ .. }`\n\nOther types like fieldless enums can potentially use `FromMacro`\nto generated compatible `FromMacro` implementations to use with this macro.\n\n### Example\n\nWe use the same set of attributes as `FromMacro`\n\n```rust\n#[derive(FromAttrs)]\n#[macroex(rename_all=\"snake_case\")]\npub struct Animal {\n    #[macroex(required)]\n    pub name: String,\n    #[macroex(default=\"0.0\")]\n    pub height: f32,\n    #[macroex(default=r#\"Ident::new(\"Dog\", Span::call_site())\"#)]\n    pub species: Ident,\n    #[macroex(repeat, rename=\"mascot\")]\n    pub mascot_infos: Vec\u003cMascotInfo\u003e,\n}\n```\n\nExample attribute:\n\n```rust\n#[animal(name = \"Ferris\", species = Crab, mascot(language = \"Rust\"))]\n```\n\nWe can parse either\n\n```rust\n(name = \"Ferris\", species = Crab, mascot(language = \"Rust\"))\n```\n\nwith `from_one`, or\n\n```rust\nname = \"Ferris\", species = Crab, mascot(language = \"Rust\")\n```\n\nwith `from_many`, commonly extracted with `syn`.\n\n## Macro Chaining and Hygeine\n\nWe treat our input as string-like and we will try\nto flatten all `None` delimited groups encountered during parsing.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmintlu8%2Fmacroex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmintlu8%2Fmacroex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmintlu8%2Fmacroex/lists"}