Skip to content

Commit 0eccce0

Browse files
committed
the big refactor
1 parent d527af0 commit 0eccce0

19 files changed

+2156
-1990
lines changed

CHANGELOG.md

+16-3
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,28 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
<!-- ## [Unreleased] -->
7+
## [Unreleased]
8+
### Added
9+
- Attributes can now be nested, i.e. `#[outer(inner(key = value))]`.
10+
11+
### Changed
12+
- **Breaking Change** added `span` to `IdentValue`, as this is mostly an implementation detail,
13+
most users need not worry about this change.
14+
- **Breaking Change** changed `FromAttr::from_attributes` to take `[Borrow<Attribute>]`, only relevant for type inference.
15+
- **Breaking Change** `TokenStream`, when used as field in `FromAttr` now only supports `<name>(<tokens>)` syntax, `<name>=<tokens>` was removed.
16+
17+
### Removed
18+
- **Breaking Change** mandatory flags
19+
- **Breaking Change** removed `found_field` in custom error messages
20+
821
## [0.8.1] - 2023-09-27
922
### Added
1023
- Added `FlagOrValue::{is_none, is_flag, is_value, into_value, as_value}`
1124

1225
## [0.8.0] - 2023-09-18
1326
### Changed
1427
- Renamed `Attribute` to `FromAttr` to not conflict with `syn::Attribute`.
15-
The old path is still exported (#[doc(hidden)]). Existing usages should not break.
28+
The old path is still exported (`#[doc(hidden)]` and deprecated). Existing usages should not break.
1629

1730
## [0.7.1] - 2023-09-17
1831
### Fixed
@@ -22,7 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2235
- Updated dependencies
2336

2437
### Added
25-
- Added `FlagOrValue` to support a value both as a Flag and a Value
38+
- `FlagOrValue` to support a value both as a Flag and a Value
2639

2740
### Changed
2841
- `bool` now allows specifying a flag multiple times.

Cargo.toml

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
[workspace]
2+
members = ["example"]
3+
14
[package]
25
categories = ["rust-patterns", "development-tools::procedural-macro-helpers", "parsing"]
3-
description = "Clap for proc macro attributes"
6+
description = "Clap like parsing for attributes in proc-macros"
47
documentation = "https://docs.rs/attribute-derive"
58
include = ["src/**/*", "LICENSE", "README.md"]
6-
keywords = ["derive", "macro"]
9+
keywords = ["derive", "macro", "attribute", "arguments", "syn", "proc-macro"]
710
license = "MIT OR Apache-2.0"
811
readme = "README.md"
912
repository = "https://github.com/ModProg/attribute-derive"
@@ -14,9 +17,11 @@ edition = "2021"
1417
[lib]
1518

1619
[dependencies]
20+
derive-where = "1.2.5"
21+
manyhow = "0.10.3"
1722
proc-macro2 = "1"
1823
quote = "1"
19-
syn = "2"
24+
syn = "2"
2025

2126
[features]
2227
# default = ["syn-full"]
@@ -26,8 +31,10 @@ syn-full = ["syn/full"]
2631
version = "0.8.1"
2732
path = "macro"
2833

29-
[workspace]
30-
members = ["example", "macro"]
34+
[dev-dependencies]
35+
insta = "1.34.0"
36+
quote = "1"
37+
syn = { version = "2", features = ["extra-traits"] }
3138

3239
[package.metadata.release]
3340
shared-version = true

docs/traits.html

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1em; font-size: 70%;">
2+
<style>
3+
.node {
4+
padding: .5em;
5+
border: thin solid;
6+
border-radius: 1em;
7+
}
8+
h3 {
9+
margin-top: 0 !important;
10+
font-size: 1.25em !important;
11+
}
12+
h3 code {
13+
background: none !important;
14+
}
15+
.arrow-head {
16+
width: 10px;
17+
height: 10px;
18+
border-top: thin solid;
19+
border-right: thin solid;
20+
transform: rotate(-45deg);
21+
margin-bottom: -11px;
22+
}
23+
.arrow-v {
24+
width: 0px;
25+
min-height: 10px;
26+
border-left: thin solid;
27+
}
28+
.arrow-h {
29+
height: 0px;
30+
border-bottom: thin solid;
31+
}
32+
.arrow-label {
33+
padding-inline: 5px;
34+
background: none !important;
35+
text-align: center !important;
36+
max-width: calc(100% - 1.5em);
37+
}
38+
.center-h {
39+
margin-inline: auto;
40+
}
41+
.arrow-cell {
42+
display: flex;
43+
flex-direction: column;
44+
align-content: center;
45+
align-items: center;
46+
}
47+
</style>
48+
<div class="node">
49+
<h3><a href="../trait.FromAttr.html"><code>FromAttr</code></a></h3>
50+
<p>Main entry point. Derived via macro. Anything that can be parsed from one or multiple attributes.</p>
51+
</div>
52+
<div class="node">
53+
<h3><a href="trait.AttributeNamed.html"><code>AttributeNamed</code></a></h3>
54+
<p>Values that can be parsed named, e.g. <code>name(&lt;value&gt;)</code>, <code>name = &lt;value&gt;</code>, <code>name</code> (as flag).</p>
55+
<p>This is the default parsing mode used for fields in derived <a href="../trait.FromAttr.html"><code>FromAttr</code></a> implementations.</p>
56+
</div>
57+
<div class="node">
58+
<h3><a href="trait.AttributePositional.html"><code>AttributePositional</code></a></h3>
59+
<p>Values that can be parsed positionally, i.e., without a name, e.g. <code>"literal"</code>, <code>a + b</code>, <code>true</code>.</p>
60+
<p>When deriving <a href="../trait.FromAttr.html"><code>FromAttr</code></a> this is enabled via putting <code>#[attr(positional)]</code> on the field.</p>
61+
</div>
62+
<div class="arrow-cell" style="grid-column: 1; grid-row: 2;">
63+
<div class="arrow-head"></div>
64+
<div style="flex: 1" class="arrow-v"></div>
65+
<code class="arrow-label">impl &lt;T: AttributeValue&gt; FromAttr for T</code>
66+
<div style="flex: 1" class="arrow-v"></div>
67+
</div>
68+
<div class="arrow-cell" style="grid-column: 2; grid-row: 2;">
69+
<div class="arrow-head"></div>
70+
<div style="flex: 1" class="arrow-v"></div>
71+
<code class="arrow-label">impl &lt;T: AttributeValue&gt; AttributeNamed for T</code>
72+
<div style="flex: 1" class="arrow-v"></div>
73+
</div>
74+
<div class="arrow-cell" style="grid-column: 3; grid-row: 2;">
75+
<div class="arrow-head"></div>
76+
<div style="flex: 1" class="arrow-v"></div>
77+
<code class="arrow-label">impl &lt;T: AttributeValue + PositionalValue&gt; AttributePositional for T</code>
78+
<div style="flex: 1" class="arrow-v"></div>
79+
</div>
80+
<div style="grid-column: 2 / 4; grid-row: 2; position: relative;">
81+
<div class="arrow-v" style="left: calc(50% - 1.5em); bottom: 0; height: 50%; position: absolute;"> </div>
82+
<div class="arrow-h" style="left: calc(50% - 1.5em); bottom: 50%; width: 3em; position: absolute;"> </div>
83+
</div>
84+
<div class="arrow-cell">
85+
<div style="height: 4em; margin-top: -1em;" class="arrow-v"></div>
86+
<div class="arrow-h" style="margin-left: 50%; width: 50%;"></div>
87+
</div>
88+
<div class="node">
89+
<h3><a href="trait.AttributeValue.html"><code>AttributeValue</code></a></h3>
90+
Any attribute that has the concept of a value, e.g., <code>"positional"</code>, <code>meta(&lt;value&gt;)</code>, <code>key = &lt;value&gt;</code>.
91+
</div>
92+
<div class="node">
93+
<h3><a href="trait.PositionalValue.html"><code>PositionalValue</code></a></h3>
94+
Empty marker trait, defining which <code>AttributeValue</code> implement <code>AttributePositional</code>.
95+
</div>
96+
<div class="arrow-cell" style="grid-column: 2;">
97+
<div class="arrow-head"></div>
98+
<div style="flex: 1" class="arrow-v"></div>
99+
<code class="arrow-label">impl &lt;T: AttributeMeta&gt; AttributeValue for T</code>
100+
<div style="flex: 1" class="arrow-v"></div>
101+
</div>
102+
<div class="node" style="grid-column: 2;">
103+
<h3><a href="trait.AttributeMeta.html"><code>AttributeMeta</code></a></h3>
104+
<p>Values in function or meta style attributes, i.e., <code>meta(&lt;value&gt;).</code></p>
105+
</div>
106+
</div>

example/src/lib.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ struct Normal {
4646
#[attribute(example = "2.5")]
4747
example: f32,
4848
flag: bool,
49-
#[attribute(optional = false)]
50-
mandatory_flag: bool,
5149
}
5250
#[proc_macro_derive(Normal, attributes(ident, a, b, empty, single))]
5351
pub fn normal_derive(input: TokenStream) -> proc_macro::TokenStream {
@@ -62,12 +60,10 @@ pub fn normal_derive(input: TokenStream) -> proc_macro::TokenStream {
6260
#[derive(FromAttr, Debug)]
6361
#[attribute(ident = ident, aliases = [a, b])]
6462
#[attribute(error(
65-
unknown_field = "found `{found_field}` but expected one of {expected_fields:i(`{}`)(, )}",
63+
unknown_field = "expected one of {expected_fields:i(`{}`)(, )}",
6664
duplicate_field = "duplicate `{field}`",
6765
missing_field = "missing field `{field}`",
6866
field_help = "try {attribute}: {field}={example}",
69-
missing_flag = "missing flag `{flag}`",
70-
flag_help = "try {attribute}: {flag}",
7167
conflict = "{first} !!! {second}"
7268
))]
7369
struct Custom {
@@ -84,15 +80,13 @@ struct Custom {
8480
#[attribute(example = "2.5")]
8581
example: f32,
8682
flag: bool,
87-
#[attribute(optional = false)]
88-
mandatory_flag: bool,
8983
}
9084
#[derive(FromAttr)]
91-
#[attribute(ident = empty, error(unknown_field_empty = "found {found_field}, but expected none"))]
85+
#[attribute(ident = empty, error(unknown_field_empty = "expected nothing"))]
9286
struct EmptyCustom {}
9387

9488
#[derive(FromAttr)]
95-
#[attribute(ident = single, error(unknown_field_single = "found {found_field}, but expected {expected_field}"))]
89+
#[attribute(ident = single, error(unknown_field_single = "expected {expected_field}"))]
9690
struct SingleCustom {
9791
field: bool,
9892
}

example/tests/ui/custom.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@ struct Example;
1414
optional_default = 3,
1515
default = 2,
1616
conflict_a = "hello",
17-
mandatory_flag
1817
)]
1918
struct ExampleOI;
2019

