From a5ca2d87d04355fbd3b8c4e3831af972960a40f6 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 14:18:00 +0000 Subject: [PATCH 01/39] move macro to try_v2_derive --- Cargo.toml | 36 +------------------ crates/try_v2_derive/Cargo.toml | 30 ++++++++++++++++ build.rs => crates/try_v2_derive/build.rs | 0 .../try_v2_derive/examples}/BangMatching.rs | 0 .../try_v2_derive/examples}/Nested_NoTry.rs | 0 .../try_v2_derive/examples}/Nested_Try.rs | 2 +- .../try_v2_derive/examples}/TraitExt_NoTry.rs | 0 .../try_v2_derive/examples}/TraitExt_Try.rs | 2 +- .../try_v2_derive/examples}/Transpose.rs | 0 .../try_v2_derive/examples}/TryFrom2.rs | 2 +- .../try_v2_derive/examples}/Unwrap.rs | 0 .../try_v2_derive/examples}/signatures.rs | 0 {src => crates/try_v2_derive/src}/lib.rs | 0 {src => crates/try_v2_derive/src}/parse.rs | 0 .../tests}/compilation/Cargo.toml | 4 +-- .../examples/fail_FirstGenericNotOutput.rs | 2 +- .../fail_FirstGenericNotOutput.stderr | 0 .../compilation/examples/fail_MustUse.rs | 2 +- .../compilation/examples/fail_MustUse.stderr | 0 .../compilation/examples/fail_NoGenerics.rs | 2 +- .../examples/fail_NoGenerics.stderr | 0 .../examples/fail_OutputNamedFields.rs | 2 +- .../examples/fail_OutputNamedFields.stderr | 0 .../examples/fail_OutputTypeKind.rs | 2 +- .../examples/fail_OutputTypeKind.stderr | 0 .../examples/fail_OutputUnitType.rs | 2 +- .../examples/fail_OutputUnitType.stderr | 0 .../compilation/examples/fail_Struct.rs | 2 +- .../compilation/examples/fail_Struct.stderr | 0 .../examples/fail_TooManyOutputs.rs | 2 +- .../examples/fail_TooManyOutputs.stderr | 0 .../tests}/compilation/examples/fail_Union.rs | 2 +- .../compilation/examples/fail_Union.stderr | 0 .../examples/fail_ZeroFieldEnum.rs | 2 +- .../examples/fail_ZeroFieldEnum.stderr | 0 .../examples/fail_lifetime_conversion.rs | 2 +- .../examples/fail_lifetime_conversion.stderr | 0 .../examples/fail_lifetime_duration.rs | 2 +- .../examples/fail_lifetime_duration.stderr | 0 .../compilation/examples/pass_EDebug.rs | 2 +- .../compilation/examples/pass_GenericE.rs | 2 +- .../examples/pass_MultipleFields.rs | 2 +- .../examples/pass_MultipleGenerics.rs | 2 +- .../examples/pass_NoFieldResiduals.rs | 2 +- .../examples/pass_NoUnitResidual.rs | 2 +- .../compilation/examples/pass_ResultMeBang.rs | 2 +- .../compilation/examples/wip_ShortCircuitT.rs | 2 +- .../tests}/compilation/src/lib.rs | 0 .../try_v2_derive/tests}/test_compilation.rs | 0 .../try_v2_derive/tests}/test_usage.rs | 4 +-- 50 files changed, 58 insertions(+), 62 deletions(-) create mode 100644 crates/try_v2_derive/Cargo.toml rename build.rs => crates/try_v2_derive/build.rs (100%) rename {examples => crates/try_v2_derive/examples}/BangMatching.rs (100%) rename {examples => crates/try_v2_derive/examples}/Nested_NoTry.rs (100%) rename {examples => crates/try_v2_derive/examples}/Nested_Try.rs (96%) rename {examples => crates/try_v2_derive/examples}/TraitExt_NoTry.rs (100%) rename {examples => crates/try_v2_derive/examples}/TraitExt_Try.rs (97%) rename {examples => crates/try_v2_derive/examples}/Transpose.rs (100%) rename {examples => crates/try_v2_derive/examples}/TryFrom2.rs (98%) rename {examples => crates/try_v2_derive/examples}/Unwrap.rs (100%) rename {examples => crates/try_v2_derive/examples}/signatures.rs (100%) rename {src => crates/try_v2_derive/src}/lib.rs (100%) rename {src => crates/try_v2_derive/src}/parse.rs (100%) rename {tests => crates/try_v2_derive/tests}/compilation/Cargo.toml (53%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_FirstGenericNotOutput.rs (90%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_FirstGenericNotOutput.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_MustUse.rs (83%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_MustUse.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_NoGenerics.rs (82%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_NoGenerics.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_OutputNamedFields.rs (89%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_OutputNamedFields.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_OutputTypeKind.rs (92%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_OutputTypeKind.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_OutputUnitType.rs (83%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_OutputUnitType.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_Struct.rs (78%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_Struct.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_TooManyOutputs.rs (91%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_TooManyOutputs.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_Union.rs (80%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_Union.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_ZeroFieldEnum.rs (79%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_ZeroFieldEnum.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_lifetime_conversion.rs (98%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_lifetime_conversion.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_lifetime_duration.rs (96%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/fail_lifetime_duration.stderr (100%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/pass_EDebug.rs (88%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/pass_GenericE.rs (83%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/pass_MultipleFields.rs (84%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/pass_MultipleGenerics.rs (83%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/pass_NoFieldResiduals.rs (87%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/pass_NoUnitResidual.rs (87%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/pass_ResultMeBang.rs (93%) rename {tests => crates/try_v2_derive/tests}/compilation/examples/wip_ShortCircuitT.rs (85%) rename {tests => crates/try_v2_derive/tests}/compilation/src/lib.rs (100%) rename {tests => crates/try_v2_derive/tests}/test_compilation.rs (100%) rename {tests => crates/try_v2_derive/tests}/test_usage.rs (99%) diff --git a/Cargo.toml b/Cargo.toml index a79dab7..c66a4d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,36 +1,2 @@ -[package] -name = "try_v2" -version = "0.4.2" -edition = "2024" -readme = "README.md" -description = "Provides a derive macro for `Try` ([try_trait_v2](https://rust-lang.github.io/rfcs/3058-try-trait-v2.html))" -authors = ["Mike Foster "] -keywords = ["derive", "Try", "try_trait_v2"] -homepage = "https://github.com/MusicalNinjaDad/try_v2" -repository = "https://github.com/MusicalNinjaDad/try_v2" -categories = ["development-tools"] -license = "MIT" -rust-version = "1.85.1" -exclude = [".github", ".devcontainer"] - -[lib] -proc-macro = true - -[dependencies] -syn = {version = "2.0.117", features = ["full","extra-traits"]} -proc-macro2 = "1.0.106" -proc_macro2_diagnostic = "0.3.0" -quote = "1.0.45" - -[dev-dependencies] -log = "0.4.29" -trybuild = "1.0.116" - -[build-dependencies] -autocfg = "1.5.1" - [workspace] -members = ["tests/compilation"] - -[workspace.dependencies] -try_v2 = { path = "."} +members = ["crates/*"] diff --git a/crates/try_v2_derive/Cargo.toml b/crates/try_v2_derive/Cargo.toml new file mode 100644 index 0000000..4e2b1dd --- /dev/null +++ b/crates/try_v2_derive/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "try_v2_derive" +version = "0.5.0" +edition = "2024" +readme = "README.md" +description = "Provides a derive macro for `Try` ([try_trait_v2](https://rust-lang.github.io/rfcs/3058-try-trait-v2.html))" +authors = ["Mike Foster "] +keywords = ["derive", "Try", "try_trait_v2"] +homepage = "https://github.com/MusicalNinjaDad/try_v2" +repository = "https://github.com/MusicalNinjaDad/try_v2" +categories = ["development-tools"] +license = "MIT" +rust-version = "1.85.1" +exclude = [".github", ".devcontainer"] + +[lib] +proc-macro = true + +[dependencies] +syn = {version = "2.0.117", features = ["full","extra-traits"]} +proc-macro2 = "1.0.106" +proc_macro2_diagnostic = "0.3.0" +quote = "1.0.45" + +[dev-dependencies] +log = "0.4.29" +trybuild = "1.0.116" + +[build-dependencies] +autocfg = "1.5.1" diff --git a/build.rs b/crates/try_v2_derive/build.rs similarity index 100% rename from build.rs rename to crates/try_v2_derive/build.rs diff --git a/examples/BangMatching.rs b/crates/try_v2_derive/examples/BangMatching.rs similarity index 100% rename from examples/BangMatching.rs rename to crates/try_v2_derive/examples/BangMatching.rs diff --git a/examples/Nested_NoTry.rs b/crates/try_v2_derive/examples/Nested_NoTry.rs similarity index 100% rename from examples/Nested_NoTry.rs rename to crates/try_v2_derive/examples/Nested_NoTry.rs diff --git a/examples/Nested_Try.rs b/crates/try_v2_derive/examples/Nested_Try.rs similarity index 96% rename from examples/Nested_Try.rs rename to crates/try_v2_derive/examples/Nested_Try.rs index f728927..10cf14a 100644 --- a/examples/Nested_Try.rs +++ b/crates/try_v2_derive/examples/Nested_Try.rs @@ -5,7 +5,7 @@ use std::{error::Error, io}; -use try_v2::Try; +use try_v2_derive::Try; use DuplicateData::Duplicate; diff --git a/examples/TraitExt_NoTry.rs b/crates/try_v2_derive/examples/TraitExt_NoTry.rs similarity index 100% rename from examples/TraitExt_NoTry.rs rename to crates/try_v2_derive/examples/TraitExt_NoTry.rs diff --git a/examples/TraitExt_Try.rs b/crates/try_v2_derive/examples/TraitExt_Try.rs similarity index 97% rename from examples/TraitExt_Try.rs rename to crates/try_v2_derive/examples/TraitExt_Try.rs index d1387a6..f2b5d49 100644 --- a/examples/TraitExt_Try.rs +++ b/crates/try_v2_derive/examples/TraitExt_Try.rs @@ -6,7 +6,7 @@ use log::info; use std::{fmt::Display, ops::Add}; -use try_v2::Try; +use try_v2_derive::Try; use Counter::Count; diff --git a/examples/Transpose.rs b/crates/try_v2_derive/examples/Transpose.rs similarity index 100% rename from examples/Transpose.rs rename to crates/try_v2_derive/examples/Transpose.rs diff --git a/examples/TryFrom2.rs b/crates/try_v2_derive/examples/TryFrom2.rs similarity index 98% rename from examples/TryFrom2.rs rename to crates/try_v2_derive/examples/TryFrom2.rs index f15bbfc..ae9c2b8 100644 --- a/examples/TryFrom2.rs +++ b/crates/try_v2_derive/examples/TryFrom2.rs @@ -3,7 +3,7 @@ #![feature(try_trait_v2_residual)] #![feature(associated_type_defaults)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; /// Make TryFrom able to return arbitrary Try types trait TryFrom2: std::marker::Sized { diff --git a/examples/Unwrap.rs b/crates/try_v2_derive/examples/Unwrap.rs similarity index 100% rename from examples/Unwrap.rs rename to crates/try_v2_derive/examples/Unwrap.rs diff --git a/examples/signatures.rs b/crates/try_v2_derive/examples/signatures.rs similarity index 100% rename from examples/signatures.rs rename to crates/try_v2_derive/examples/signatures.rs diff --git a/src/lib.rs b/crates/try_v2_derive/src/lib.rs similarity index 100% rename from src/lib.rs rename to crates/try_v2_derive/src/lib.rs diff --git a/src/parse.rs b/crates/try_v2_derive/src/parse.rs similarity index 100% rename from src/parse.rs rename to crates/try_v2_derive/src/parse.rs diff --git a/tests/compilation/Cargo.toml b/crates/try_v2_derive/tests/compilation/Cargo.toml similarity index 53% rename from tests/compilation/Cargo.toml rename to crates/try_v2_derive/tests/compilation/Cargo.toml index 5e9dfd2..a21bc69 100644 --- a/tests/compilation/Cargo.toml +++ b/crates/try_v2_derive/tests/compilation/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "try_v2_compilation_tests" +name = "try_v2_derive_compilation_tests" version = "0.4.0" edition = "2024" publish = false @@ -7,4 +7,4 @@ publish = false [lib] [dev-dependencies] -try_v2 = { workspace = true} +try_v2_derive = { workspace = true} diff --git a/tests/compilation/examples/fail_FirstGenericNotOutput.rs b/crates/try_v2_derive/tests/compilation/examples/fail_FirstGenericNotOutput.rs similarity index 90% rename from tests/compilation/examples/fail_FirstGenericNotOutput.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_FirstGenericNotOutput.rs index 7d869b4..88c4354 100644 --- a/tests/compilation/examples/fail_FirstGenericNotOutput.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_FirstGenericNotOutput.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/fail_FirstGenericNotOutput.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_FirstGenericNotOutput.stderr similarity index 100% rename from tests/compilation/examples/fail_FirstGenericNotOutput.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_FirstGenericNotOutput.stderr diff --git a/tests/compilation/examples/fail_MustUse.rs b/crates/try_v2_derive/tests/compilation/examples/fail_MustUse.rs similarity index 83% rename from tests/compilation/examples/fail_MustUse.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_MustUse.rs index 98bcbb8..ec46c0e 100644 --- a/tests/compilation/examples/fail_MustUse.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_MustUse.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Debug, Try, Try_ConvertResult)] enum ExitE { diff --git a/tests/compilation/examples/fail_MustUse.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_MustUse.stderr similarity index 100% rename from tests/compilation/examples/fail_MustUse.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_MustUse.stderr diff --git a/tests/compilation/examples/fail_NoGenerics.rs b/crates/try_v2_derive/tests/compilation/examples/fail_NoGenerics.rs similarity index 82% rename from tests/compilation/examples/fail_NoGenerics.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_NoGenerics.rs index dc09ff7..d723716 100644 --- a/tests/compilation/examples/fail_NoGenerics.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_NoGenerics.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/fail_NoGenerics.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_NoGenerics.stderr similarity index 100% rename from tests/compilation/examples/fail_NoGenerics.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_NoGenerics.stderr diff --git a/tests/compilation/examples/fail_OutputNamedFields.rs b/crates/try_v2_derive/tests/compilation/examples/fail_OutputNamedFields.rs similarity index 89% rename from tests/compilation/examples/fail_OutputNamedFields.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_OutputNamedFields.rs index db01796..763dae4 100644 --- a/tests/compilation/examples/fail_OutputNamedFields.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_OutputNamedFields.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/fail_OutputNamedFields.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_OutputNamedFields.stderr similarity index 100% rename from tests/compilation/examples/fail_OutputNamedFields.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_OutputNamedFields.stderr diff --git a/tests/compilation/examples/fail_OutputTypeKind.rs b/crates/try_v2_derive/tests/compilation/examples/fail_OutputTypeKind.rs similarity index 92% rename from tests/compilation/examples/fail_OutputTypeKind.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_OutputTypeKind.rs index 0efc5b8..ed6b358 100644 --- a/tests/compilation/examples/fail_OutputTypeKind.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_OutputTypeKind.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/fail_OutputTypeKind.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_OutputTypeKind.stderr similarity index 100% rename from tests/compilation/examples/fail_OutputTypeKind.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_OutputTypeKind.stderr diff --git a/tests/compilation/examples/fail_OutputUnitType.rs b/crates/try_v2_derive/tests/compilation/examples/fail_OutputUnitType.rs similarity index 83% rename from tests/compilation/examples/fail_OutputUnitType.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_OutputUnitType.rs index b624ab9..771b8ef 100644 --- a/tests/compilation/examples/fail_OutputUnitType.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_OutputUnitType.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/fail_OutputUnitType.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_OutputUnitType.stderr similarity index 100% rename from tests/compilation/examples/fail_OutputUnitType.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_OutputUnitType.stderr diff --git a/tests/compilation/examples/fail_Struct.rs b/crates/try_v2_derive/tests/compilation/examples/fail_Struct.rs similarity index 78% rename from tests/compilation/examples/fail_Struct.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_Struct.rs index a018045..5db7af9 100644 --- a/tests/compilation/examples/fail_Struct.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_Struct.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/fail_Struct.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_Struct.stderr similarity index 100% rename from tests/compilation/examples/fail_Struct.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_Struct.stderr diff --git a/tests/compilation/examples/fail_TooManyOutputs.rs b/crates/try_v2_derive/tests/compilation/examples/fail_TooManyOutputs.rs similarity index 91% rename from tests/compilation/examples/fail_TooManyOutputs.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_TooManyOutputs.rs index 5d9798d..ca209bd 100644 --- a/tests/compilation/examples/fail_TooManyOutputs.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_TooManyOutputs.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/fail_TooManyOutputs.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_TooManyOutputs.stderr similarity index 100% rename from tests/compilation/examples/fail_TooManyOutputs.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_TooManyOutputs.stderr diff --git a/tests/compilation/examples/fail_Union.rs b/crates/try_v2_derive/tests/compilation/examples/fail_Union.rs similarity index 80% rename from tests/compilation/examples/fail_Union.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_Union.rs index 8273c24..d7d4885 100644 --- a/tests/compilation/examples/fail_Union.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_Union.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/fail_Union.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_Union.stderr similarity index 100% rename from tests/compilation/examples/fail_Union.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_Union.stderr diff --git a/tests/compilation/examples/fail_ZeroFieldEnum.rs b/crates/try_v2_derive/tests/compilation/examples/fail_ZeroFieldEnum.rs similarity index 79% rename from tests/compilation/examples/fail_ZeroFieldEnum.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_ZeroFieldEnum.rs index a735d42..76655b6 100644 --- a/tests/compilation/examples/fail_ZeroFieldEnum.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_ZeroFieldEnum.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/fail_ZeroFieldEnum.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_ZeroFieldEnum.stderr similarity index 100% rename from tests/compilation/examples/fail_ZeroFieldEnum.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_ZeroFieldEnum.stderr diff --git a/tests/compilation/examples/fail_lifetime_conversion.rs b/crates/try_v2_derive/tests/compilation/examples/fail_lifetime_conversion.rs similarity index 98% rename from tests/compilation/examples/fail_lifetime_conversion.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_lifetime_conversion.rs index 4ec5f31..2fd9db4 100644 --- a/tests/compilation/examples/fail_lifetime_conversion.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_lifetime_conversion.rs @@ -4,7 +4,7 @@ //! Tests that conversion between custom enum and std::result::Result requires correct lifetime bounds. -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Debug, Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/fail_lifetime_conversion.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_lifetime_conversion.stderr similarity index 100% rename from tests/compilation/examples/fail_lifetime_conversion.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_lifetime_conversion.stderr diff --git a/tests/compilation/examples/fail_lifetime_duration.rs b/crates/try_v2_derive/tests/compilation/examples/fail_lifetime_duration.rs similarity index 96% rename from tests/compilation/examples/fail_lifetime_duration.rs rename to crates/try_v2_derive/tests/compilation/examples/fail_lifetime_duration.rs index d07a04c..56d419c 100644 --- a/tests/compilation/examples/fail_lifetime_duration.rs +++ b/crates/try_v2_derive/tests/compilation/examples/fail_lifetime_duration.rs @@ -4,7 +4,7 @@ //! Tests to ensure that lifetimes are correctly passed through and live as long as expected. -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; // Basic result with T & E borrowed #[must_use] diff --git a/tests/compilation/examples/fail_lifetime_duration.stderr b/crates/try_v2_derive/tests/compilation/examples/fail_lifetime_duration.stderr similarity index 100% rename from tests/compilation/examples/fail_lifetime_duration.stderr rename to crates/try_v2_derive/tests/compilation/examples/fail_lifetime_duration.stderr diff --git a/tests/compilation/examples/pass_EDebug.rs b/crates/try_v2_derive/tests/compilation/examples/pass_EDebug.rs similarity index 88% rename from tests/compilation/examples/pass_EDebug.rs rename to crates/try_v2_derive/tests/compilation/examples/pass_EDebug.rs index 6b6477d..9da48da 100644 --- a/tests/compilation/examples/pass_EDebug.rs +++ b/crates/try_v2_derive/tests/compilation/examples/pass_EDebug.rs @@ -5,7 +5,7 @@ use std::fmt::Debug; -use try_v2::{Try, Try_Methods}; +use try_v2_derive::{Try, Try_Methods}; #[derive(Debug, Try, Try_Methods)] #[must_use] diff --git a/tests/compilation/examples/pass_GenericE.rs b/crates/try_v2_derive/tests/compilation/examples/pass_GenericE.rs similarity index 83% rename from tests/compilation/examples/pass_GenericE.rs rename to crates/try_v2_derive/tests/compilation/examples/pass_GenericE.rs index 06c712d..7845e20 100644 --- a/tests/compilation/examples/pass_GenericE.rs +++ b/crates/try_v2_derive/tests/compilation/examples/pass_GenericE.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Debug, Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/pass_MultipleFields.rs b/crates/try_v2_derive/tests/compilation/examples/pass_MultipleFields.rs similarity index 84% rename from tests/compilation/examples/pass_MultipleFields.rs rename to crates/try_v2_derive/tests/compilation/examples/pass_MultipleFields.rs index 05b4eb7..6d9af9d 100644 --- a/tests/compilation/examples/pass_MultipleFields.rs +++ b/crates/try_v2_derive/tests/compilation/examples/pass_MultipleFields.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Debug, Try, Try_ConvertResult)] #[allow(unused)] diff --git a/tests/compilation/examples/pass_MultipleGenerics.rs b/crates/try_v2_derive/tests/compilation/examples/pass_MultipleGenerics.rs similarity index 83% rename from tests/compilation/examples/pass_MultipleGenerics.rs rename to crates/try_v2_derive/tests/compilation/examples/pass_MultipleGenerics.rs index 5bfcbda..2ff632f 100644 --- a/tests/compilation/examples/pass_MultipleGenerics.rs +++ b/crates/try_v2_derive/tests/compilation/examples/pass_MultipleGenerics.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Debug, Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/pass_NoFieldResiduals.rs b/crates/try_v2_derive/tests/compilation/examples/pass_NoFieldResiduals.rs similarity index 87% rename from tests/compilation/examples/pass_NoFieldResiduals.rs rename to crates/try_v2_derive/tests/compilation/examples/pass_NoFieldResiduals.rs index 6a31649..ab60fe7 100644 --- a/tests/compilation/examples/pass_NoFieldResiduals.rs +++ b/crates/try_v2_derive/tests/compilation/examples/pass_NoFieldResiduals.rs @@ -4,7 +4,7 @@ use std::process::Termination; -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Debug, Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/pass_NoUnitResidual.rs b/crates/try_v2_derive/tests/compilation/examples/pass_NoUnitResidual.rs similarity index 87% rename from tests/compilation/examples/pass_NoUnitResidual.rs rename to crates/try_v2_derive/tests/compilation/examples/pass_NoUnitResidual.rs index 742b634..6f42e71 100644 --- a/tests/compilation/examples/pass_NoUnitResidual.rs +++ b/crates/try_v2_derive/tests/compilation/examples/pass_NoUnitResidual.rs @@ -4,7 +4,7 @@ use std::process::Termination; -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Debug, Try, Try_ConvertResult)] #[allow(unused)] // If it compiles then it already passes diff --git a/tests/compilation/examples/pass_ResultMeBang.rs b/crates/try_v2_derive/tests/compilation/examples/pass_ResultMeBang.rs similarity index 93% rename from tests/compilation/examples/pass_ResultMeBang.rs rename to crates/try_v2_derive/tests/compilation/examples/pass_ResultMeBang.rs index 518de7c..6b96698 100644 --- a/tests/compilation/examples/pass_ResultMeBang.rs +++ b/crates/try_v2_derive/tests/compilation/examples/pass_ResultMeBang.rs @@ -2,7 +2,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/examples/wip_ShortCircuitT.rs b/crates/try_v2_derive/tests/compilation/examples/wip_ShortCircuitT.rs similarity index 85% rename from tests/compilation/examples/wip_ShortCircuitT.rs rename to crates/try_v2_derive/tests/compilation/examples/wip_ShortCircuitT.rs index dbb00b6..5f4cea1 100644 --- a/tests/compilation/examples/wip_ShortCircuitT.rs +++ b/crates/try_v2_derive/tests/compilation/examples/wip_ShortCircuitT.rs @@ -4,7 +4,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult}; +use try_v2_derive::{Try, Try_ConvertResult}; #[derive(Debug, Try, Try_ConvertResult)] #[must_use] diff --git a/tests/compilation/src/lib.rs b/crates/try_v2_derive/tests/compilation/src/lib.rs similarity index 100% rename from tests/compilation/src/lib.rs rename to crates/try_v2_derive/tests/compilation/src/lib.rs diff --git a/tests/test_compilation.rs b/crates/try_v2_derive/tests/test_compilation.rs similarity index 100% rename from tests/test_compilation.rs rename to crates/try_v2_derive/tests/test_compilation.rs diff --git a/tests/test_usage.rs b/crates/try_v2_derive/tests/test_usage.rs similarity index 99% rename from tests/test_usage.rs rename to crates/try_v2_derive/tests/test_usage.rs index 6d2b97c..3605363 100644 --- a/tests/test_usage.rs +++ b/crates/try_v2_derive/tests/test_usage.rs @@ -4,7 +4,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2::{Try, Try_ConvertResult, Try_Methods}; +use try_v2_derive::{Try, Try_ConvertResult, Try_Methods}; #[cfg(assert_matches_in_module)] use std::assert_matches::assert_matches; @@ -141,7 +141,7 @@ mod multiple_generics { } mod iter { - use try_v2::Try_Iterator; + use try_v2_derive::Try_Iterator; use super::*; From 27b07a03c97863bb476853949d376bb76422e5ec Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 14:26:07 +0000 Subject: [PATCH 02/39] pub reexport from new try_v2 crate --- Cargo.toml | 3 + crates/try_v2/Cargo.toml | 23 ++++++ crates/try_v2/src/lib.rs | 115 +++++++++++++++++++++++++++++ crates/try_v2_derive/src/lib.rs | 123 ++------------------------------ 4 files changed, 146 insertions(+), 118 deletions(-) create mode 100644 crates/try_v2/Cargo.toml create mode 100644 crates/try_v2/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index c66a4d7..ee3bfe0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,5 @@ [workspace] members = ["crates/*"] + +[workspace.dependencies] +try_v2_derive = { path = "crates/try_v2_derive", version = "0.5.0" } diff --git a/crates/try_v2/Cargo.toml b/crates/try_v2/Cargo.toml new file mode 100644 index 0000000..675a5c8 --- /dev/null +++ b/crates/try_v2/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "try_v2" +version = "0.5.0" +edition = "2024" +readme = "README.md" +description = "Provides a derive macro & helper traits for `Try`" +authors = ["Mike Foster "] +keywords = ["derive", "Try", "try_trait_v2"] +homepage = "https://github.com/MusicalNinjaDad/try_v2" +repository = "https://github.com/MusicalNinjaDad/try_v2" +categories = ["development-tools"] +license = "MIT" +rust-version = "1.85.1" +exclude = [".github", ".devcontainer"] + +[lib] + +[dependencies] +try_v2_derive = { workspace = true } + +[dev-dependencies] + +[build-dependencies] diff --git a/crates/try_v2/src/lib.rs b/crates/try_v2/src/lib.rs new file mode 100644 index 0000000..4306030 --- /dev/null +++ b/crates/try_v2/src/lib.rs @@ -0,0 +1,115 @@ +//! Provides a derive macro for [Try] & optionally [Try_ConvertResult] for interconversion with +//! `std::result::Result` and [Try_Iterator] for iterating over `IntoIterator` and collecting from +//! `FromIterator` analog to how `Result` & `Option` do this. +//! See ([try_trait_v2](https://rust-lang.github.io/rfcs/3058-try-trait-v2.html)) for more details +//! of the underlying trait. +//! +//! ## Requires +//! +//! - nightly +//! - `#![feature(never_type)]` +//! - `#![feature(try_trait_v2)]` +//! - `#![feature(try_trait_v2_residual)]` +//! - optionally: `#![feature(iterator_try_collect)]` (if using Try_Iterator) +//! +//! ## Limitations on the annotated type +//! +//! - must be an `enum` +//! - must have _at least one_ generic type +//! - the _first_ generic type must be the `Output` type (produced when not short-circuiting) +//! - the output variant (does not short-circuit) must be the _first_ variant and store the output +//! type as the _only unnamed_ field +//! - no other variant can store the Output type (TODO #72 add a nice error message) +//! +//! See the individual documentation for [Try], [Try_ConvertResult] and [Try_Iterator] for specifics +//! on the generated code. +//! +//! ## Example Usage +//! +//! ```rust +//! #![feature(never_type)] +//! #![feature(try_trait_v2)] +//! #![feature(try_trait_v2_residual)] +//! use try_v2::{Try, Try_ConvertResult}; +//! +//! #[derive(Try, Try_ConvertResult)] +//! enum TestResult { +//! Ok(T), +//! TestsFailed, +//! OtherError(String) +//! } +//! +//! // Basic short-circuiting thanks to `#[derive(Try)]` +//! fn run_tests() -> TestResult<()> { +//! TestResult::OtherError("oops!".to_string())?; // <- Function short-circuits here ... +//! TestResult::TestsFailed?; +//! TestResult::Ok(()) +//! } +//! +//! assert!(matches!(run_tests(), TestResult::OtherError(msg) if msg == "oops!")); +//! +//! +//! // Conversion from std::result::Result thanks to `#[derive(Try_ConvertResult)]` +//! struct TestFailure {} +//! +//! impl From for TestResult { +//! fn from(err: TestFailure) -> Self { +//! TestResult::TestsFailed +//! } +//! } +//! +//! fn run_more_tests() -> TestResult<()> { +//! std::result::Result::Err(TestFailure{})?; // <- Function short-circuits here & converts to a TestResult... +//! TestResult::Ok(()) +//! } +//! +//! assert!(matches!(run_more_tests(), TestResult::TestsFailed)); +//! ``` +//! +//! ## Stability & MSRV +//! +//! Given that this crate exposes an experimental API from std it makes use of experimental +//! features which require a nightly toolchain. +//! +//! In order to use this crate you must enable the features which it exposes: +//! +//! > 🔬 **Required Experimental Features** +//! > +//! > - [`#![feature(never_type)]`](https://github.com/rust-lang/rust/issues/35121) +//! > - [`#![feature(try_trait_v2)]`](https://github.com/rust-lang/rust/issues/84277) +//! > - [`#![feature(try_trait_v2_residual)]`](https://github.com/rust-lang/rust/issues/91285) +//! > - optionally: [`#![feature(iterator_try_collect)]`](https://github.com/rust-lang/rust/issues/94047) (if using [Try_Iterator]) +//! +//! This crate makes use of the following experimental features in addition to those which it +//! directly supports: +//! +//! > 🔬 **Additional Experimental Features** +//! > +//! > - [`#![feature(if_let_guard)]`](https://github.com/rust-lang/rust/issues/51114) (stable since 1.95.0) +//! > - [`#![feature(let_chains)]`](https://github.com/rust-lang/rust/issues/139951) (stable since 1.88.0) +//! > +//! > This list includes any unstable features used by direct & transitive dependencies (currently, none). +//! > +//! > You do not need to enable these in your own code, the list is for information only. +//! +//! ### Stability guarantees +//! +//! We run automated tests **every month** to ensure no fundamental changes affect this crate and +//! test every PR against the current nightly, as well as the current equivalent beta & stable. +//! If you find an issue before we do, please +//! [raise an issue on github](https://github.com/MusicalNinjaDad/try_v2/issues). +//! +//! ### MSRV +//! +//! For those of you working with a pinned nightly (etc.) this crate supports every version of +//! edition 2024 (rust 1.85.1 onwards, released as stable on 2025-03-18). We use +//! [autocfg](https://crates.io/crates/autocfg/) to seamlessly handle features which have been +//! stabilised since then. +//! +//! ## Currently untested (may work, may not ...): +//! +//! - `where` clauses +//! - storing `Fn`s in variants + +#[doc(inline)] +pub use try_v2_derive::*; diff --git a/crates/try_v2_derive/src/lib.rs b/crates/try_v2_derive/src/lib.rs index fae8116..479f868 100644 --- a/crates/try_v2_derive/src/lib.rs +++ b/crates/try_v2_derive/src/lib.rs @@ -2,119 +2,6 @@ #![cfg_attr(unstable_let_chains, feature(let_chains))] #![feature(never_type)] -//! Provides a derive macro for [Try] & optionally [Try_ConvertResult] for interconversion with -//! `std::result::Result` and [Try_Iterator] for iterating over `IntoIterator` and collecting from -//! `FromIterator` analog to how `Result` & `Option` do this. -//! See ([try_trait_v2](https://rust-lang.github.io/rfcs/3058-try-trait-v2.html)) for more details -//! of the underlying trait. -//! -//! ## Requires -//! -//! - nightly -//! - `#![feature(never_type)]` -//! - `#![feature(try_trait_v2)]` -//! - `#![feature(try_trait_v2_residual)]` -//! - optionally: `#![feature(iterator_try_collect)]` (if using Try_Iterator) -//! -//! ## Limitations on the annotated type -//! -//! - must be an `enum` -//! - must have _at least one_ generic type -//! - the _first_ generic type must be the `Output` type (produced when not short-circuiting) -//! - the output variant (does not short-circuit) must be the _first_ variant and store the output -//! type as the _only unnamed_ field -//! - no other variant can store the Output type (TODO #72 add a nice error message) -//! -//! See the individual documentation for [Try], [Try_ConvertResult] and [Try_Iterator] for specifics -//! on the generated code. -//! -//! ## Example Usage -//! -//! ```rust -//! #![feature(never_type)] -//! #![feature(try_trait_v2)] -//! #![feature(try_trait_v2_residual)] -//! use try_v2::{Try, Try_ConvertResult}; -//! -//! #[derive(Try, Try_ConvertResult)] -//! enum TestResult { -//! Ok(T), -//! TestsFailed, -//! OtherError(String) -//! } -//! -//! // Basic short-circuiting thanks to `#[derive(Try)]` -//! fn run_tests() -> TestResult<()> { -//! TestResult::OtherError("oops!".to_string())?; // <- Function short-circuits here ... -//! TestResult::TestsFailed?; -//! TestResult::Ok(()) -//! } -//! -//! assert!(matches!(run_tests(), TestResult::OtherError(msg) if msg == "oops!")); -//! -//! -//! // Conversion from std::result::Result thanks to `#[derive(Try_ConvertResult)]` -//! struct TestFailure {} -//! -//! impl From for TestResult { -//! fn from(err: TestFailure) -> Self { -//! TestResult::TestsFailed -//! } -//! } -//! -//! fn run_more_tests() -> TestResult<()> { -//! std::result::Result::Err(TestFailure{})?; // <- Function short-circuits here & converts to a TestResult... -//! TestResult::Ok(()) -//! } -//! -//! assert!(matches!(run_more_tests(), TestResult::TestsFailed)); -//! ``` -//! -//! ## Stability & MSRV -//! -//! Given that this crate exposes an experimental API from std it makes use of experimental -//! features which require a nightly toolchain. -//! -//! In order to use this crate you must enable the features which it exposes: -//! -//! > 🔬 **Required Experimental Features** -//! > -//! > - [`#![feature(never_type)]`](https://github.com/rust-lang/rust/issues/35121) -//! > - [`#![feature(try_trait_v2)]`](https://github.com/rust-lang/rust/issues/84277) -//! > - [`#![feature(try_trait_v2_residual)]`](https://github.com/rust-lang/rust/issues/91285) -//! > - optionally: [`#![feature(iterator_try_collect)]`](https://github.com/rust-lang/rust/issues/94047) (if using [Try_Iterator]) -//! -//! This crate makes use of the following experimental features in addition to those which it -//! directly supports: -//! -//! > 🔬 **Additional Experimental Features** -//! > -//! > - [`#![feature(if_let_guard)]`](https://github.com/rust-lang/rust/issues/51114) (stable since 1.95.0) -//! > - [`#![feature(let_chains)]`](https://github.com/rust-lang/rust/issues/139951) (stable since 1.88.0) -//! > -//! > This list includes any unstable features used by direct & transitive dependencies (currently, none). -//! > -//! > You do not need to enable these in your own code, the list is for information only. -//! -//! ### Stability guarantees -//! -//! We run automated tests **every month** to ensure no fundamental changes affect this crate and -//! test every PR against the current nightly, as well as the current equivalent beta & stable. -//! If you find an issue before we do, please -//! [raise an issue on github](https://github.com/MusicalNinjaDad/try_v2/issues). -//! -//! ### MSRV -//! -//! For those of you working with a pinned nightly (etc.) this crate supports every version of -//! edition 2024 (rust 1.85.1 onwards, released as stable on 2025-03-18). We use -//! [autocfg](https://crates.io/crates/autocfg/) to seamlessly handle features which have been -//! stabilised since then. -//! -//! ## Currently untested (may work, may not ...): -//! -//! - `where` clauses -//! - storing `Fn`s in variants - use proc_macro::TokenStream as TokenStream1; use proc_macro2::TokenStream as TokenStream2; use proc_macro2_diagnostic::prelude::*; @@ -134,7 +21,7 @@ use parse::TryEnum; /// # #![feature(never_type)] /// # #![feature(try_trait_v2)] /// # #![feature(try_trait_v2_residual)] -/// # use try_v2::Try; +/// # use try_v2_derive::Try; /// #[derive(Try)] /// enum TestResult { /// Ok(T), @@ -201,7 +88,7 @@ use parse::TryEnum; /// # #![feature(never_type)] /// # #![feature(try_trait_v2)] /// # #![feature(try_trait_v2_residual)] -/// # use try_v2::Try; +/// # use try_v2_derive::Try; /// #[derive(Try)] /// enum TestResult<'t, 'e, T, E> { /// Ok(&'t T), @@ -318,7 +205,7 @@ fn impl_derive(input: TokenStream2) -> DiagnosticStream { /// # #![feature(never_type)] /// # #![feature(try_trait_v2)] /// # #![feature(try_trait_v2_residual)] -/// # use try_v2::{Try, Try_ConvertResult}; +/// # use try_v2_derive::{Try, Try_ConvertResult}; /// #[derive(Try, Try_ConvertResult)] /// #[must_use] /// enum TestResult { @@ -355,7 +242,7 @@ fn impl_derive(input: TokenStream2) -> DiagnosticStream { /// #![feature(try_trait_v2)] /// #![feature(try_trait_v2_residual)] /// -/// use try_v2::{Try, Try_ConvertResult}; +/// # use try_v2_derive::{Try, Try_ConvertResult}; /// /// #[derive(Try, Try_ConvertResult)] /// #[must_use] @@ -513,7 +400,7 @@ fn impl_try_methods(input: TokenStream2) -> DiagnosticStream { /// # #![feature(try_trait_v2)] /// # #![feature(try_trait_v2_residual)] /// # #![feature(iterator_try_collect)] -/// # use try_v2::{Try, Try_Iterator}; +/// # use try_v2_derive::{Try, Try_Iterator}; /// # use TestResult::{Ok, TestsFailed, OtherError}; /// #[derive(Try, Try_Iterator)] /// #[must_use] From 3cb793481fdf55e6cdb2bf088d7acfceb36b5ee3 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 14:35:09 +0000 Subject: [PATCH 03/39] fix doc link --- crates/try_v2_derive/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/try_v2_derive/src/lib.rs b/crates/try_v2_derive/src/lib.rs index 479f868..a2eb755 100644 --- a/crates/try_v2_derive/src/lib.rs +++ b/crates/try_v2_derive/src/lib.rs @@ -14,7 +14,14 @@ use parse::TryEnum; #[proc_macro_derive(Try)] /// Derives [try_trait_v2](https://rust-lang.github.io/rfcs/3058-try-trait-v2.html) /// -/// See the [crate level documentation](crate) for restrictions and detailed examples +/// ## Limitations on the annotated type +/// +/// - must be an `enum` +/// - must have _at least one_ generic type +/// - the _first_ generic type must be the `Output` type (produced when not short-circuiting) +/// - the output variant (does not short-circuit) must be the _first_ variant and store the output +/// type as the _only unnamed_ field +/// - no other variant can store the Output type (TODO #72 add a nice error message) /// /// ## Derived code /// ``` From ce2855ed91624fc988a89f1c566c002b55154c21 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 14:50:21 +0000 Subject: [PATCH 04/39] Transform::transpose --- crates/try_v2/src/lib.rs | 6 +++ crates/try_v2/src/transform.rs | 87 ++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 crates/try_v2/src/transform.rs diff --git a/crates/try_v2/src/lib.rs b/crates/try_v2/src/lib.rs index 4306030..d1b12f6 100644 --- a/crates/try_v2/src/lib.rs +++ b/crates/try_v2/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(try_trait_v2)] + //! Provides a derive macro for [Try] & optionally [Try_ConvertResult] for interconversion with //! `std::result::Result` and [Try_Iterator] for iterating over `IntoIterator` and collecting from //! `FromIterator` analog to how `Result` & `Option` do this. @@ -113,3 +115,7 @@ #[doc(inline)] pub use try_v2_derive::*; + +mod transform; +#[doc(inline)] +pub use transform::Transform; diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs new file mode 100644 index 0000000..24adeb8 --- /dev/null +++ b/crates/try_v2/src/transform.rs @@ -0,0 +1,87 @@ +use std::ops::{ControlFlow, FromResidual, Try}; + +pub trait Transform +where + Self: Try + Sized, +{ + /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. + fn transpose(self) -> U + where + Self::Output: Try, + U: Try, + U::Output: Try, + { + match self.branch() { + ControlFlow::Continue(inner_u) => match inner_u.branch() { + ControlFlow::Continue(val) => { + let inner_t = Try::from_output(val); + U::from_output(inner_t) + } + ControlFlow::Break(u_residual) => U::from_residual(u_residual), + }, + ControlFlow::Break(t_residual) => { + let inner_t = FromResidual::from_residual(t_residual); + U::from_output(inner_t) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + impl Transform for Option {} + impl Transform for Result {} + + mod transpose { + use super::*; + #[test] + fn ok_some() { + let ok_some: Result, String> = Ok(Some(5)); + let stdlib: Option> = ok_some.clone().transpose(); + let custom: Option> = Transform::transpose(ok_some); + assert_eq!(stdlib, custom) + } + + #[test] + fn ok_none() { + let ok_none: Result, String> = Ok(None); + let stdlib = ok_none.clone().transpose(); + let custom = Transform::transpose(ok_none); + assert_eq!(stdlib, custom) + } + + #[test] + fn err() { + let err: Result, String> = Err("Oops".to_string()); + let stdlib = err.clone().transpose(); + let custom = Transform::transpose(err); + assert_eq!(stdlib, custom) + } + + #[test] + fn some_ok() { + let some_ok: Option> = Some(Ok(5)); + let stdlib: Result, String> = some_ok.clone().transpose(); + let custom: Result, String> = Transform::transpose(some_ok); + assert_eq!(stdlib, custom) + } + + #[test] + fn some_err() { + let some_err: Option> = Some(Err("Oops".to_string())); + let stdlib = some_err.clone().transpose(); + let custom = Transform::transpose(some_err); + assert_eq!(stdlib, custom) + } + + #[test] + fn none() { + let none: Option> = None; + let stdlib = none.clone().transpose(); + let custom = Transform::transpose(none); + assert_eq!(stdlib, custom) + } + } +} From 9e8b7f9c2fbae0fdee4af3cc93e1c4f4bd18ba0f Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 15:17:51 +0000 Subject: [PATCH 05/39] Transform::flatten --- crates/try_v2/src/transform.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 24adeb8..6441201 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -4,7 +4,17 @@ pub trait Transform where Self: Try + Sized, { - /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. + /// removes one level of nesting, converting `Foo>` to `Foo` + /// or from `Foo>` to `Bar` if suitable residual interconversion is implemented. + fn flatten(self) -> U + where + Self: Try, + U: FromResidual, + { + self? + } + + /// converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. fn transpose(self) -> U where Self::Output: Try, @@ -34,6 +44,18 @@ mod tests { impl Transform for Option {} impl Transform for Result {} + mod flatten { + use super::*; + + #[test] + fn some_some() { + let some_5 = Some(Some(5)); + let stdlib = some_5.flatten(); + let custom = Transform::flatten(some_5); + assert_eq!(stdlib, custom) + } + } + mod transpose { use super::*; #[test] From 4a516675f54ff13a815d9306f2295ff0a4533aaa Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 17:24:10 +0000 Subject: [PATCH 06/39] widen transpose bounds to better leverage interconversion --- crates/try_v2/src/transform.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 6441201..4f38fb3 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -15,23 +15,23 @@ where } /// converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. - fn transpose(self) -> U + fn transpose(self) -> U where - Self::Output: Try, - U: Try, - U::Output: Try, + Self::Output: Try, + U: Try + FromResidual<::Residual>, + U::Output: Try + FromResidual, { match self.branch() { ControlFlow::Continue(inner_u) => match inner_u.branch() { ControlFlow::Continue(val) => { let inner_t = Try::from_output(val); - U::from_output(inner_t) + Try::from_output(inner_t) } - ControlFlow::Break(u_residual) => U::from_residual(u_residual), + ControlFlow::Break(u_residual) => FromResidual::from_residual(u_residual), }, ControlFlow::Break(t_residual) => { let inner_t = FromResidual::from_residual(t_residual); - U::from_output(inner_t) + Try::from_output(inner_t) } } } From 67c61fb40e6975bd935d551db335ef899ba100d7 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 17:27:53 +0000 Subject: [PATCH 07/39] not re ambiguity --- crates/try_v2/src/transform.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 4f38fb3..e509bd1 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -20,6 +20,7 @@ where Self::Output: Try, U: Try + FromResidual<::Residual>, U::Output: Try + FromResidual, + // TODO: Consider ambiguity risk analog try_reduce { match self.branch() { ControlFlow::Continue(inner_u) => match inner_u.branch() { From cb7fac83501109721e40aabb499cdf70a7d08651 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 17:46:12 +0000 Subject: [PATCH 08/39] inspect --- crates/try_v2/src/transform.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index e509bd1..39e75bb 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -4,7 +4,7 @@ pub trait Transform where Self: Try + Sized, { - /// removes one level of nesting, converting `Foo>` to `Foo` + /// Removes one level of nesting, converting `Foo>` to `Foo` /// or from `Foo>` to `Bar` if suitable residual interconversion is implemented. fn flatten(self) -> U where @@ -14,7 +14,17 @@ where self? } - /// converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. + /// Calls a function with a reference to the contained value. Returns the original Self + fn inspect(self, f: F) -> Self + where + F: FnOnce(&Self::Output), + { + let val = self?; + f(&val); + Try::from_output(val) + } + + /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. fn transpose(self) -> U where Self::Output: Try, @@ -57,6 +67,23 @@ mod tests { } } + mod inspect { + use super::*; + use std::fmt::Write; + + #[test] + fn some_5() { + let some_5 = Some(5); + let mut text = String::new(); + some_5.inspect(|x| write!(text, "{x}").expect("failed to write {x} to text")); + assert_eq!(text, "5"); + Transform::inspect(some_5, |x| { + write!(text, "{x}").expect("failed to write {x} to text") + }); + assert_eq!(text, "55"); + } + } + mod transpose { use super::*; #[test] From c0130c040dc9f3191334b94f454fb61fe77aa2c7 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 17:57:42 +0000 Subject: [PATCH 09/39] map --- crates/try_v2/src/transform.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 39e75bb..7dabab7 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -24,6 +24,17 @@ where Try::from_output(val) } + /// Applys a function to the contained value + fn map(self, f: F) -> U + where + U: Try + FromResidual, + F: FnOnce(Self::Output) -> U::Output, + { + let val = self?; + let mapped = f(val); + Try::from_output(mapped) + } + /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. fn transpose(self) -> U where @@ -84,6 +95,18 @@ mod tests { } } + mod map { + use super::*; + + #[test] + fn some_5() { + let some_5 = Some(5); + let stdlib = some_5.map(|x| x + 1); + let custom = Transform::map(some_5, |x| x + 1); + assert_eq!(stdlib, custom); + } + } + mod transpose { use super::*; #[test] From 62955897feba675c433b6ebd4a4f64fd903e370a Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 18:19:01 +0000 Subject: [PATCH 10/39] map_or --- crates/try_v2/src/transform.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 7dabab7..32a197d 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -35,6 +35,16 @@ where Try::from_output(mapped) } + fn map_or(self, default: U, f: F) -> U + where + F: FnOnce(Self::Output) -> U, + { + match self.branch() { + ControlFlow::Continue(val) => f(val), + ControlFlow::Break(_) => default, + } + } + /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. fn transpose(self) -> U where @@ -99,12 +109,20 @@ mod tests { use super::*; #[test] - fn some_5() { + fn map() { let some_5 = Some(5); let stdlib = some_5.map(|x| x + 1); let custom = Transform::map(some_5, |x| x + 1); assert_eq!(stdlib, custom); } + + #[test] + fn map_or_some() { + let some_5 = Some(5); + let stdlib = some_5.map_or(0, |x| x + 1); + let custom = Transform::map_or(some_5, 0, |x| x + 1); + assert_eq!(stdlib, custom); + } } mod transpose { From 1d975b8a4c598ab6ce419a0b2212ece3a20ae6ef Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 18:20:18 +0000 Subject: [PATCH 11/39] test map_or None --- crates/try_v2/src/transform.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 32a197d..9a5a65b 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -123,6 +123,14 @@ mod tests { let custom = Transform::map_or(some_5, 0, |x| x + 1); assert_eq!(stdlib, custom); } + + #[test] + fn map_or_none() { + let some_5: Option = None; + let stdlib = some_5.map_or(0, |x| x + 1); + let custom = Transform::map_or(some_5, 0, |x| x + 1); + assert_eq!(stdlib, custom); + } } mod transpose { From e04fe38d8c852e5c57d0046ccfee2363270c3653 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 18:24:38 +0000 Subject: [PATCH 12/39] map_or_else --- crates/try_v2/src/transform.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 9a5a65b..ea5ee8a 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -45,6 +45,17 @@ where } } + fn map_or_else(self, default: D, f: F) -> U + where + D: FnOnce() -> U, + F: FnOnce(Self::Output) -> U, + { + match self.branch() { + ControlFlow::Continue(val) => f(val), + ControlFlow::Break(_) => default(), + } + } + /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. fn transpose(self) -> U where @@ -131,6 +142,22 @@ mod tests { let custom = Transform::map_or(some_5, 0, |x| x + 1); assert_eq!(stdlib, custom); } + + #[test] + fn map_or_else_some() { + let some_5 = Some(5); + let stdlib = some_5.map_or_else(|| 1 + 1, |x| x + 1); + let custom = Transform::map_or_else(some_5, || 1 + 1, |x| x + 1); + assert_eq!(stdlib, custom); + } + + #[test] + fn map_or_else_none() { + let some_5: Option = None; + let stdlib = some_5.map_or_else(|| 1 + 1, |x| x + 1); + let custom = Transform::map_or_else(some_5, || 1 + 1, |x| x + 1); + assert_eq!(stdlib, custom); + } } mod transpose { From 3fe14b16f9aa6fce06d11f1fd17ed651ff602262 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 18:34:17 +0000 Subject: [PATCH 13/39] ambiguous zip --- crates/try_v2/src/transform.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index ea5ee8a..33a307b 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -78,6 +78,18 @@ where } } } + + fn zip(self, other: U) -> Z + where + U: Try, + Z: Try + + FromResidual + + FromResidual, + { + let v1 = self?; + let v2 = other?; + Try::from_output((v1, v2)) + } } #[cfg(test)] @@ -210,4 +222,17 @@ mod tests { assert_eq!(stdlib, custom) } } + + mod zip { + use super::*; + + #[test] + fn some_some() { + let some_1 = Some(1); + let some_x = Some("x"); + let stdlib: Option<(i32, &str)> = some_1.zip(some_x); + let custom: Option<(i32, &str)> = Transform::zip(some_1, some_x); + assert_eq!(stdlib, custom); + } + } } From 94e698e6fa171c8361d2f9cfa53311040335434d Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Mon, 1 Jun 2026 18:37:16 +0000 Subject: [PATCH 14/39] unambiguous zip --- crates/try_v2/src/lib.rs | 1 + crates/try_v2/src/transform.rs | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/try_v2/src/lib.rs b/crates/try_v2/src/lib.rs index d1b12f6..3428b3b 100644 --- a/crates/try_v2/src/lib.rs +++ b/crates/try_v2/src/lib.rs @@ -1,4 +1,5 @@ #![feature(try_trait_v2)] +#![feature(try_trait_v2_residual)] //! Provides a derive macro for [Try] & optionally [Try_ConvertResult] for interconversion with //! `std::result::Result` and [Try_Iterator] for iterating over `IntoIterator` and collecting from diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 33a307b..583ba16 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -1,4 +1,4 @@ -use std::ops::{ControlFlow, FromResidual, Try}; +use std::ops::{ControlFlow, FromResidual, Residual, Try}; pub trait Transform where @@ -85,6 +85,7 @@ where Z: Try + FromResidual + FromResidual, + Self::Residual: Residual, { let v1 = self?; let v2 = other?; @@ -230,8 +231,8 @@ mod tests { fn some_some() { let some_1 = Some(1); let some_x = Some("x"); - let stdlib: Option<(i32, &str)> = some_1.zip(some_x); - let custom: Option<(i32, &str)> = Transform::zip(some_1, some_x); + let stdlib = some_1.zip(some_x); + let custom = Transform::zip(some_1, some_x); assert_eq!(stdlib, custom); } } From 866e46805eeb9b8e6ff91e9fb8d285778ceac847 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 05:18:39 +0000 Subject: [PATCH 15/39] unamabiguous map --- crates/try_v2/src/transform.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 583ba16..2bfc207 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -24,11 +24,13 @@ where Try::from_output(val) } - /// Applys a function to the contained value - fn map(self, f: F) -> U + /// Applys a function to the contained value converting `T` -> `U` then + /// returns the canonical TryType for Self with Output `U` + fn map(self, f: F) -> X where - U: Try + FromResidual, - F: FnOnce(Self::Output) -> U::Output, + F: FnOnce(Self::Output) -> U, + X: Try + FromResidual, + Self::Residual: Residual, { let val = self?; let mapped = f(val); From 3595da45de3497996b7c92680999bf676f4915dc Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 05:56:41 +0000 Subject: [PATCH 16/39] longhand BART, FOOT as helper --- crates/try_v2/src/transform.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 2bfc207..e2b08f3 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -59,12 +59,12 @@ where } /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. - fn transpose(self) -> U + fn transpose(self) -> U where - Self::Output: Try, - U: Try + FromResidual<::Residual>, - U::Output: Try + FromResidual, - // TODO: Consider ambiguity risk analog try_reduce + Self: Try, + BART: Try, + FOOT: Try + FromResidual, + U: Try + FromResidual, { match self.branch() { ControlFlow::Continue(inner_u) => match inner_u.branch() { @@ -190,7 +190,7 @@ mod tests { let ok_none: Result, String> = Ok(None); let stdlib = ok_none.clone().transpose(); let custom = Transform::transpose(ok_none); - assert_eq!(stdlib, custom) + // assert_eq!(stdlib, custom) } #[test] From ca08868ce44c517e427d6581fc38edbe4e2f7ffd Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 05:57:52 +0000 Subject: [PATCH 17/39] infer option --- crates/try_v2/src/transform.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index e2b08f3..1cbc97a 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -65,6 +65,7 @@ where BART: Try, FOOT: Try + FromResidual, U: Try + FromResidual, + BART::Residual: Residual, { match self.branch() { ControlFlow::Continue(inner_u) => match inner_u.branch() { From ab331589c04970de0c9a3b164fc4f9977523917c Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 06:00:10 +0000 Subject: [PATCH 18/39] unambiguous transpose --- crates/try_v2/src/transform.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 1cbc97a..c9c51c7 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -66,6 +66,7 @@ where FOOT: Try + FromResidual, U: Try + FromResidual, BART::Residual: Residual, + Self::Residual: Residual, { match self.branch() { ControlFlow::Continue(inner_u) => match inner_u.branch() { @@ -191,7 +192,7 @@ mod tests { let ok_none: Result, String> = Ok(None); let stdlib = ok_none.clone().transpose(); let custom = Transform::transpose(ok_none); - // assert_eq!(stdlib, custom) + assert_eq!(stdlib, custom) } #[test] From b7c72a3bfcadd0075f3daecf864064e7f730ba56 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 06:04:45 +0000 Subject: [PATCH 19/39] remove BART & FOOT --- crates/try_v2/src/transform.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index c9c51c7..5aaefce 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -59,14 +59,13 @@ where } /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. - fn transpose(self) -> U + fn transpose(self) -> U where - Self: Try, - BART: Try, - FOOT: Try + FromResidual, - U: Try + FromResidual, - BART::Residual: Residual, - Self::Residual: Residual, + Self::Output: Try, + ::Residual: Residual, + U: Try + FromResidual<::Residual>, + U::Output: Try + FromResidual, + Self::Residual: Residual, { match self.branch() { ControlFlow::Continue(inner_u) => match inner_u.branch() { From c22a37a3a426c8b4b9375005b8bf36909db16f49 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 06:06:34 +0000 Subject: [PATCH 20/39] add V for readability --- crates/try_v2/src/transform.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 5aaefce..61233d2 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -59,10 +59,11 @@ where } /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. - fn transpose(self) -> U + fn transpose(self) -> U where - Self::Output: Try, - ::Residual: Residual, + Self: Try, + V: Try, + V::Residual: Residual, U: Try + FromResidual<::Residual>, U::Output: Try + FromResidual, Self::Residual: Residual, From e1a09e9aafb07c4b5bb0f2bb679baa4d50f49601 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 06:26:18 +0000 Subject: [PATCH 21/39] comments to help future me --- crates/try_v2/src/transform.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 61233d2..da03f0f 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -59,13 +59,22 @@ where } /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. + /// + /// ## Note + /// Return types are canonical TryTypes, for asymetrical cases this may not be `Bar` & `Foo` fn transpose(self) -> U where + // Foo> Self: Try, + // Bar V: Try, - V::Residual: Residual, + // Bar> U: Try + FromResidual<::Residual>, + // Foo U::Output: Try + FromResidual, + // U *is* the canonical TryType for `Bar>` + V::Residual: Residual, + // U *wraps* the canonical TryType for `Foo` Self::Residual: Residual, { match self.branch() { From e3313b969aaa9389aa3ec64be130af74ddd60f61 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 06:33:41 +0000 Subject: [PATCH 22/39] Document specifics of zip --- crates/try_v2/src/transform.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index da03f0f..4e8fd59 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -92,6 +92,8 @@ where } } + /// Combines a Foo with a Bar into a Foo<(T,U)> where residual interconversion + /// is available from Bar->Foo. Returns the canonical TryType. fn zip(self, other: U) -> Z where U: Try, From 6ef957a60e1663f0cf2a29ed1540d31dc63a7c79 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 06:49:40 +0000 Subject: [PATCH 23/39] zip_with --- crates/try_v2/src/lib.rs | 1 + crates/try_v2/src/transform.rs | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/crates/try_v2/src/lib.rs b/crates/try_v2/src/lib.rs index 3428b3b..fe0c88f 100644 --- a/crates/try_v2/src/lib.rs +++ b/crates/try_v2/src/lib.rs @@ -1,5 +1,6 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] +#![cfg_attr(test, feature(option_zip))] //! Provides a derive macro for [Try] & optionally [Try_ConvertResult] for interconversion with //! `std::result::Result` and [Try_Iterator] for iterating over `IntoIterator` and collecting from diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 4e8fd59..d5f6c0c 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -93,7 +93,7 @@ where } /// Combines a Foo with a Bar into a Foo<(T,U)> where residual interconversion - /// is available from Bar->Foo. Returns the canonical TryType. + /// is available from Bar->Foo. Returns the canonical TryType based upon Foo. fn zip(self, other: U) -> Z where U: Try, @@ -106,6 +106,22 @@ where let v2 = other?; Try::from_output((v1, v2)) } + + /// Applies function `f` to the values inside Foo & Bar where residual interconversion + /// is available from Bar->Foo. Returns the canonical TryType based upon Foo. + /// + /// TODO: #[unstable(feature = "option_zip", issue = "70086")] + fn zip_with(self, other: U, f: F) -> Z + where + U: Try, + Z: Try + FromResidual + FromResidual, + Self::Residual: Residual, + F: FnOnce(Self::Output, U::Output) -> R, + { + let v1 = self?; + let v2 = other?; + Try::from_output(f(v1, v2)) + } } #[cfg(test)] @@ -250,5 +266,14 @@ mod tests { let custom = Transform::zip(some_1, some_x); assert_eq!(stdlib, custom); } + + #[test] + fn some_some_with() { + let some_1 = Some(-1_i32); + let some_2 = Some(2_u16); + let stdlib = some_1.zip_with(some_2, |x, y| x + i32::from(y)); + let custom = Transform::zip_with(some_1, some_2, |x, y| x + i32::from(y)); + assert_eq!(stdlib, custom); + } } } From f486d8438c29402ce9cb92d2447e83b6030e59dc Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 07:07:29 +0000 Subject: [PATCH 24/39] output --- crates/try_v2/src/transform.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index d5f6c0c..a9a0474 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -24,6 +24,17 @@ where Try::from_output(val) } + /// Extracts the contained value `v` returning `Some(v)`, or `None` in the case of a Residual + fn output(self) -> Option + where + Self: Try, + { + match self.branch() { + ControlFlow::Continue(val) => Some(val), + ControlFlow::Break(_) => None, + } + } + /// Applys a function to the contained value converting `T` -> `U` then /// returns the canonical TryType for Self with Output `U` fn map(self, f: F) -> X @@ -160,6 +171,18 @@ mod tests { } } + mod output { + use super::*; + + #[test] + fn ok() { + let ok_5: Result<_, ()> = Ok(5); + let stdlib = ok_5.ok(); + let custom = ok_5.output(); + assert_eq!(stdlib, custom); + } + } + mod map { use super::*; From 58deacdadc02d793ce921e10ad0524534d156b66 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 07:23:24 +0000 Subject: [PATCH 25/39] trait doc --- crates/try_v2/src/transform.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index a9a0474..8be9164 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -1,5 +1,16 @@ use std::ops::{ControlFlow, FromResidual, Residual, Try}; +/// Methods for transforming TryTypes. Inspired by the methods provided on `Option` & `Result` +/// +/// ## Note +/// +/// - Methods which act on the contained value are only available for the Output case. TryTypes +/// are recommended to directly implement equivalent methods for Residual cases with suitable +/// naming. E.g. we provide a `.map()` but not a `.map_err()` equivalent as multiple such +/// methods may be needed and no standardised naming makes sense. +/// - Methods which act on the contained value will extract a value of type `Output`and return the +/// canonical TryType for the new Output. This is usually the expected behaviour but can lead to +/// a different value type or resulting TryType where Try is not implemented symmetrically. pub trait Transform where Self: Try + Sized, From c0fb7137b28652a4745e5ffb3a36eb60f7d1526f Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 07:24:48 +0000 Subject: [PATCH 26/39] workspace resolver for 2024 edition --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index ee3bfe0..35f9420 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,6 @@ [workspace] +edition = "2024" +resolver = "3" members = ["crates/*"] [workspace.dependencies] From 64ce39cc20c2c93ea03fdcf424c9d8a02ec7cc4f Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 07:33:19 +0000 Subject: [PATCH 27/39] doc formatting --- crates/try_v2/src/transform.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 8be9164..4bff8b3 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -4,13 +4,13 @@ use std::ops::{ControlFlow, FromResidual, Residual, Try}; /// /// ## Note /// -/// - Methods which act on the contained value are only available for the Output case. TryTypes -/// are recommended to directly implement equivalent methods for Residual cases with suitable +/// - Methods which act on the contained value are only available for the *Output* case. TryTypes +/// are recommended to directly implement equivalent methods for *Residual* cases with suitable /// naming. E.g. we provide a `.map()` but not a `.map_err()` equivalent as multiple such /// methods may be needed and no standardised naming makes sense. -/// - Methods which act on the contained value will extract a value of type `Output`and return the -/// canonical TryType for the new Output. This is usually the expected behaviour but can lead to -/// a different value type or resulting TryType where Try is not implemented symmetrically. +/// - Methods which act on the contained value will extract a value of type `Output` and return the +/// *canonical TryType* for the new Output. This is usually the expected behaviour but can lead to +/// a different value type or resulting TryType where `Try` is not implemented symmetrically. pub trait Transform where Self: Try + Sized, @@ -25,7 +25,7 @@ where self? } - /// Calls a function with a reference to the contained value. Returns the original Self + /// Calls a function with a reference to the contained value. Returns the original `Self` fn inspect(self, f: F) -> Self where F: FnOnce(&Self::Output), @@ -47,7 +47,7 @@ where } /// Applys a function to the contained value converting `T` -> `U` then - /// returns the canonical TryType for Self with Output `U` + /// returns the canonical TryType for `Self` with Output `U` fn map(self, f: F) -> X where F: FnOnce(Self::Output) -> U, @@ -82,8 +82,9 @@ where /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. /// - /// ## Note - /// Return types are canonical TryTypes, for asymetrical cases this may not be `Bar` & `Foo` + /// # Note + /// + /// - Return types are *canonical TryTypes*, for asymetrical cases this may not be `Bar` & `Foo` fn transpose(self) -> U where // Foo> @@ -114,8 +115,8 @@ where } } - /// Combines a Foo with a Bar into a Foo<(T,U)> where residual interconversion - /// is available from Bar->Foo. Returns the canonical TryType based upon Foo. + /// Combines a `Foo` with a `Bar` into a `Foo<(T,U)>` where residual interconversion + /// is available from `Bar->Foo`. Returns the *canonical TryType* based upon `Foo`. fn zip(self, other: U) -> Z where U: Try, @@ -129,8 +130,8 @@ where Try::from_output((v1, v2)) } - /// Applies function `f` to the values inside Foo & Bar where residual interconversion - /// is available from Bar->Foo. Returns the canonical TryType based upon Foo. + /// Applies function `f` to the values inside `Foo` & `Bar` where residual interconversion + /// is available from `Bar->Foo`. Returns the *canonical TryType* based upon `Foo`. /// /// TODO: #[unstable(feature = "option_zip", issue = "70086")] fn zip_with(self, other: U, f: F) -> Z From f84f5ccfb4a658e05d0fc21613ebbd965ae7264e Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 07:50:03 +0000 Subject: [PATCH 28/39] standardised generic params --- crates/try_v2/src/transform.rs | 46 ++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 4bff8b3..d49c57c 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -9,18 +9,26 @@ use std::ops::{ControlFlow, FromResidual, Residual, Try}; /// naming. E.g. we provide a `.map()` but not a `.map_err()` equivalent as multiple such /// methods may be needed and no standardised naming makes sense. /// - Methods which act on the contained value will extract a value of type `Output` and return the -/// *canonical TryType* for the new Output. This is usually the expected behaviour but can lead to -/// a different value type or resulting TryType where `Try` is not implemented symmetrically. +/// *canonical TryType* for the new Output. This is identifiable by the generic type `X` in the +/// method signature. This is usually the expected behaviour but can lead to a different value +/// type or resulting TryType where `Try` is not implemented symmetrically. +/// - Generic type conventions used in signatures (in standard order): +/// - `X` the *canonical TryType* returned +/// - `T` the `Output` type for `Self` +/// - `U` the primary *other* type. +/// - `F` a function/closure passed as a parameter +/// - `G` the return type of `F` +/// - `R` *never used* to avoid confusion with "Residual". pub trait Transform where Self: Try + Sized, { /// Removes one level of nesting, converting `Foo>` to `Foo` /// or from `Foo>` to `Bar` if suitable residual interconversion is implemented. - fn flatten(self) -> U + fn flatten(self) -> X where - Self: Try, - U: FromResidual, + Self: Try, + X: FromResidual, { self? } @@ -85,20 +93,20 @@ where /// # Note /// /// - Return types are *canonical TryTypes*, for asymetrical cases this may not be `Bar` & `Foo` - fn transpose(self) -> U + fn transpose(self) -> X where // Foo> - Self: Try, + Self: Try, // Bar - V: Try, + U: Try, // Bar> - U: Try + FromResidual<::Residual>, + X: Try + FromResidual<::Residual>, // Foo - U::Output: Try + FromResidual, + X::Output: Try + FromResidual, // U *is* the canonical TryType for `Bar>` - V::Residual: Residual, + U::Residual: Residual, // U *wraps* the canonical TryType for `Foo` - Self::Residual: Residual, + Self::Residual: Residual, { match self.branch() { ControlFlow::Continue(inner_u) => match inner_u.branch() { @@ -117,13 +125,13 @@ where /// Combines a `Foo` with a `Bar` into a `Foo<(T,U)>` where residual interconversion /// is available from `Bar->Foo`. Returns the *canonical TryType* based upon `Foo`. - fn zip(self, other: U) -> Z + fn zip(self, other: U) -> X where U: Try, - Z: Try + X: Try + FromResidual + FromResidual, - Self::Residual: Residual, + Self::Residual: Residual, { let v1 = self?; let v2 = other?; @@ -134,12 +142,12 @@ where /// is available from `Bar->Foo`. Returns the *canonical TryType* based upon `Foo`. /// /// TODO: #[unstable(feature = "option_zip", issue = "70086")] - fn zip_with(self, other: U, f: F) -> Z + fn zip_with(self, other: U, f: F) -> X where U: Try, - Z: Try + FromResidual + FromResidual, - Self::Residual: Residual, - F: FnOnce(Self::Output, U::Output) -> R, + X: Try + FromResidual + FromResidual, + Self::Residual: Residual, + F: FnOnce(Self::Output, U::Output) -> G, { let v1 = self?; let v2 = other?; From e7b38f89a6448713e4ea54d3ccf19224a978d8cc Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 07:55:17 +0000 Subject: [PATCH 29/39] consistently use `V` for other TryType --- crates/try_v2/src/transform.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index d49c57c..75ec839 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -14,8 +14,9 @@ use std::ops::{ControlFlow, FromResidual, Residual, Try}; /// type or resulting TryType where `Try` is not implemented symmetrically. /// - Generic type conventions used in signatures (in standard order): /// - `X` the *canonical TryType* returned +/// - `V` the other TryType /// - `T` the `Output` type for `Self` -/// - `U` the primary *other* type. +/// - `U` the other `Output` type /// - `F` a function/closure passed as a parameter /// - `G` the return type of `F` /// - `R` *never used* to avoid confusion with "Residual". @@ -93,18 +94,18 @@ where /// # Note /// /// - Return types are *canonical TryTypes*, for asymetrical cases this may not be `Bar` & `Foo` - fn transpose(self) -> X + fn transpose(self) -> X where // Foo> - Self: Try, + Self: Try, // Bar - U: Try, + V: Try, // Bar> X: Try + FromResidual<::Residual>, // Foo X::Output: Try + FromResidual, // U *is* the canonical TryType for `Bar>` - U::Residual: Residual, + V::Residual: Residual, // U *wraps* the canonical TryType for `Foo` Self::Residual: Residual, { @@ -125,12 +126,12 @@ where /// Combines a `Foo` with a `Bar` into a `Foo<(T,U)>` where residual interconversion /// is available from `Bar->Foo`. Returns the *canonical TryType* based upon `Foo`. - fn zip(self, other: U) -> X + fn zip(self, other: V) -> X where - U: Try, - X: Try + V: Try, + X: Try + FromResidual - + FromResidual, + + FromResidual, Self::Residual: Residual, { let v1 = self?; @@ -142,12 +143,12 @@ where /// is available from `Bar->Foo`. Returns the *canonical TryType* based upon `Foo`. /// /// TODO: #[unstable(feature = "option_zip", issue = "70086")] - fn zip_with(self, other: U, f: F) -> X + fn zip_with(self, other: V, f: F) -> X where - U: Try, - X: Try + FromResidual + FromResidual, + V: Try, + X: Try + FromResidual + FromResidual, Self::Residual: Residual, - F: FnOnce(Self::Output, U::Output) -> G, + F: FnOnce(Self::Output, V::Output) -> G, { let v1 = self?; let v2 = other?; From 4d0e041aeb18e980b7d1752e721468d7845c8f9d Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 08:00:57 +0000 Subject: [PATCH 30/39] consistently use U & V --- crates/try_v2/src/transform.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 75ec839..c77c70b 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -26,10 +26,10 @@ where { /// Removes one level of nesting, converting `Foo>` to `Foo` /// or from `Foo>` to `Bar` if suitable residual interconversion is implemented. - fn flatten(self) -> X + fn flatten(self) -> V where - Self: Try, - X: FromResidual, + Self: Try, + V: FromResidual, { self? } @@ -89,25 +89,25 @@ where } } - /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. + /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. /// /// # Note /// /// - Return types are *canonical TryTypes*, for asymetrical cases this may not be `Bar` & `Foo` - fn transpose(self) -> X + fn transpose(self) -> X where // Foo> Self: Try, // Bar - V: Try, + V: Try, // Bar> X: Try + FromResidual<::Residual>, // Foo - X::Output: Try + FromResidual, + X::Output: Try + FromResidual, // U *is* the canonical TryType for `Bar>` V::Residual: Residual, // U *wraps* the canonical TryType for `Foo` - Self::Residual: Residual, + Self::Residual: Residual, { match self.branch() { ControlFlow::Continue(inner_u) => match inner_u.branch() { @@ -126,10 +126,10 @@ where /// Combines a `Foo` with a `Bar` into a `Foo<(T,U)>` where residual interconversion /// is available from `Bar->Foo`. Returns the *canonical TryType* based upon `Foo`. - fn zip(self, other: V) -> X + fn zip(self, other: V) -> X where - V: Try, - X: Try + V: Try, + X: Try + FromResidual + FromResidual, Self::Residual: Residual, From 5a9db68e1b52099b47cf9b28c5176da3c2dd9fa9 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 08:29:47 +0000 Subject: [PATCH 31/39] Use Y for other TryType --- crates/try_v2/src/transform.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index c77c70b..7831a35 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -14,7 +14,7 @@ use std::ops::{ControlFlow, FromResidual, Residual, Try}; /// type or resulting TryType where `Try` is not implemented symmetrically. /// - Generic type conventions used in signatures (in standard order): /// - `X` the *canonical TryType* returned -/// - `V` the other TryType +/// - `Y` the other TryType /// - `T` the `Output` type for `Self` /// - `U` the other `Output` type /// - `F` a function/closure passed as a parameter @@ -26,10 +26,10 @@ where { /// Removes one level of nesting, converting `Foo>` to `Foo` /// or from `Foo>` to `Bar` if suitable residual interconversion is implemented. - fn flatten(self) -> V + fn flatten(self) -> Y where - Self: Try, - V: FromResidual, + Self: Try, + Y: FromResidual, { self? } @@ -94,19 +94,19 @@ where /// # Note /// /// - Return types are *canonical TryTypes*, for asymetrical cases this may not be `Bar` & `Foo` - fn transpose(self) -> X + fn transpose(self) -> X where // Foo> - Self: Try, + Self: Try, // Bar - V: Try, + Y: Try, // Bar> X: Try + FromResidual<::Residual>, // Foo X::Output: Try + FromResidual, - // U *is* the canonical TryType for `Bar>` - V::Residual: Residual, - // U *wraps* the canonical TryType for `Foo` + // X *is* the canonical TryType for `Bar>` + Y::Residual: Residual, + // X *wraps* the canonical TryType for `Foo` Self::Residual: Residual, { match self.branch() { @@ -126,12 +126,12 @@ where /// Combines a `Foo` with a `Bar` into a `Foo<(T,U)>` where residual interconversion /// is available from `Bar->Foo`. Returns the *canonical TryType* based upon `Foo`. - fn zip(self, other: V) -> X + fn zip(self, other: Y) -> X where - V: Try, + Y: Try, X: Try + FromResidual - + FromResidual, + + FromResidual, Self::Residual: Residual, { let v1 = self?; @@ -143,12 +143,12 @@ where /// is available from `Bar->Foo`. Returns the *canonical TryType* based upon `Foo`. /// /// TODO: #[unstable(feature = "option_zip", issue = "70086")] - fn zip_with(self, other: V, f: F) -> X + fn zip_with(self, other: Y, f: F) -> X where - V: Try, - X: Try + FromResidual + FromResidual, + Y: Try, + X: Try + FromResidual + FromResidual, Self::Residual: Residual, - F: FnOnce(Self::Output, V::Output) -> G, + F: FnOnce(Self::Output, Y::Output) -> G, { let v1 = self?; let v2 = other?; From 4ae6cdf981162d2b66a13d64b099de26feb2de12 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 08:33:29 +0000 Subject: [PATCH 32/39] remove unnecessary `U`s --- crates/try_v2/src/transform.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 7831a35..59e237a 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -89,25 +89,25 @@ where } } - /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. + /// Converts from a `Foo>` to a `Bar>` where both `Foo` & `Bar` are `Try`. /// /// # Note /// /// - Return types are *canonical TryTypes*, for asymetrical cases this may not be `Bar` & `Foo` - fn transpose(self) -> X + fn transpose(self) -> X where // Foo> Self: Try, // Bar - Y: Try, + Y: Try, // Bar> X: Try + FromResidual<::Residual>, - // Foo - X::Output: Try + FromResidual, + // Foo: Try + FromResidual> + X::Output: Try + FromResidual, // X *is* the canonical TryType for `Bar>` Y::Residual: Residual, // X *wraps* the canonical TryType for `Foo` - Self::Residual: Residual, + Self::Residual: Residual, { match self.branch() { ControlFlow::Continue(inner_u) => match inner_u.branch() { @@ -126,10 +126,10 @@ where /// Combines a `Foo` with a `Bar` into a `Foo<(T,U)>` where residual interconversion /// is available from `Bar->Foo`. Returns the *canonical TryType* based upon `Foo`. - fn zip(self, other: Y) -> X + fn zip(self, other: Y) -> X where - Y: Try, - X: Try + Y: Try, + X: Try + FromResidual + FromResidual, Self::Residual: Residual, From 5317de0a73e33802db0f26bad7f736a9bb224dc9 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 08:39:03 +0000 Subject: [PATCH 33/39] ordering where clauses for readbility --- crates/try_v2/src/transform.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index 59e237a..c2463a1 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -146,9 +146,9 @@ where fn zip_with(self, other: Y, f: F) -> X where Y: Try, + F: FnOnce(Self::Output, Y::Output) -> G, X: Try + FromResidual + FromResidual, Self::Residual: Residual, - F: FnOnce(Self::Output, Y::Output) -> G, { let v1 = self?; let v2 = other?; From d9ada95935be1894bcb5ba9743f24acdf93f34da Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 08:44:45 +0000 Subject: [PATCH 34/39] update description for crates.io --- crates/try_v2_derive/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/try_v2_derive/Cargo.toml b/crates/try_v2_derive/Cargo.toml index 4e2b1dd..86b38e7 100644 --- a/crates/try_v2_derive/Cargo.toml +++ b/crates/try_v2_derive/Cargo.toml @@ -3,7 +3,7 @@ name = "try_v2_derive" version = "0.5.0" edition = "2024" readme = "README.md" -description = "Provides a derive macro for `Try` ([try_trait_v2](https://rust-lang.github.io/rfcs/3058-try-trait-v2.html))" +description = "Provides a derive macro for `Try`. Part of crate `try_v2`." authors = ["Mike Foster "] keywords = ["derive", "Try", "try_trait_v2"] homepage = "https://github.com/MusicalNinjaDad/try_v2" From 7ec0475a62ca8a7bc91f1b9b80c3f0ac6baf019b Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 08:49:09 +0000 Subject: [PATCH 35/39] update changelog & readme --- CHANGELOG.md | 6 ++++++ README.md | 13 ++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8b9ce5..9da3725 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog try_v2 +## [v0.5.0] + +### New features + +- Add `trait Transform` (Forces move of derive macros to own crate & re-export) + ## [v0.4.2] ### Bugfixes diff --git a/README.md b/README.md index 5032102..8c78cd3 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,13 @@ # Try_v2 - Provides a derive macro for `Try` & optionally `Try_ConvertResult` for interconversion with - `std::result::Result` and `Try_Iterator` for iterating over `IntoIterator` and collecting from - `FromIterator` analogous to how `Result` & `Option` do this. - See ([try_trait_v2](https://rust-lang.github.io/rfcs/3058-try-trait-v2.html)) for more details - of the underlying trait. + Provides: + +- a derive macro for `Try` +- traits with standard methods to make TryTypes usable (e.g. `trait Transform` provides `.map()`) +- derive `Try_ConvertResult` for interconversion with `std::result::Result` +- derive `Try_Iterator` for iterating over `IntoIterator` and collecting from `FromIterator` analogous to how `Result` & `Option` do this. + +See ([try_trait_v2](https://rust-lang.github.io/rfcs/3058-try-trait-v2.html)) for more details of the underlying trait. ## Requires From 9d2a0ea465b5299f433b758488a2035b5394571d Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 08:52:39 +0000 Subject: [PATCH 36/39] remove Try_Methods --- CHANGELOG.md | 4 ++ crates/try_v2_derive/src/lib.rs | 53 +------------------ .../tests/compilation/examples/pass_EDebug.rs | 18 ------- crates/try_v2_derive/tests/test_usage.rs | 36 +------------ 4 files changed, 6 insertions(+), 105 deletions(-) delete mode 100644 crates/try_v2_derive/tests/compilation/examples/pass_EDebug.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 9da3725..955d0ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - Add `trait Transform` (Forces move of derive macros to own crate & re-export) +### Breaking changes + +- Removed derive `Try_Methods` in favour of trait-based implementation + ## [v0.4.2] ### Bugfixes diff --git a/crates/try_v2_derive/src/lib.rs b/crates/try_v2_derive/src/lib.rs index a2eb755..8e3726e 100644 --- a/crates/try_v2_derive/src/lib.rs +++ b/crates/try_v2_derive/src/lib.rs @@ -6,7 +6,7 @@ use proc_macro::TokenStream as TokenStream1; use proc_macro2::TokenStream as TokenStream2; use proc_macro2_diagnostic::prelude::*; use quote::{format_ident, quote}; -use syn::{DeriveInput, GenericParam, TypeParamBound, parse_quote, spanned::Spanned}; +use syn::{DeriveInput, GenericParam, parse_quote, spanned::Spanned}; mod parse; use parse::TryEnum; @@ -344,57 +344,6 @@ fn impl_convert_result(input: TokenStream2) -> DiagnosticStream { Ok(impl_convert) } -#[proc_macro_derive(Try_Methods)] -/// Derives std methods: -/// -/// ## Extracting the contained value -/// - `unwrap()` return the value contained in the Output variant - or *panics* with a generic message -pub fn try_methods(input: TokenStream1) -> TokenStream1 { - impl_try_methods(input.into()).into() -} - -fn impl_try_methods(input: TokenStream2) -> DiagnosticStream { - let ast: DeriveInput = syn::parse2(input).expect("derive macro"); - - let tryenum = TryEnum::parse(&ast)?; - #[allow(unused_variables)] - let ( - name, - output_variant_name, - output_type, - residual_type_name, - residual_type, - impl_generics, - ty_generics, - where_clause, - ) = tryenum.split_for_impl(); - - //let (debug_impl_generics, debug_ty_generics, debug_where_clause) - let debug: TypeParamBound = parse_quote!(std::fmt::Debug); - let debug_generics = tryenum.generics(|g| { - for param in g.type_params_mut() { - if param.bounds.iter().find(|b| b == &&debug).is_none() { - param.bounds.push(debug.clone()); - } - } - }); - let (debug_impl_generics, debug_ty_generics, debug_where_clause) = - debug_generics.split_for_impl(); - - let impl_extraction = quote! { - impl #debug_impl_generics #name #debug_ty_generics #debug_where_clause { - pub fn unwrap(self) -> #output_type { - let #name::#output_variant_name(val) = self else { - panic!("called `unwrap()` on a short-circuiting value: {:?}", self); - }; - val - } - } - }; - - Ok(impl_extraction) -} - #[proc_macro_derive(Try_Iterator)] /// Derives `IntoIterator` and `FromIterator` analog to `Result` & `Option`. /// diff --git a/crates/try_v2_derive/tests/compilation/examples/pass_EDebug.rs b/crates/try_v2_derive/tests/compilation/examples/pass_EDebug.rs deleted file mode 100644 index 9da48da..0000000 --- a/crates/try_v2_derive/tests/compilation/examples/pass_EDebug.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![feature(never_type)] -#![feature(try_trait_v2)] -#![feature(try_trait_v2_residual)] -#![allow(dead_code)] - -use std::fmt::Debug; - -use try_v2_derive::{Try, Try_Methods}; - -#[derive(Debug, Try, Try_Methods)] -#[must_use] -enum ExitE { - Ok(T), - TestsFailed(F), - OtherError(E), -} - -fn main() {} diff --git a/crates/try_v2_derive/tests/test_usage.rs b/crates/try_v2_derive/tests/test_usage.rs index 3605363..40c1409 100644 --- a/crates/try_v2_derive/tests/test_usage.rs +++ b/crates/try_v2_derive/tests/test_usage.rs @@ -4,7 +4,7 @@ #![feature(try_trait_v2)] #![feature(try_trait_v2_residual)] -use try_v2_derive::{Try, Try_ConvertResult, Try_Methods}; +use try_v2_derive::{Try, Try_ConvertResult}; #[cfg(assert_matches_in_module)] use std::assert_matches::assert_matches; @@ -431,37 +431,3 @@ mod lifetime_duration { assert_matches!(restricted_lifetimes(&0, &7), BorrowedResult::Err(&7)); } } - -/// Validate that the derived methods work -mod methods { - - use super::*; - - #[derive(Debug, Try, Try_Methods)] - #[must_use] - enum Validated { - Valid(T), - Invalid, - ValidationFailed(E), - } - - #[test] - fn unwrap() { - let x: Validated<_, String> = Validated::Valid(2); - assert_eq!(x.unwrap(), 2); - } - - #[test] - #[should_panic(expected = "called `unwrap()` on a short-circuiting value: ValidationFailed(2)")] - fn unwrap_panic_fields() { - let x: Validated = Validated::ValidationFailed(2); - assert_eq!(x.unwrap(), 2); - } - - #[test] - #[should_panic(expected = "called `unwrap()` on a short-circuiting value: Invalid")] - fn unwrap_panic_unit() { - let y: Validated = Validated::Invalid; - y.unwrap(); - } -} From 2cc27d537b8f0cdad659ddbba293402d09d97a7b Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 09:02:29 +0000 Subject: [PATCH 37/39] run msrv check on each crate in CI --- .github/workflows/rust.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 3815669..a67f6c7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -63,6 +63,13 @@ jobs: if: needs.skip_check.outputs.should_skip != 'true' runs-on: ubuntu-latest + strategy: + matrix: + crate: ["try_v2", "try_v2_derive"] + + defaults: + run: + working-directory: crates/${{ matrix.crate }} env: RUSTC_BOOTSTRAP: 1 From 2a4428ace7be701ae00041afead5ea2d34a58043 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 09:05:37 +0000 Subject: [PATCH 38/39] typo --- crates/try_v2/src/transform.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/try_v2/src/transform.rs b/crates/try_v2/src/transform.rs index c2463a1..8baa0d0 100644 --- a/crates/try_v2/src/transform.rs +++ b/crates/try_v2/src/transform.rs @@ -55,7 +55,7 @@ where } } - /// Applys a function to the contained value converting `T` -> `U` then + /// Applies a function to the contained value converting `T` -> `U` then /// returns the canonical TryType for `Self` with Output `U` fn map(self, f: F) -> X where From 3943e8b9b74ac1b289c2154e5313c8f2376c54a8 Mon Sep 17 00:00:00 2001 From: Mike Foster Date: Tue, 2 Jun 2026 09:11:54 +0000 Subject: [PATCH 39/39] use API Key to publish new crate --- .github/workflows/rust-publish.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust-publish.yml b/.github/workflows/rust-publish.yml index dfe502d..f578fa4 100644 --- a/.github/workflows/rust-publish.yml +++ b/.github/workflows/rust-publish.yml @@ -21,10 +21,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe #v1.0.4 - id: auth + # - uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe #v1.0.4 + # id: auth - name: Publish env: - CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} + # CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} run: cargo publish