mirror of
https://github.com/awfixers-stuff/src.git
synced 2026-03-27 12:56:19 +00:00
create src
This commit is contained in:
187
src-macros/CHANGELOG.md
Normal file
187
src-macros/CHANGELOG.md
Normal file
@@ -0,0 +1,187 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.1.5 (2024-05-22)
|
||||
|
||||
A maintenance release without user-facing changes.
|
||||
|
||||
### Commit Statistics
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
- 3 commits contributed to the release over the course of 8 calendar days.
|
||||
- 68 days passed between releases.
|
||||
- 0 commits were understood as [conventional](https://www.conventionalcommits.org).
|
||||
- 0 issues like '(#ID)' were seen in commit messages
|
||||
|
||||
### Commit Details
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
<details><summary>view details</summary>
|
||||
|
||||
* **Uncategorized**
|
||||
- Adjust changelogs prior to release ([`9511416`](https://github.com/Byron/gitoxide/commit/9511416a6cd0c571233f958c165329c8705c2498))
|
||||
- Merge branch 'status' ([`04ef31e`](https://github.com/Byron/gitoxide/commit/04ef31e9d6f5332d49037a5a4c248ebbb5aaf92b))
|
||||
- Adapt to changes in `src-pack` ([`bad5b48`](https://github.com/Byron/gitoxide/commit/bad5b48e4f0d865b0b0937f136d9a0041aa88046))
|
||||
</details>
|
||||
|
||||
## 0.1.4 (2024-03-14)
|
||||
|
||||
A maintenance release without user-facing changes.
|
||||
|
||||
### Commit Statistics
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
- 4 commits contributed to the release over the course of 4 calendar days.
|
||||
- 75 days passed between releases.
|
||||
- 0 commits were understood as [conventional](https://www.conventionalcommits.org).
|
||||
- 0 issues like '(#ID)' were seen in commit messages
|
||||
|
||||
### Commit Details
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
<details><summary>view details</summary>
|
||||
|
||||
* **Uncategorized**
|
||||
- Release src-date v0.8.5, src-hash v0.14.2, src-trace v0.1.8, src-utils v0.1.11, src-features v0.38.1, src-actor v0.31.0, src-validate v0.8.4, src-object v0.42.0, src-path v0.10.7, src-glob v0.16.2, src-quote v0.4.12, src-attributes v0.22.2, src-command v0.3.6, src-filter v0.11.0, src-fs v0.10.1, src-chunk v0.4.8, src-commitgraph v0.24.2, src-hashtable v0.5.2, src-revwalk v0.13.0, src-traverse v0.38.0, src-worktree-stream v0.11.0, src-archive v0.11.0, src-config-value v0.14.6, src-tempfile v13.1.1, src-lock v13.1.1, src-ref v0.43.0, src-sec v0.10.6, src-config v0.36.0, src-prompt v0.8.4, src-url v0.27.2, src-credentials v0.24.2, src-ignore v0.11.2, src-bitmap v0.2.11, src-index v0.31.0, src-worktree v0.32.0, src-diff v0.42.0, src-discover v0.31.0, src-pathspec v0.7.1, src-dir v0.2.0, src-macros v0.1.4, src-mailmap v0.23.0, src-negotiate v0.13.0, src-pack v0.49.0, src-odb v0.59.0, src-packetline v0.17.4, src-transport v0.41.2, src-protocol v0.44.2, src-revision v0.27.0, src-refspec v0.23.0, src-status v0.7.0, src-submodule v0.10.0, src-worktree-state v0.9.0, src v0.60.0, safety bump 26 crates ([`b050327`](https://github.com/Byron/gitoxide/commit/b050327e76f234b19be921b78b7b28e034319fdb))
|
||||
- Prepare changelogs prior to release ([`52c3bbd`](https://github.com/Byron/gitoxide/commit/52c3bbd36b9e94a0f3a78b4ada84d0c08eba27f6))
|
||||
- Merge branch 'status' ([`3e5c974`](https://github.com/Byron/gitoxide/commit/3e5c974dd62ac134711c6c2f5a5490187a6ea55e))
|
||||
- Fix lints for nightly, and clippy ([`f8ce3d0`](https://github.com/Byron/gitoxide/commit/f8ce3d0721b6a53713a9392f2451874f520bc44c))
|
||||
</details>
|
||||
|
||||
## 0.1.3 (2023-12-30)
|
||||
|
||||
<csr-id-3bd09ef120945a9669321ea856db4079a5dab930/>
|
||||
|
||||
### Chore
|
||||
|
||||
- <csr-id-3bd09ef120945a9669321ea856db4079a5dab930/> change `rust-version` manifest field back to 1.65.
|
||||
They didn't actually need to be higher to work, and changing them
|
||||
unecessarily can break downstream CI.
|
||||
|
||||
Let's keep this value as low as possible, and only increase it when
|
||||
more recent features are actually used.
|
||||
|
||||
### Commit Statistics
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
- 3 commits contributed to the release.
|
||||
- 1 commit was understood as [conventional](https://www.conventionalcommits.org).
|
||||
- 0 issues like '(#ID)' were seen in commit messages
|
||||
|
||||
### Commit Details
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
<details><summary>view details</summary>
|
||||
|
||||
* **Uncategorized**
|
||||
- Release src-date v0.8.3, src-hash v0.14.1, src-trace v0.1.6, src-features v0.37.1, src-actor v0.29.1, src-validate v0.8.3, src-object v0.40.1, src-path v0.10.3, src-glob v0.15.1, src-quote v0.4.10, src-attributes v0.21.1, src-command v0.3.2, src-packetline-blocking v0.17.2, src-utils v0.1.8, src-filter v0.8.1, src-fs v0.9.1, src-chunk v0.4.7, src-commitgraph v0.23.1, src-hashtable v0.5.1, src-revwalk v0.11.1, src-traverse v0.36.1, src-worktree-stream v0.8.1, src-archive v0.8.1, src-config-value v0.14.3, src-tempfile v12.0.1, src-lock v12.0.1, src-ref v0.40.1, src-sec v0.10.3, src-config v0.33.1, src-prompt v0.8.2, src-url v0.26.1, src-credentials v0.23.1, src-ignore v0.10.1, src-bitmap v0.2.10, src-index v0.28.1, src-worktree v0.29.1, src-diff v0.39.1, src-discover v0.28.1, src-macros v0.1.3, src-mailmap v0.21.1, src-negotiate v0.11.1, src-pack v0.46.1, src-odb v0.56.1, src-pathspec v0.5.1, src-packetline v0.17.2, src-transport v0.40.1, src-protocol v0.43.1, src-revision v0.25.1, src-refspec v0.21.1, src-status v0.4.1, src-submodule v0.7.1, src-worktree-state v0.6.1, src v0.57.1 ([`972241f`](https://github.com/Byron/gitoxide/commit/972241f1904944e8b6e84c6aa1649a49be7a85c3))
|
||||
- Merge branch 'msrv' ([`8c492d7`](https://github.com/Byron/gitoxide/commit/8c492d7b7e6e5d520b1e3ffeb489eeb88266aa75))
|
||||
- Change `rust-version` manifest field back to 1.65. ([`3bd09ef`](https://github.com/Byron/gitoxide/commit/3bd09ef120945a9669321ea856db4079a5dab930))
|
||||
</details>
|
||||
|
||||
## 0.1.2 (2023-12-29)
|
||||
|
||||
<csr-id-aea89c3ad52f1a800abb620e9a4701bdf904ff7d/>
|
||||
|
||||
### Chore
|
||||
|
||||
- <csr-id-aea89c3ad52f1a800abb620e9a4701bdf904ff7d/> upgrade MSRV to v1.70
|
||||
Our MSRV follows the one of `helix`, which in turn follows Firefox.
|
||||
|
||||
### Commit Statistics
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
- 5 commits contributed to the release over the course of 14 calendar days.
|
||||
- 22 days passed between releases.
|
||||
- 1 commit was understood as [conventional](https://www.conventionalcommits.org).
|
||||
- 0 issues like '(#ID)' were seen in commit messages
|
||||
|
||||
### Commit Details
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
<details><summary>view details</summary>
|
||||
|
||||
* **Uncategorized**
|
||||
- Release src-date v0.8.2, src-hash v0.14.0, src-trace v0.1.5, src-features v0.37.0, src-actor v0.29.0, src-validate v0.8.2, src-object v0.40.0, src-path v0.10.2, src-glob v0.15.0, src-quote v0.4.9, src-attributes v0.21.0, src-command v0.3.1, src-packetline-blocking v0.17.1, src-utils v0.1.7, src-filter v0.8.0, src-fs v0.9.0, src-chunk v0.4.6, src-commitgraph v0.23.0, src-hashtable v0.5.0, src-revwalk v0.11.0, src-traverse v0.36.0, src-worktree-stream v0.8.0, src-archive v0.8.0, src-config-value v0.14.2, src-tempfile v12.0.0, src-lock v12.0.0, src-ref v0.40.0, src-sec v0.10.2, src-config v0.33.0, src-prompt v0.8.1, src-url v0.26.0, src-credentials v0.23.0, src-ignore v0.10.0, src-bitmap v0.2.9, src-index v0.28.0, src-worktree v0.29.0, src-diff v0.39.0, src-discover v0.28.0, src-macros v0.1.2, src-mailmap v0.21.0, src-negotiate v0.11.0, src-pack v0.46.0, src-odb v0.56.0, src-pathspec v0.5.0, src-packetline v0.17.1, src-transport v0.40.0, src-protocol v0.43.0, src-revision v0.25.0, src-refspec v0.21.0, src-status v0.4.0, src-submodule v0.7.0, src-worktree-state v0.6.0, src v0.57.0, src-fsck v0.2.0, gitoxide-core v0.35.0, gitoxide v0.33.0, safety bump 40 crates ([`e1aae19`](https://github.com/Byron/gitoxide/commit/e1aae191d7421c748913c92e2c5883274331dd20))
|
||||
- Prepare changelogs of next release ([`e78a92b`](https://github.com/Byron/gitoxide/commit/e78a92bfeda168b2f35bb7ba9a94175cdece12f2))
|
||||
- Merge branch 'maintenance' ([`4454c9d`](https://github.com/Byron/gitoxide/commit/4454c9d66c32a1de75a66639016c73edbda3bd34))
|
||||
- Upgrade MSRV to v1.70 ([`aea89c3`](https://github.com/Byron/gitoxide/commit/aea89c3ad52f1a800abb620e9a4701bdf904ff7d))
|
||||
- Merge branch 'main' into fix-1183 ([`1691ba6`](https://github.com/Byron/gitoxide/commit/1691ba669537f4a39ebb0891747dc509a6aedbef))
|
||||
</details>
|
||||
|
||||
## 0.1.1 (2023-12-06)
|
||||
|
||||
A maintenance release without user-facing changes.
|
||||
|
||||
### Commit Statistics
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
- 6 commits contributed to the release over the course of 46 calendar days.
|
||||
- 88 days passed between releases.
|
||||
- 0 commits were understood as [conventional](https://www.conventionalcommits.org).
|
||||
- 0 issues like '(#ID)' were seen in commit messages
|
||||
|
||||
### Commit Details
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
<details><summary>view details</summary>
|
||||
|
||||
* **Uncategorized**
|
||||
- Release src-worktree v0.28.0, src-diff v0.38.0, src-discover v0.27.0, src-macros v0.1.1, src-mailmap v0.20.1, src-negotiate v0.10.0, src-pack v0.45.0, src-odb v0.55.0, src-pathspec v0.4.1, src-packetline v0.17.0, src-transport v0.39.0, src-protocol v0.42.0, src-revision v0.24.0, src-refspec v0.20.0, src-status v0.3.0, src-submodule v0.6.0, src-worktree-state v0.5.0, src v0.56.0, src-fsck v0.1.0, gitoxide-core v0.34.0, gitoxide v0.32.0 ([`d3fd11e`](https://github.com/Byron/gitoxide/commit/d3fd11ec3783843d4e49081e1d14359ed9714b5f))
|
||||
- Release src-date v0.8.1, src-hash v0.13.2, src-trace v0.1.4, src-features v0.36.1, src-actor v0.28.1, src-validate v0.8.1, src-object v0.39.0, src-path v0.10.1, src-glob v0.14.1, src-quote v0.4.8, src-attributes v0.20.1, src-command v0.3.0, src-packetline-blocking v0.17.0, src-utils v0.1.6, src-filter v0.7.0, src-fs v0.8.1, src-chunk v0.4.5, src-commitgraph v0.22.1, src-hashtable v0.4.1, src-revwalk v0.10.0, src-traverse v0.35.0, src-worktree-stream v0.7.0, src-archive v0.7.0, src-config-value v0.14.1, src-tempfile v11.0.1, src-lock v11.0.1, src-ref v0.39.0, src-sec v0.10.1, src-config v0.32.0, src-prompt v0.8.0, src-url v0.25.2, src-credentials v0.22.0, src-ignore v0.9.1, src-bitmap v0.2.8, src-index v0.27.0, src-worktree v0.28.0, src-diff v0.38.0, src-discover v0.27.0, src-macros v0.1.1, src-mailmap v0.20.1, src-negotiate v0.10.0, src-pack v0.45.0, src-odb v0.55.0, src-pathspec v0.4.1, src-packetline v0.17.0, src-transport v0.39.0, src-protocol v0.42.0, src-revision v0.24.0, src-refspec v0.20.0, src-status v0.3.0, src-submodule v0.6.0, src-worktree-state v0.5.0, src v0.56.0, src-fsck v0.1.0, gitoxide-core v0.34.0, gitoxide v0.32.0, safety bump 27 crates ([`55d386a`](https://github.com/Byron/gitoxide/commit/55d386a2448aba1dd22c73fb63b3fd5b3a8401c9))
|
||||
- Prepare changelogs prior to release ([`d3dcbe5`](https://github.com/Byron/gitoxide/commit/d3dcbe5c4e3a004360d02fbfb74a8fad52f19b5e))
|
||||
- J fmt ([`51c7abc`](https://github.com/Byron/gitoxide/commit/51c7abc65f368b1b2bd3d82473793d3cd4fcbad5))
|
||||
- Merge branch 'size-optimization' ([`c0e72fb`](https://github.com/Byron/gitoxide/commit/c0e72fbadc0a494f47a110aebb46462d7b9f5664))
|
||||
- Remove CHANGELOG.md from all packages ([`b65a80b`](https://github.com/Byron/gitoxide/commit/b65a80b05c9372e752e7e67fcc5c073f71da164a))
|
||||
</details>
|
||||
|
||||
## 0.1.0 (2023-09-08)
|
||||
|
||||
The initial release with support for the `momo` proc-macro.
|
||||
|
||||
### Commit Statistics
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
- 15 commits contributed to the release over the course of 13 calendar days.
|
||||
- 0 commits were understood as [conventional](https://www.conventionalcommits.org).
|
||||
- 0 issues like '(#ID)' were seen in commit messages
|
||||
|
||||
### Commit Details
|
||||
|
||||
<csr-read-only-do-not-edit/>
|
||||
|
||||
<details><summary>view details</summary>
|
||||
|
||||
* **Uncategorized**
|
||||
- Release src-date v0.8.0, src-hash v0.13.0, src-features v0.34.0, src-actor v0.26.0, src-object v0.36.0, src-path v0.10.0, src-glob v0.12.0, src-attributes v0.18.0, src-packetline-blocking v0.16.6, src-filter v0.4.0, src-fs v0.6.0, src-commitgraph v0.20.0, src-hashtable v0.4.0, src-revwalk v0.7.0, src-traverse v0.32.0, src-worktree-stream v0.4.0, src-archive v0.4.0, src-config-value v0.14.0, src-tempfile v9.0.0, src-lock v9.0.0, src-ref v0.36.0, src-sec v0.10.0, src-config v0.29.0, src-prompt v0.7.0, src-url v0.23.0, src-credentials v0.19.0, src-diff v0.35.0, src-discover v0.24.0, src-ignore v0.7.0, src-index v0.24.0, src-macros v0.1.0, src-mailmap v0.18.0, src-negotiate v0.7.0, src-pack v0.42.0, src-odb v0.52.0, src-pathspec v0.2.0, src-packetline v0.16.6, src-transport v0.36.0, src-protocol v0.39.0, src-revision v0.21.0, src-refspec v0.17.0, src-submodule v0.3.0, src-worktree v0.25.0, src-worktree-state v0.2.0, src v0.53.0, safety bump 39 crates ([`8bd0456`](https://github.com/Byron/gitoxide/commit/8bd045676bb2cdc02624ab93e73ff8518064ca38))
|
||||
- Prepare changelogs for release ([`375db06`](https://github.com/Byron/gitoxide/commit/375db06a8442378c3f7a922fae38e2a6694d9d04))
|
||||
- Merge branch 'feat/src-momo' ([`a1ed6a1`](https://github.com/Byron/gitoxide/commit/a1ed6a1aacae02a167b7ec44e1a47411a2194ff7))
|
||||
- Consolidate compile tests ([`d76efdd`](https://github.com/Byron/gitoxide/commit/d76efddf5afb73563ce7e837cf975cedd01e979c))
|
||||
- Revert to use `item_fn.span()` ([`72545e9`](https://github.com/Byron/gitoxide/commit/72545e971c894de511a723f6d5515f637a84f28f))
|
||||
- Fix ui test `error_if_ineffective` ([`9be2622`](https://github.com/Byron/gitoxide/commit/9be26220876498df4d1add77da45c415268a77dc))
|
||||
- Add test-suite for failure modes ([`c8e7324`](https://github.com/Byron/gitoxide/commit/c8e732430f3740348ccedd0dc1a9a28b06a0adee))
|
||||
- Remove `TODO` in `src-macros/src/lib.rs` ([`c4ed7c1`](https://github.com/Byron/gitoxide/commit/c4ed7c180e3ec1ff75cb10d78d4b8eed3b75be2f))
|
||||
- Improve docs ([`705f2f3`](https://github.com/Byron/gitoxide/commit/705f2f34f1fa95d767646b154f41d2a6ce65ad10))
|
||||
- Refactor ([`48a2088`](https://github.com/Byron/gitoxide/commit/48a20888d158b94811074a09a8c57ff5c8410769))
|
||||
- Feat `momo`: Rm unnecessary `#[allow(unused_mut)]` on generated inner fn ([`b619456`](https://github.com/Byron/gitoxide/commit/b6194568e1d3042305f472103e1c00549cc4ccb9))
|
||||
- Feat `momo`: Support parsing pattern in params ([`b5f78be`](https://github.com/Byron/gitoxide/commit/b5f78be06792153cd981c316a486974c000f1fd8))
|
||||
- Dramatically simplify `gix_macros::momo` ([`c72eaa0`](https://github.com/Byron/gitoxide/commit/c72eaa05697a3e34adaa3ee90584dce4b5c00120))
|
||||
- Remove `TryInto` support from `gix_macros::momo` ([`95a1626`](https://github.com/Byron/gitoxide/commit/95a16264b0a6f8c7d8e2acded3a4c9c170c2729b))
|
||||
- Add new crate `src-macros` ([`6dae9e9`](https://github.com/Byron/gitoxide/commit/6dae9e9d455ba5e3bf18c452789d07ff6cfaf392))
|
||||
</details>
|
||||
|
||||
27
src-macros/Cargo.toml
Normal file
27
src-macros/Cargo.toml
Normal file
@@ -0,0 +1,27 @@
|
||||
lints.workspace = true
|
||||
|
||||
[package]
|
||||
name = "src-macros"
|
||||
version = "0.1.5"
|
||||
edition = "2021"
|
||||
description = "Proc-macro utilities for src"
|
||||
authors = [
|
||||
"Jiahao XU <Jiahao_XU@outlook.com>",
|
||||
"Andre Bogus <bogusandre@gmail.com>",
|
||||
"Sebastian Thiel <sebastian.thiel@icloud.com>",
|
||||
]
|
||||
repository = "https://github.com/GitoxideLabs/gitoxide"
|
||||
license = "MIT OR Apache-2.0"
|
||||
include = ["src/**/*", "LICENSE-*"]
|
||||
rust-version = "1.82"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "2.0", features = ["full", "fold"] }
|
||||
quote = "1.0"
|
||||
proc-macro2 = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
trybuild = "1.0"
|
||||
1
src-macros/LICENSE-APACHE
Symbolic link
1
src-macros/LICENSE-APACHE
Symbolic link
@@ -0,0 +1 @@
|
||||
../LICENSE-APACHE
|
||||
1
src-macros/LICENSE-MIT
Symbolic link
1
src-macros/LICENSE-MIT
Symbolic link
@@ -0,0 +1 @@
|
||||
../LICENSE-MIT
|
||||
25
src-macros/src/lib.rs
Normal file
25
src-macros/src/lib.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
//! A crate of useful macros used in `src` primarily.
|
||||
//!
|
||||
//! Note that within `src-*` crates, monomorphization should never be used for convenience, but only for performance
|
||||
//! reasons. And in the latter case, manual denomophization should be considered if the trait in questions isn't called
|
||||
//! often enough or measurements indicate that `&dyn Trait` is increasing the runtime. Thus, `src-*` crates should probably
|
||||
//! by default prefer using `&dyn` unless measurements indicate otherwise.
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
/// When applied to functions or methods, it will turn it into a wrapper that will immediately call
|
||||
/// a de-monomorphized implementation (i.e. one that uses `&dyn Trait`).
|
||||
///
|
||||
/// That way, the landing-pads for convenience will be as small as possible which then delegate to a single
|
||||
/// function or method for implementation.
|
||||
///
|
||||
/// The parameters using the following traits can be de-monomorphized:
|
||||
///
|
||||
/// * `Into`
|
||||
/// * `AsRef`
|
||||
/// * `AsMut`
|
||||
#[proc_macro_attribute]
|
||||
pub fn momo(_attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
momo::inner(input.into()).into()
|
||||
}
|
||||
|
||||
mod momo;
|
||||
300
src-macros/src/momo.rs
Normal file
300
src-macros/src/momo.rs
Normal file
@@ -0,0 +1,300 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use quote::quote;
|
||||
use syn::{punctuated::Punctuated, spanned::Spanned, *};
|
||||
|
||||
pub(crate) fn inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
|
||||
let fn_item: Item = match syn::parse2(code.clone()) {
|
||||
Ok(input) => input,
|
||||
Err(err) => return err.to_compile_error(),
|
||||
};
|
||||
|
||||
if let Item::Fn(item_fn) = fn_item {
|
||||
let ty_conversions = parse_generics(&item_fn.sig);
|
||||
let (has_conversion_in_effect, argtypes, argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions);
|
||||
if !has_conversion_in_effect {
|
||||
return Error::new(
|
||||
item_fn.span(),
|
||||
"Couldn't apply a single conversion - momo is ineffective here",
|
||||
)
|
||||
.to_compile_error();
|
||||
}
|
||||
|
||||
let uses_self = has_self
|
||||
|| item_fn.sig.inputs.iter().any(has_self_type)
|
||||
|| matches!(&item_fn.sig.output, ReturnType::Type(_, ty) if contains_self_type(ty));
|
||||
|
||||
let inner_ident = Ident::new(
|
||||
// Use long qualifier to avoid name collision.
|
||||
&format!("_{}_inner_generated_by_gix_macro_momo", item_fn.sig.ident),
|
||||
proc_macro2::Span::call_site(),
|
||||
);
|
||||
|
||||
let outer_sig = Signature {
|
||||
inputs: argtypes,
|
||||
..item_fn.sig.clone()
|
||||
};
|
||||
|
||||
let new_inner_item = Item::Fn(ItemFn {
|
||||
// Remove doc comment since they will increase compile-time and
|
||||
// also generates duplicate warning/error messages for the doc,
|
||||
// especially if it contains doc-tests.
|
||||
attrs: {
|
||||
let mut attrs = item_fn.attrs.clone();
|
||||
attrs.retain(|attr| {
|
||||
let segments = &attr.path().segments;
|
||||
!(segments.len() == 1 && segments[0].ident == "doc")
|
||||
});
|
||||
attrs
|
||||
},
|
||||
vis: Visibility::Inherited,
|
||||
sig: Signature {
|
||||
ident: inner_ident.clone(),
|
||||
..item_fn.sig
|
||||
},
|
||||
block: item_fn.block,
|
||||
});
|
||||
|
||||
if uses_self {
|
||||
// We can use `self` or `Self` inside function defined within
|
||||
// the impl-fn, so instead declare two separate functions.
|
||||
//
|
||||
// Since it's an impl block, it's unlikely to have name conflict,
|
||||
// though this won't work for impl-trait.
|
||||
//
|
||||
// This approach also make sure we can call the right function
|
||||
// using `Self` qualifier.
|
||||
let new_item = Item::Fn(ItemFn {
|
||||
attrs: item_fn.attrs,
|
||||
vis: item_fn.vis,
|
||||
sig: outer_sig,
|
||||
block: if has_self {
|
||||
parse_quote!({ self.#inner_ident(#argexprs) })
|
||||
} else {
|
||||
parse_quote!({ Self::#inner_ident(#argexprs) })
|
||||
},
|
||||
});
|
||||
quote!(#new_item #new_inner_item)
|
||||
} else {
|
||||
// Put the new inner function within the function block
|
||||
// to avoid duplicate function name and support associated
|
||||
// function that doesn't use `self` or `Self`.
|
||||
let new_item = Item::Fn(ItemFn {
|
||||
attrs: item_fn.attrs,
|
||||
vis: item_fn.vis,
|
||||
sig: outer_sig,
|
||||
block: parse_quote!({
|
||||
#new_inner_item
|
||||
|
||||
#inner_ident(#argexprs)
|
||||
}),
|
||||
});
|
||||
quote!(#new_item)
|
||||
}
|
||||
} else {
|
||||
Error::new(fn_item.span(), "expect a function").to_compile_error()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
// All conversions we support. Check references to this type for an idea how to add more.
|
||||
enum Conversion {
|
||||
Into,
|
||||
AsRef,
|
||||
AsMut,
|
||||
}
|
||||
|
||||
impl Conversion {
|
||||
fn conversion_expr(&self, i: &Ident) -> Expr {
|
||||
match *self {
|
||||
Conversion::Into => parse_quote!(#i.into()),
|
||||
Conversion::AsRef => parse_quote!(#i.as_ref()),
|
||||
Conversion::AsMut => parse_quote!(#i.as_mut()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_bounded_type(ty: &Type) -> Option<Ident> {
|
||||
match &ty {
|
||||
Type::Path(TypePath { qself: None, path }) if path.segments.len() == 1 => Some(path.segments[0].ident.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_bounds(bounds: &Punctuated<TypeParamBound, Token![+]>) -> Option<Conversion> {
|
||||
if bounds.len() != 1 {
|
||||
return None;
|
||||
}
|
||||
if let TypeParamBound::Trait(ref tb) = bounds.first().unwrap() {
|
||||
if let Some(seg) = tb.path.segments.iter().next_back() {
|
||||
if let PathArguments::AngleBracketed(ref gen_args) = seg.arguments {
|
||||
if let GenericArgument::Type(_) = gen_args.args.first().unwrap() {
|
||||
if seg.ident == "Into" {
|
||||
return Some(Conversion::Into);
|
||||
} else if seg.ident == "AsRef" {
|
||||
return Some(Conversion::AsRef);
|
||||
} else if seg.ident == "AsMut" {
|
||||
return Some(Conversion::AsMut);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// create a map from generic type to Conversion
|
||||
fn parse_generics(decl: &Signature) -> HashMap<Ident, Conversion> {
|
||||
let mut ty_conversions = HashMap::new();
|
||||
for gp in decl.generics.params.iter() {
|
||||
if let GenericParam::Type(ref tp) = gp {
|
||||
if let Some(conversion) = parse_bounds(&tp.bounds) {
|
||||
ty_conversions.insert(tp.ident.clone(), conversion);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(ref wc) = decl.generics.where_clause {
|
||||
for wp in wc.predicates.iter() {
|
||||
if let WherePredicate::Type(ref pt) = wp {
|
||||
if let Some(ident) = parse_bounded_type(&pt.bounded_ty) {
|
||||
if let Some(conversion) = parse_bounds(&pt.bounds) {
|
||||
ty_conversions.insert(ident, conversion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ty_conversions
|
||||
}
|
||||
|
||||
fn convert(
|
||||
inputs: &Punctuated<FnArg, Token![,]>,
|
||||
ty_conversions: &HashMap<Ident, Conversion>,
|
||||
) -> (bool, Punctuated<FnArg, Token![,]>, Punctuated<Expr, Token![,]>, bool) {
|
||||
let mut has_conversion_in_effect = false;
|
||||
let mut argtypes = Punctuated::new();
|
||||
let mut argexprs = Punctuated::new();
|
||||
let mut has_self = false;
|
||||
inputs.iter().enumerate().for_each(|(i, input)| match input.clone() {
|
||||
FnArg::Receiver(receiver) => {
|
||||
has_self = true;
|
||||
argtypes.push(FnArg::Receiver(receiver));
|
||||
}
|
||||
FnArg::Typed(mut pat_type) => {
|
||||
let pat_ident = match &mut *pat_type.pat {
|
||||
Pat::Ident(pat_ident) if pat_ident.by_ref.is_none() && pat_ident.subpat.is_none() => pat_ident,
|
||||
_ => {
|
||||
*pat_type.pat = Pat::Ident(PatIdent {
|
||||
ident: Ident::new(&format!("arg_{i}_gen_by_momo_"), proc_macro2::Span::call_site()),
|
||||
attrs: Default::default(),
|
||||
by_ref: None,
|
||||
mutability: None,
|
||||
subpat: None,
|
||||
});
|
||||
|
||||
if let Pat::Ident(pat_ident) = &mut *pat_type.pat {
|
||||
pat_ident
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
};
|
||||
// Outer function type argument pat does not need mut unless its
|
||||
// type is `impl AsMut`.
|
||||
pat_ident.mutability = None;
|
||||
|
||||
let ident = &pat_ident.ident;
|
||||
|
||||
let to_expr = || parse_quote!(#ident);
|
||||
|
||||
match *pat_type.ty {
|
||||
Type::ImplTrait(TypeImplTrait { ref bounds, .. }) => {
|
||||
if let Some(conv) = parse_bounds(bounds) {
|
||||
has_conversion_in_effect = true;
|
||||
argexprs.push(conv.conversion_expr(ident));
|
||||
if let Conversion::AsMut = conv {
|
||||
pat_ident.mutability = Some(Default::default());
|
||||
}
|
||||
} else {
|
||||
argexprs.push(to_expr());
|
||||
}
|
||||
}
|
||||
Type::Path(..) => {
|
||||
if let Some(conv) = parse_bounded_type(&pat_type.ty).and_then(|ident| ty_conversions.get(&ident)) {
|
||||
has_conversion_in_effect = true;
|
||||
argexprs.push(conv.conversion_expr(ident));
|
||||
if let Conversion::AsMut = conv {
|
||||
pat_ident.mutability = Some(Default::default());
|
||||
}
|
||||
} else {
|
||||
argexprs.push(to_expr());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
argexprs.push(to_expr());
|
||||
}
|
||||
}
|
||||
|
||||
// Now that mutability is decided, push the type into argtypes
|
||||
argtypes.push(FnArg::Typed(pat_type));
|
||||
}
|
||||
});
|
||||
(has_conversion_in_effect, argtypes, argexprs, has_self)
|
||||
}
|
||||
|
||||
fn contains_self_type_path(path: &Path) -> bool {
|
||||
path.segments.iter().any(|segment| {
|
||||
segment.ident == "Self"
|
||||
|| match &segment.arguments {
|
||||
PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }) => {
|
||||
args.iter().any(|generic_arg| match generic_arg {
|
||||
GenericArgument::Type(ty) => contains_self_type(ty),
|
||||
GenericArgument::Const(expr) => contains_self_type_expr(expr),
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
PathArguments::Parenthesized(ParenthesizedGenericArguments { inputs, output, .. }) => {
|
||||
inputs.iter().any(contains_self_type)
|
||||
|| matches!(output, ReturnType::Type(_, ty) if contains_self_type(ty))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn contains_self_type_expr(expr: &Expr) -> bool {
|
||||
match expr {
|
||||
Expr::Path(ExprPath { qself: Some(_), .. }) => true,
|
||||
Expr::Path(ExprPath { path, .. }) => contains_self_type_path(path),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_self_type(input: &Type) -> bool {
|
||||
match input {
|
||||
Type::Array(TypeArray { elem, len, .. }) => {
|
||||
// Call `matches!` first so that we can do tail call here
|
||||
// as an optimization.
|
||||
contains_self_type_expr(len) || contains_self_type(elem)
|
||||
}
|
||||
Type::Group(TypeGroup { elem, .. }) => contains_self_type(elem),
|
||||
Type::Paren(TypeParen { elem, .. }) => contains_self_type(elem),
|
||||
Type::Ptr(TypePtr { elem, .. }) => contains_self_type(elem),
|
||||
Type::Reference(TypeReference { elem, .. }) => contains_self_type(elem),
|
||||
Type::Slice(TypeSlice { elem, .. }) => contains_self_type(elem),
|
||||
|
||||
Type::Tuple(TypeTuple { elems, .. }) => elems.iter().any(contains_self_type),
|
||||
|
||||
Type::Path(TypePath { qself: Some(_), .. }) => true,
|
||||
Type::Path(TypePath { path, .. }) => contains_self_type_path(path),
|
||||
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn has_self_type(input: &FnArg) -> bool {
|
||||
match input {
|
||||
FnArg::Receiver(_) => true,
|
||||
FnArg::Typed(PatType { ty, .. }) => contains_self_type(ty),
|
||||
}
|
||||
}
|
||||
1
src-macros/tests/macros.rs
Normal file
1
src-macros/tests/macros.rs
Normal file
@@ -0,0 +1 @@
|
||||
mod momo;
|
||||
303
src-macros/tests/momo/mod.rs
Normal file
303
src-macros/tests/momo/mod.rs
Normal file
@@ -0,0 +1,303 @@
|
||||
use std::pin::Pin;
|
||||
|
||||
use gix_macros::momo;
|
||||
|
||||
struct Options;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn test_open_opts_inner(_dir: impl Into<std::path::PathBuf>, _options: Options) -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// See if doc are kept
|
||||
#[allow(dead_code)]
|
||||
#[momo]
|
||||
fn test_open_opts(directory: impl Into<std::path::PathBuf>, options: Options) -> Result<(), ()> {
|
||||
test_open_opts_inner(directory, options)
|
||||
}
|
||||
|
||||
#[momo]
|
||||
fn test_fn<E>(
|
||||
a: impl Into<String>,
|
||||
b: impl AsRef<str>,
|
||||
mut c: impl AsMut<str>,
|
||||
d: impl TryInto<String, Error = E>,
|
||||
) -> Result<String, E> {
|
||||
let mut s = a.into();
|
||||
s += b.as_ref();
|
||||
s += c.as_mut();
|
||||
s += &d.try_into()?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
#[momo]
|
||||
fn test_fn_call_style<E>(
|
||||
a: impl Into<String>,
|
||||
b: impl AsRef<str>,
|
||||
mut c: impl AsMut<str>,
|
||||
d: impl TryInto<String, Error = E>,
|
||||
) -> Result<String, E> {
|
||||
let mut s = Into::into(a);
|
||||
s += AsRef::as_ref(&b);
|
||||
s += AsMut::as_mut(&mut c);
|
||||
s += &TryInto::try_into(d)?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
#[momo]
|
||||
fn test_fn_where<A, B, C, D, E>(a: A, b: B, mut c: C, d: D) -> Result<String, E>
|
||||
where
|
||||
A: Into<String>,
|
||||
B: AsRef<str>,
|
||||
C: AsMut<str>,
|
||||
D: TryInto<String, Error = E>,
|
||||
{
|
||||
let mut s = a.into();
|
||||
s += b.as_ref();
|
||||
s += c.as_mut();
|
||||
s += &d.try_into()?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
struct TestStruct;
|
||||
|
||||
impl TestStruct {
|
||||
#[momo]
|
||||
fn test_method<E>(
|
||||
self,
|
||||
a: impl Into<String>,
|
||||
b: impl AsRef<str>,
|
||||
mut c: impl AsMut<str>,
|
||||
d: impl TryInto<String, Error = E>,
|
||||
) -> Result<String, E> {
|
||||
let mut s = a.into();
|
||||
s += b.as_ref();
|
||||
s += c.as_mut();
|
||||
s += &d.try_into()?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_arbitrary_self_type)]
|
||||
#[momo]
|
||||
fn test_method2<E>(
|
||||
self: Self,
|
||||
a: impl Into<String>,
|
||||
b: impl AsRef<str>,
|
||||
mut c: impl AsMut<str>,
|
||||
d: impl TryInto<String, Error = E>,
|
||||
) -> Result<String, E> {
|
||||
let mut s = a.into();
|
||||
s += b.as_ref();
|
||||
s += c.as_mut();
|
||||
s += &d.try_into()?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
#[momo]
|
||||
fn test_fn<E>(
|
||||
a: impl Into<String>,
|
||||
b: impl AsRef<str>,
|
||||
mut c: impl AsMut<str>,
|
||||
d: impl TryInto<String, Error = E>,
|
||||
_e: (),
|
||||
) -> Result<String, E> {
|
||||
let mut s = a.into();
|
||||
s += b.as_ref();
|
||||
s += c.as_mut();
|
||||
s += &d.try_into()?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
#[momo]
|
||||
fn test_fn2<E>(
|
||||
_this: Self,
|
||||
a: impl Into<String>,
|
||||
b: impl AsRef<str>,
|
||||
mut c: impl AsMut<str>,
|
||||
d: impl TryInto<String, Error = E>,
|
||||
_e: (),
|
||||
_f: (),
|
||||
) -> Result<String, E> {
|
||||
let mut s = a.into();
|
||||
s += b.as_ref();
|
||||
s += c.as_mut();
|
||||
s += &d.try_into()?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
#[momo]
|
||||
fn test_fn3<E>(
|
||||
_this: Pin<&mut Self>,
|
||||
a: impl Into<String>,
|
||||
b: impl AsRef<str>,
|
||||
mut c: impl AsMut<str>,
|
||||
d: impl TryInto<String, Error = E>,
|
||||
_e: (),
|
||||
_f: (),
|
||||
) -> Result<String, E> {
|
||||
let mut s = a.into();
|
||||
s += b.as_ref();
|
||||
s += c.as_mut();
|
||||
s += &d.try_into()?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[momo]
|
||||
fn test_fn_ret<E>(
|
||||
_this: Pin<&mut Self>,
|
||||
a: impl Into<String>,
|
||||
b: impl AsRef<str>,
|
||||
mut c: impl AsMut<str>,
|
||||
d: impl TryInto<String, Error = E>,
|
||||
_e: (),
|
||||
_f: (),
|
||||
) -> Result<Self, E> {
|
||||
let mut s = a.into();
|
||||
s += b.as_ref();
|
||||
s += c.as_mut();
|
||||
s += &d.try_into()?;
|
||||
|
||||
drop(s);
|
||||
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
struct S(bool);
|
||||
impl TryInto<String> for S {
|
||||
type Error = ();
|
||||
|
||||
fn try_into(self) -> Result<String, ()> {
|
||||
if self.0 {
|
||||
Ok(String::from("!2345"))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[momo]
|
||||
fn test_fn_pat<E>(
|
||||
a: impl Into<String>,
|
||||
b: impl AsRef<str>,
|
||||
mut c: impl AsMut<str>,
|
||||
d: impl TryInto<String, Error = E>,
|
||||
S(_g): S,
|
||||
) -> Result<(), E> {
|
||||
let mut s = a.into();
|
||||
s += b.as_ref();
|
||||
s += c.as_mut();
|
||||
s += &d.try_into()?;
|
||||
|
||||
drop(s);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_fn() {
|
||||
assert_eq!(
|
||||
test_fn("12345", "12345", String::from("12345"), S(true)).unwrap(),
|
||||
"123451234512345!2345"
|
||||
);
|
||||
|
||||
test_fn("12345", "12345", String::from("12345"), S(false)).unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
test_fn_call_style("12345", "12345", String::from("12345"), S(true)).unwrap(),
|
||||
"123451234512345!2345"
|
||||
);
|
||||
|
||||
test_fn_call_style("12345", "12345", String::from("12345"), S(false)).unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
test_fn_where("12345", "12345", String::from("12345"), S(true)).unwrap(),
|
||||
"123451234512345!2345"
|
||||
);
|
||||
|
||||
test_fn_where("12345", "12345", String::from("12345"), S(false)).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn struct_method() {
|
||||
assert_eq!(
|
||||
TestStruct
|
||||
.test_method("12345", "12345", String::from("12345"), S(true))
|
||||
.unwrap(),
|
||||
"123451234512345!2345"
|
||||
);
|
||||
|
||||
TestStruct
|
||||
.test_method("12345", "12345", String::from("12345"), S(false))
|
||||
.unwrap_err();
|
||||
|
||||
// Test test_method2
|
||||
assert_eq!(
|
||||
TestStruct
|
||||
.test_method2("12345", "12345", String::from("12345"), S(true))
|
||||
.unwrap(),
|
||||
"123451234512345!2345"
|
||||
);
|
||||
|
||||
TestStruct
|
||||
.test_method2("12345", "12345", String::from("12345"), S(false))
|
||||
.unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn struct_fn() {
|
||||
assert_eq!(
|
||||
TestStruct::test_fn("12345", "12345", String::from("12345"), S(true), ()).unwrap(),
|
||||
"123451234512345!2345"
|
||||
);
|
||||
|
||||
TestStruct::test_fn("12345", "12345", String::from("12345"), S(false), ()).unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
TestStruct::test_fn2(TestStruct, "12345", "12345", String::from("12345"), S(true), (), ()).unwrap(),
|
||||
"123451234512345!2345"
|
||||
);
|
||||
|
||||
TestStruct::test_fn2(TestStruct, "12345", "12345", String::from("12345"), S(false), (), ()).unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
TestStruct::test_fn3(
|
||||
Pin::new(&mut TestStruct),
|
||||
"12345",
|
||||
"12345",
|
||||
String::from("12345"),
|
||||
S(true),
|
||||
(),
|
||||
()
|
||||
)
|
||||
.unwrap(),
|
||||
"123451234512345!2345"
|
||||
);
|
||||
|
||||
TestStruct::test_fn3(
|
||||
Pin::new(&mut TestStruct),
|
||||
"12345",
|
||||
"12345",
|
||||
String::from("12345"),
|
||||
S(false),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ux() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/momo/ux/*.rs");
|
||||
}
|
||||
3
src-macros/tests/momo/ux/error_if_ineffective.rs
Normal file
3
src-macros/tests/momo/ux/error_if_ineffective.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
/// If nothing is done, momo should fail.
|
||||
#[gix_macros::momo]
|
||||
fn main() {}
|
||||
11
src-macros/tests/momo/ux/error_if_ineffective.stderr
Normal file
11
src-macros/tests/momo/ux/error_if_ineffective.stderr
Normal file
@@ -0,0 +1,11 @@
|
||||
error: Couldn't apply a single conversion - momo is ineffective here
|
||||
--> tests/momo/ux/error_if_ineffective.rs:1:1
|
||||
|
|
||||
1 | /// If nothing is done, momo should fail.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0601]: `main` function not found in crate `$CRATE`
|
||||
--> tests/momo/ux/error_if_ineffective.rs:3:13
|
||||
|
|
||||
3 | fn main() {}
|
||||
| ^ consider adding a `main` function to `$DIR/tests/momo/ux/error_if_ineffective.rs`
|
||||
5
src-macros/tests/momo/ux/error_on_struct.rs
Normal file
5
src-macros/tests/momo/ux/error_on_struct.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
fn main() {}
|
||||
|
||||
/// Only functions work with momo
|
||||
#[gix_macros::momo]
|
||||
struct S;
|
||||
5
src-macros/tests/momo/ux/error_on_struct.stderr
Normal file
5
src-macros/tests/momo/ux/error_on_struct.stderr
Normal file
@@ -0,0 +1,5 @@
|
||||
error: expect a function
|
||||
--> tests/momo/ux/error_on_struct.rs:3:1
|
||||
|
|
||||
3 | /// Only functions work with momo
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Reference in New Issue
Block a user