2120
#[derive(Custom)]
22-
#[ident(example = 1., mandatory_flag)]
21+
#[ident(example = 1.)]
2322
#[a(conflict_a = "hey")]
2423
#[b(conflict_b = "hi")]
2524
struct Conflict;

example/tests/ui/custom.stderr

+13-23
Original file line numberDiff line numberDiff line change
@@ -8,42 +8,32 @@ error: missing field `example`
88
|
99
= note: this error originates in the derive macro `Custom` (in Nightly builds, run with -Z macro-backtrace for more info)
1010

11-
error: missing flag `mandatory_flag`
12-
13-
= help: try ident: mandatory_flag
14-
--> tests/ui/custom.rs:6:10
15-
|
16-
6 | #[derive(Custom)]
17-
| ^^^^^^
18-
|
19-
= note: this error originates in the derive macro `Custom` (in Nightly builds, run with -Z macro-backtrace for more info)
20-
2111
error: conflict_a !!! conflict_b
22-
--> tests/ui/custom.rs:23:5
12+
--> tests/ui/custom.rs:22:5
2313
|
24-
23 | #[a(conflict_a = "hey")]
14+
22 | #[a(conflict_a = "hey")]
2515
| ^^^^^^^^^^
2616

2717
error: conflict_b !!! conflict_a
28-
--> tests/ui/custom.rs:24:5
18+
--> tests/ui/custom.rs:23:5
2919
|
30-
24 | #[b(conflict_b = "hi")]
20+
23 | #[b(conflict_b = "hi")]
3121
| ^^^^^^^^^^
3222

33-
error: found `hello` but expected one of `optional_implicit`, `optional_explicit`, `optional_default`, `default`, `conflict_a`, `conflict_b`, `example`, `flag`, `mandatory_flag`
34-
--> tests/ui/custom.rs:28:9
23+
error: expected one of `optional_implicit`, `optional_explicit`, `optional_default`, `default`, `conflict_a`, `conflict_b`, `example`, `flag`
24+
--> tests/ui/custom.rs:27:9
3525
|
36-
28 | #[ident(hello)]
26+
27 | #[ident(hello)]
3727
| ^^^^^
3828

39-
error: found hello, but expected none
40-
--> tests/ui/custom.rs:30:9
29+
error: expected nothing
30+
--> tests/ui/custom.rs:29:9
4131
|
42-
30 | #[empty(hello)]
32+
29 | #[empty(hello)]
4333
| ^^^^^
4434

45-
error: found hello, but expected field
46-
--> tests/ui/custom.rs:29:10
35+
error: expected field
36+
--> tests/ui/custom.rs:28:10
4737
|
48-
29 | #[single(hello)]
38+
28 | #[single(hello)]
4939
| ^^^^^

example/tests/ui/normal.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@ struct Example;
1414
optional_default = 3,
1515
default = 2,
1616
conflict_a = "hello",
17-
mandatory_flag
1817
)]
1918
struct ExampleOI;
2019

2120
#[derive(Normal)]
22-
#[ident(example = 1., mandatory_flag)]
21+
#[ident(example = 1.)]
2322
#[a(conflict_a = "hey")]
2423
#[b(conflict_b = "hi")]
2524
struct Conflict;

example/tests/ui/normal.stderr

+12-22
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,39 @@
11
error: required `example` is not specified
22

3-
= help: try `#[ident(example=2.5)]`
3+
= help: try `#[ident(example = 2.5)]`
44
--> tests/ui/normal.rs:3:10
55
|
66
3 | #[derive(Normal)]
77
| ^^^^^^
88
|
99
= note: this error originates in the derive macro `Normal` (in Nightly builds, run with -Z macro-backtrace for more info)
1010

11-
error: required `mandatory_flag` is not specified
12-
13-
= help: try `#[ident(mandatory_flag)]`
14-
--> tests/ui/normal.rs:6:10
15-
|
16-
6 | #[derive(Normal)]
17-
| ^^^^^^
18-
|
19-
= note: this error originates in the derive macro `Normal` (in Nightly builds, run with -Z macro-backtrace for more info)
20-
2111
error: `conflict_a` conflicts with mutually exclusive `conflict_b`
22-
--> tests/ui/normal.rs:23:5
12+
--> tests/ui/normal.rs:22:5
2313
|
24-
23 | #[a(conflict_a = "hey")]
14+
22 | #[a(conflict_a = "hey")]
2515
| ^^^^^^^^^^
2616

2717
error: `conflict_b` conflicts with mutually exclusive `conflict_a`
28-
--> tests/ui/normal.rs:24:5
18+
--> tests/ui/normal.rs:23:5
2919
|
30-
24 | #[b(conflict_b = "hi")]
20+
23 | #[b(conflict_b = "hi")]
3121
| ^^^^^^^^^^
3222

33-
error: supported fields are `optional_implicit`, `optional_explicit`, `optional_default`, `default`, `conflict_a`, `conflict_b`, `example`, `flag` and `mandatory_flag`
34-
--> tests/ui/normal.rs:28:9
23+
error: supported fields are `optional_implicit`, `optional_explicit`, `optional_default`, `default`, `conflict_a`, `conflict_b`, `example` and `flag`
24+
--> tests/ui/normal.rs:27:9
3525
|
36-
28 | #[ident(hello)]
26+
27 | #[ident(hello)]
3727
| ^^^^^
3828

3929
error: expected empty attribute
40-
--> tests/ui/normal.rs:30:9
30+
--> tests/ui/normal.rs:29:9
4131
|
42-
30 | #[empty(hello)]
32+
29 | #[empty(hello)]
4333
| ^^^^^
4434

4535
error: expected supported field `field`
46-
--> tests/ui/normal.rs:29:10
36+
--> tests/ui/normal.rs:28:10
4737
|
48-
29 | #[single(hello)]
38+
28 | #[single(hello)]
4939
| ^^^^^

macro/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ proc-macro = true
1818
[dependencies]
1919
proc-macro2 = "1"
2020
quote = "1"
21-
quote-use = { version = "0.7", features = ["namespace_idents"] }
21+
quote-use = "0.8"
2222
syn = "2"
2323
proc-macro-utils = "0.8.0"
2424
# proc-macro-utils = {path = "../../proc-macro-utils"}
2525
interpolator = { version = "0.5.0", features = ["iter"] }
2626
collection_literals = "1"
27-
manyhow = "0.8"
27+
manyhow = "0.10"
2828

2929
[package.metadata.release]
3030
tag = false

0 commit comments

Comments
 (0)