From cbb25367cf7867f07b0a2c7718f894de437f22eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Sun, 20 Mar 2022 17:52:38 +0000 Subject: [PATCH 01/41] Fix a borrowing safety bug in slices --- cglue/Cargo.toml | 2 +- cglue/src/slice.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index df768c2..2c33fc7 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue" -version = "0.2.10" +version = "0.2.11" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe abstractions for making plugins and C-compatible libraries" diff --git a/cglue/src/slice.rs b/cglue/src/slice.rs index 0554276..1056ff0 100644 --- a/cglue/src/slice.rs +++ b/cglue/src/slice.rs @@ -252,7 +252,7 @@ impl<'a, T> From> for &'a [T] { } } -impl<'a: 'b, 'b, T> From<&'b CSliceMut<'a, T>> for CSliceMut<'a, T> { +impl<'a: 'b, 'b, T> From<&'b CSliceMut<'a, T>> for CSliceRef<'a, T> { fn from(from: &'b CSliceMut<'a, T>) -> Self { Self { data: from.data, From 4a942c55a6dd215045132b51d63b47b32560b0cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Sun, 20 Mar 2022 18:00:25 +0000 Subject: [PATCH 02/41] Update CHANGELOG --- CHANGELOG.md | 4 ++++ Cargo.lock | 36 ++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8771cf0..e097ad6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CGlue changelog +## Changes in 0.2.11: + +[Fix a safety bug with slices](https://github.com/h33p/cglue/commit/cbb25367cf7867f07b0a2c7718f894de437f22eb) + ## Changes in 0.2.10: [Rename Tup to CTup](https://github.com/h33p/cglue/commit/0c4eeabc9196a7796216a57d40b684f2e68f4d58) diff --git a/Cargo.lock b/Cargo.lock index 90420e9..546b368 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,7 +88,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cglue" -version = "0.2.10" +version = "0.2.11" dependencies = [ "abi_stable", "cglue-macro", @@ -148,9 +148,9 @@ checksum = "c348a81513f573054124b9f10e258a654a0519b65f2dba0142307bd3c7b5b8b6" [[package]] name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if 1.0.0", "lazy_static", @@ -213,9 +213,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.118" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e509672465a0504304aa87f9f176f2b2b716ed8fb105ebe5c02dc6dce96a94" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "libloading" @@ -327,27 +327,27 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -384,7 +384,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.5", + "semver 1.0.6", ] [[package]] @@ -410,9 +410,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7" +checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" [[package]] name = "semver-parser" @@ -459,9 +459,9 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "syn" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" dependencies = [ "proc-macro2", "quote", From 3bd3955aa12313b273c585f8f217b3947ca24fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Tue, 28 Jun 2022 21:17:01 +0100 Subject: [PATCH 03/41] Remove usage of private syn APIs --- Cargo.lock | 129 +++++++++++++++++++--------------- cglue-gen/Cargo.toml | 4 +- cglue-gen/src/func.rs | 11 +-- cglue-gen/src/trait_groups.rs | 4 +- cglue-gen/src/util.rs | 10 ++- 5 files changed, 89 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 546b368..54a4f3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "abi_stable" version = "0.10.4" @@ -68,6 +70,12 @@ dependencies = [ "syn", ] +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bitflags" version = "1.3.2" @@ -148,9 +156,9 @@ checksum = "c348a81513f573054124b9f10e258a654a0519b65f2dba0142307bd3c7b5b8b6" [[package]] name = "crossbeam-channel" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -158,12 +166,12 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" dependencies = [ "cfg-if 1.0.0", - "lazy_static", + "once_cell", ] [[package]] @@ -201,9 +209,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "lazy_static" @@ -213,9 +221,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libloading" @@ -229,27 +237,28 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "no-std-compat" @@ -257,6 +266,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + [[package]] name = "parking_lot" version = "0.11.2" @@ -284,9 +299,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" [[package]] name = "plugin-api" @@ -308,9 +323,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.1.0" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ "thiserror", "toml", @@ -318,36 +333,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.16" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.5" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", @@ -356,9 +371,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "repr_offset" @@ -384,14 +399,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.6", + "semver 1.0.10", ] [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" [[package]] name = "scopeguard" @@ -410,9 +425,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.6" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" +checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" [[package]] name = "semver-parser" @@ -422,18 +437,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -442,9 +457,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" dependencies = [ "itoa", "ryu", @@ -453,35 +468,35 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" [[package]] name = "syn" -version = "1.0.89" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -490,9 +505,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] @@ -505,9 +520,9 @@ checksum = "855506046561ed0573bebffede853b17b80b3143b903e9f550448c8b72b2043e" [[package]] name = "tstr" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e557019b23bfc6bf04d4b320d8e65186bc793489c4cdc5ebdd345770256aeaa" +checksum = "cca3264971090dec0feef3b455a3c178f02762f7550cf4592991ac64b3be2d7e" dependencies = [ "tstr_proc_macros", ] @@ -525,10 +540,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "unicode-ident" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" [[package]] name = "user-bin" diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index a399b08..39b414a 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-gen" -version = "0.2.4" +version = "0.2.5" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe code generation for making plugins and C-compatible libraries" @@ -15,7 +15,7 @@ readme = "../README.md" syn = { version = "1", features = ["full", "extra-traits"] } proc-macro2 = "1" quote = "1" -proc-macro-crate = "=1.1.0" +proc-macro-crate = ">=1.1.3" itertools = "0.10" lazy_static = "1" diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index 627ccf9..9ec89d5 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -1,8 +1,9 @@ use super::generics::{GenericType, ParsedGenerics}; +use super::util::parse_brace_content; use proc_macro2::TokenStream; use quote::*; use std::collections::BTreeMap; -use syn::{group::parse_braces, parse::*, punctuated::Punctuated, token::Comma, Type, *}; +use syn::{parse::*, punctuated::Punctuated, token::Comma, Type, *}; const FN_PREFIX: &str = "cglue_wrapped_"; @@ -37,7 +38,7 @@ struct CustomFuncConv { impl Parse for CustomFuncImpl { fn parse(input: ParseStream) -> Result { - let content = parse_braces(input)?.content; + let content = parse_brace_content(input)?; let tys = Punctuated::parse_terminated(&content)?; input.parse::()?; @@ -46,10 +47,10 @@ impl Parse for CustomFuncImpl { input.parse::()?; - let pre_call_impl: TokenStream = parse_braces(input)?.content.parse()?; + let pre_call_impl: TokenStream = parse_brace_content(input)?.parse()?; input.parse::()?; - let c_inner_body: TokenStream = parse_braces(input)?.content.parse()?; + let c_inner_body: TokenStream = parse_brace_content(input)?.parse()?; let c_inner_body = if c_inner_body.is_empty() { None } else { @@ -57,7 +58,7 @@ impl Parse for CustomFuncImpl { }; input.parse::()?; - let impl_func_ret: TokenStream = parse_braces(input)?.content.parse()?; + let impl_func_ret: TokenStream = parse_brace_content(input)?.parse()?; let impl_func_ret = if impl_func_ret.is_empty() { None } else { diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index 4d2c456..8df1174 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -81,7 +81,7 @@ impl Parse for TraitGroup { let generics = input.parse()?; // TODO: parse associated type defs here - group::parse_braces(input).ok(); + parse_brace_content(input).ok(); input.parse::()?; let mandatory_traits = parse_maybe_braced::(input)?; @@ -248,7 +248,7 @@ impl Parse for TraitGroupImpl { Ok(ParsedGenerics { gen_where_bounds, .. }) => { - group::parse_braces(input).ok(); + parse_brace_content(input).ok(); ParsedGenerics { gen_where_bounds, ..generics diff --git a/cglue-gen/src/util.rs b/cglue-gen/src/util.rs index 3cc3440..07a8d5d 100644 --- a/cglue-gen/src/util.rs +++ b/cglue-gen/src/util.rs @@ -46,13 +46,17 @@ pub fn crate_path_fixed() -> Option { Some(ret) } +pub fn parse_brace_content(input: ParseStream) -> Result { + let content; + syn::braced!(content in input); + Ok(content) +} + /// Parse an input stream that is either a single Ident, or a list of Idents surrounded by braces. pub fn parse_maybe_braced(input: ParseStream) -> Result> { let mut ret = vec![]; - if let Ok(braces) = syn::group::parse_braces(input) { - let content = braces.content; - + if let Ok(content) = parse_brace_content(input) { while !content.is_empty() { let val = content.parse()?; From 1a8098181896bb730d276aea59464d577e5d8927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Wed, 16 Nov 2022 18:38:14 +0200 Subject: [PATCH 04/41] Initial support for GAT lifetimes --- Cargo.lock | 3 +- EXPLANATIONS.md | 50 +++++++++++ cglue-gen/src/forward.rs | 4 +- cglue-gen/src/func.rs | 89 ++++++++++++++++--- cglue-gen/src/generics.rs | 68 ++++++++++++++ cglue-gen/src/trait_groups.rs | 31 +++---- cglue-gen/src/traits.rs | 67 +++++++------- cglue-gen/src/util.rs | 39 ++++++++ cglue/Cargo.toml | 3 + cglue/build.rs | 7 ++ cglue/src/tests/extra/custom_impl.rs | 2 +- .../src/tests/generics/generic_associated.rs | 31 +++++++ cglue/src/tests/generics/mod.rs | 2 + cglue/src/tests/simple/structs.rs | 14 ++- cglue/src/tests/simple/trait_groups.rs | 2 + cglue/src/trait_group.rs | 15 ++++ 16 files changed, 359 insertions(+), 68 deletions(-) create mode 100644 EXPLANATIONS.md create mode 100644 cglue/build.rs create mode 100644 cglue/src/tests/generics/generic_associated.rs diff --git a/Cargo.lock b/Cargo.lock index 54a4f3f..5ccbd8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,6 +102,7 @@ dependencies = [ "cglue-macro", "log", "no-std-compat", + "rustc_version 0.4.0", "serde", "try_default", ] @@ -119,7 +120,7 @@ dependencies = [ [[package]] name = "cglue-gen" -version = "0.2.4" +version = "0.2.5" dependencies = [ "itertools", "lazy_static", diff --git a/EXPLANATIONS.md b/EXPLANATIONS.md new file mode 100644 index 0000000..d735ba8 --- /dev/null +++ b/EXPLANATIONS.md @@ -0,0 +1,50 @@ +# CGlue codegen explanations + +Some of the more important details behind certain decisions of CGlue code generation. + +## Function bounds + +### Lifetimes in cfunc definition vs. cfunc vtable declaration + +The key link between the two is that the cfunc must be valid for all possible lifetimes. Thus, in declaration we have the following syntax: + + +```rust +do_thing: for<'a> extern "C" fn(&'a mut T) +``` + +While the definition uses the following: + + +```rust +extern "C" fn cglue_do_thing(&mut T) { + // ... +} +``` + +It looks different, but `cglue_do_thing` is secretly valid for all lifetimes of T (`for<'a>`). + +This becomes very important when we have additional type bounds required for the function, such as the following: + +```rust +extern "C" fn cglue_do_thing< + 'a, + T: Trait + Into> + >(&'a mut T) -> CBoxRef<'a, T::SubObj> { + // ... +} +``` + +The type bound becomes misleading, because it binds `T` to that single lifetime, as opposed to all possible lifetimes (and type bound thus becomes unique on each individual lifetime). The function's type becomes incompatible with default implementation for the vtable creation. To fix this, we must bind the type to any possible lifetime, as opposed to the particular function's lifetime: + +``` +extern "C" fn cglue_do_thing<'a, T: Trait>(&'a mut T) -> CBoxRef<'a, T::SubObj> + where for<'b> T: Into> +{ + // ... +} +``` + +This will apply the exact same bound for all lifetimes `'a`, which makes the function types uniform and compatible to be with vtable creation. + +This is very important, because all instances of a function must resolve to the same underlying function, otherwise we'd have non-deterministic number of cfunc instantiations with slightly different characteristics. This becomes extremely important in GATs. diff --git a/cglue-gen/src/forward.rs b/cglue-gen/src/forward.rs index 0d4641e..93cf27a 100644 --- a/cglue-gen/src/forward.rs +++ b/cglue-gen/src/forward.rs @@ -36,9 +36,9 @@ pub fn gen_forward(tr: ItemTrait, ext_path: Option) -> TokenStream &tr, &crate_path, false, - |(ty_ident, _, _), _, _, _, _, _| { + |(ty_ident, _, ty_where_clause, _), _, _, _, _, _| { if let Some(ident) = ty_ident { - wrapped_types.extend(quote!(type #ident = CGlueT::#ident;)); + wrapped_types.extend(quote!(type #ident = CGlueT::#ident #ty_where_clause;)); } }, ); diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index 9ec89d5..38e69bd 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -2,6 +2,7 @@ use super::generics::{GenericType, ParsedGenerics}; use super::util::parse_brace_content; use proc_macro2::TokenStream; use quote::*; +use std::cmp::Ordering; use std::collections::BTreeMap; use syn::{parse::*, punctuated::Punctuated, token::Comma, Type, *}; @@ -21,6 +22,67 @@ pub struct WrappedType { pub unbounded_hrtb: bool, } +#[derive(Eq, PartialEq, Clone)] +pub struct AssocType { + pub ident: Ident, + pub generics: Generics, +} + +impl AssocType { + /// Remap the associated type for use within HRTB bounds. + /// + /// Currently the only supported configuration is a single generic lifetime. + /// + /// # Panics + /// + /// If generic types are not supported for remapping. + pub fn remap_for_hrtb(&self) -> Self { + let mut params = self.generics.params.iter(); + match (params.next(), params.next()) { + (Some(GenericParam::Lifetime(_)), None) => Self { + ident: self.ident.clone(), + generics: syn::parse2(quote!(<'cglue_b>)).unwrap(), + }, + (None, _) => self.clone(), + _ => panic!("Unsupported generic parameter configuration!"), + } + } +} + +impl ToTokens for AssocType { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.ident.to_tokens(tokens); + self.generics.to_tokens(tokens); + } +} + +impl PartialOrd for AssocType { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for AssocType { + fn cmp(&self, other: &Self) -> Ordering { + self.ident.cmp(&other.ident) + } +} + +impl From for AssocType { + fn from(ident: Ident) -> Self { + Self { + ident, + generics: Default::default(), + } + } +} + +impl AssocType { + pub fn new(ident: Ident, generics: Generics) -> Self { + Self { ident, generics } + } +} + pub struct CustomFuncImpl { pub tys: Punctuated, pub c_ret_ty: ReturnType, @@ -93,8 +155,8 @@ struct TraitArgConv { fn ret_wrap_type<'a>( ty: &mut Type, - targets: &'a BTreeMap, WrappedType>, -) -> Option<(Type, Option, &'a WrappedType)> { + targets: &'a BTreeMap, WrappedType>, +) -> Option<(Type, Option, &'a WrappedType)> { if let Some(wrapped) = targets.get(&None) { let WrappedType { ty: new_ty, .. } = wrapped; @@ -111,8 +173,8 @@ fn ret_wrap_type<'a>( fn do_wrap_type<'a>( ty: &mut Type, - targets: &'a BTreeMap, WrappedType>, -) -> Option<(Type, Option, &'a WrappedType)> { + targets: &'a BTreeMap, WrappedType>, +) -> Option<(Type, Option, &'a WrappedType)> { match ty { Type::Reference(r) => do_wrap_type(&mut *r.elem, targets), Type::Slice(s) => do_wrap_type(&mut *s.elem, targets), @@ -121,12 +183,14 @@ fn do_wrap_type<'a>( match (&p.qself, p.path.leading_colon, iter.next(), iter.next()) { (None, None, Some(p1), Some(p2)) => { if p1.ident == "Self" { - if let Some(wrapped) = targets.get(&Some(p2.ident.clone())) { + if let Some(wrapped) = targets.get(&Some(p2.ident.clone().into())) { let WrappedType { ty: new_ty, .. } = wrapped; std::mem::drop(iter); let ident = p2.ident.clone(); + let generics: Generics = syn::parse2(p2.arguments.to_token_stream()) + .expect("Failed to parse generics"); let ret = std::mem::replace( ty, @@ -134,20 +198,21 @@ fn do_wrap_type<'a>( .expect("Failed to parse wrap_type"), ); - return Some((ret, Some(ident), wrapped)); + return Some((ret, Some(AssocType::new(ident, generics)), wrapped)); } } } (None, None, Some(p1), None) => { if p1.ident == "Self" { let self_return_wrap = targets - .get(&Some(p1.ident.clone())) + .get(&Some(p1.ident.clone().into())) .expect("No self-wrap rule specified"); let WrappedType { ty: new_ty, .. } = self_return_wrap; std::mem::drop(iter); let ident = p1.ident.clone(); + // Self has no type parameters, right? let ret = std::mem::replace( ty, @@ -155,7 +220,7 @@ fn do_wrap_type<'a>( .expect("Failed to parse self-type wrap"), ); - return Some((ret, Some(ident), self_return_wrap)); + return Some((ret, Some(ident.into()), self_return_wrap)); } } _ => {} @@ -192,7 +257,7 @@ fn do_wrap_type<'a>( impl TraitArgConv { fn new( arg: &FnArg, - targets: &BTreeMap, WrappedType>, + targets: &BTreeMap, WrappedType>, crate_path: &TokenStream, inject_lifetime: Option<&Lifetime>, inject_lifetime_cast: Option<&Lifetime>, @@ -395,7 +460,7 @@ impl ParsedFunc { sig: Signature, trait_name: Ident, generics: &ParsedGenerics, - wrap_types: &BTreeMap, WrappedType>, + wrap_types: &BTreeMap, WrappedType>, res_override: Option<&Ident>, int_result: bool, crate_path: &TokenStream, @@ -1187,7 +1252,7 @@ impl ParsedReturnType { #[allow(clippy::never_loop)] fn new( (ty, c_override): (ReturnType, Option<&ReturnType>), - targets: &BTreeMap, WrappedType>, + targets: &BTreeMap, WrappedType>, res_override: Option<&Ident>, int_result: bool, unsafety: &TokenStream, @@ -1353,7 +1418,7 @@ impl ParsedReturnType { .cloned() .unwrap_or_else(|| quote!(ret)); - let return_self = trait_ty.map(|i| i == "Self") == Some(true); + let return_self = trait_ty.map(|i| i.ident == "Self") == Some(true); ret.c_out = quote!(-> #ty); ret.c_cast_out = quote!(-> #ty_cast); diff --git a/cglue-gen/src/generics.rs b/cglue-gen/src/generics.rs index 6aa6912..a8e98e6 100644 --- a/cglue-gen/src/generics.rs +++ b/cglue-gen/src/generics.rs @@ -1,3 +1,4 @@ +use crate::util::recurse_type_to_path; use proc_macro2::TokenStream; use quote::*; use std::collections::{HashMap, HashSet}; @@ -263,6 +264,73 @@ impl ParsedGenerics { stream } + + /// Replace generic arguments on the type with ones stored within Self. + /// + /// The same generic args are replaced as the ones extracted from `util::recurse_type_to_path`. + pub fn replace_on_type(&self, ty: &mut Type) { + recurse_type_to_path(ty, |path| { + let mut generics = None; + for part in path.segments.pairs_mut() { + match part { + punctuated::Pair::End(p) => { + if let PathArguments::AngleBracketed(arg) = &mut p.arguments { + generics = Some(arg); + } + } + _ => {} + } + } + + let life_use = &self.life_use; + let gen_use = &self.gen_use; + + if let Some(generics) = generics { + *generics = syn::parse2(quote!(<#life_use #gen_use>)).unwrap(); + } + + Some(()) + }); + } + + pub fn extract_lifetimes(&mut self, ty: &Type) { + fn extract_nonpath_lifetimes(ty: &Type, out: &mut HashSet) { + match ty { + Type::Array(TypeArray { elem, .. }) => extract_nonpath_lifetimes(&*elem, out), + Type::Group(TypeGroup { elem, .. }) => extract_nonpath_lifetimes(&*elem, out), + Type::Paren(TypeParen { elem, .. }) => extract_nonpath_lifetimes(&*elem, out), + Type::Ptr(TypePtr { elem, .. }) => extract_nonpath_lifetimes(&*elem, out), + Type::Reference(TypeReference { elem, lifetime, .. }) => { + if let Some(lifetime) = lifetime { + out.insert(lifetime.clone()); + } + extract_nonpath_lifetimes(&*elem, out) + } + Type::Slice(TypeSlice { elem, .. }) => extract_nonpath_lifetimes(&*elem, out), + _ => (), + } + } + + let mut lifetimes = HashSet::new(); + extract_nonpath_lifetimes(ty, &mut lifetimes); + + let existing_lifetimes = self + .life_declare + .iter() + .map(|l| &l.lifetime) + .collect::>(); + + for lt in existing_lifetimes { + lifetimes.remove(lt); + } + + for lt in lifetimes { + self.life_use.push_value(lt.clone()); + self.life_use.push_punct(Default::default()); + self.life_declare.push_value(LifetimeDef::new(lt)); + self.life_declare.push_punct(Default::default()); + } + } } impl<'a> std::iter::FromIterator<&'a ParsedGenerics> for ParsedGenerics { diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index 8df1174..0a0cbf2 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -217,8 +217,7 @@ impl Parse for TraitGroup { /// Describes trait group to be implemented on a type. #[cfg(not(feature = "unstable"))] pub struct TraitGroupImpl { - ty_path: Path, - ty: Ident, + ty: Type, ty_generics: ParsedGenerics, generics: ParsedGenerics, group_path: Path, @@ -230,9 +229,11 @@ pub struct TraitGroupImpl { #[cfg(not(feature = "unstable"))] impl Parse for TraitGroupImpl { fn parse(input: ParseStream) -> Result { - let path = input.parse()?; + let mut ty: Type = input.parse()?; - let (ty_path, ty, ty_gens) = split_path_ident(&path)?; + // Parse generic arguments from the type. + // Here we assume the last instance of AngleBracketed are generic arguments. + let ty_gens = extract_generics(&mut ty); let mut ty_generics = ParsedGenerics::from(ty_gens.as_ref()); @@ -293,8 +294,10 @@ impl Parse for TraitGroupImpl { None }; + ty_generics.replace_on_type(&mut ty); + ty_generics.extract_lifetimes(&ty); + Ok(Self { - ty_path, ty, ty_generics, generics, @@ -322,15 +325,8 @@ impl TraitGroupImpl { let ctx_bound = super::traits::ctx_bound(); - let ty_path = &self.ty_path; let ty = &self.ty; - let ParsedGenerics { - life_use: ty_life_use, - gen_use: ty_gen_use, - .. - } = &self.ty_generics; - let group = &self.group; let group_path = &self.group_path; let ParsedGenerics { gen_use, .. } = &self.generics; @@ -338,6 +334,7 @@ impl TraitGroupImpl { let ParsedGenerics { gen_declare, gen_where_bounds, + life_declare, .. } = [&self.ty_generics, &self.generics] .iter() @@ -357,8 +354,6 @@ impl TraitGroupImpl { let vtable_type = format_ident!("{}Vtables", group); let cont_name = format_ident!("{}Container", group); - let full_ty = quote!(#ty_path #ty <#ty_life_use #ty_gen_use>); - let implemented_tables = TraitGroup::enable_opt_vtbls(self.implemented_vtbl.iter()); let vtbl_where_bounds = TraitGroup::vtbl_where_bounds( self.implemented_vtbl.iter(), @@ -370,8 +365,8 @@ impl TraitGroupImpl { ); let gen = quote! { - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> - #group_path #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use> for #full_ty + impl<'cglue_a, #life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + #group_path #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use> for #ty where #gen_where_bounds #vtbl_where_bounds { fn fill_table(table: #group_path #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> #group_path #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use> { table #implemented_tables @@ -382,7 +377,7 @@ impl TraitGroupImpl { if let Some(fwd_vtbl) = &self.fwd_implemented_vtbl { let fwd_filler_trait = format_ident!("{}FwdVtableFiller", group); - let fwd_ty = quote!(#crate_path::forward::Fwd<&'cglue_a mut #full_ty>); + let fwd_ty = quote!(#crate_path::forward::Fwd<&'cglue_a mut #ty>); let implemented_tables = TraitGroup::enable_opt_vtbls(fwd_vtbl.iter()); let vtbl_where_bounds = TraitGroup::vtbl_where_bounds( @@ -398,7 +393,7 @@ impl TraitGroupImpl { #gen impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> - #group_path #fwd_filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use> for #full_ty + #group_path #fwd_filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use> for #ty where #cont_name: #crate_path::trait_group::CGlueObjBase, #gen_where_bounds #vtbl_where_bounds diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index 4e62430..5ce5f5f 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use std::collections::BTreeMap; -use super::func::{CustomFuncImpl, ParsedFunc, WrappedType}; +use super::func::{AssocType, CustomFuncImpl, ParsedFunc, WrappedType}; use super::generics::{GenericType, ParsedGenerics}; use quote::*; @@ -51,15 +51,16 @@ pub fn cglue_c_opaque_bound() -> TokenStream { } pub fn process_item( - (ty_ident, ty_bounds, ty_attrs): ( - &Option, + (ty_def, ty_bounds, ty_where_clause, ty_attrs): ( + &Option, &Punctuated, + Option<&WhereClause>, &[Attribute], ), trait_name: &Ident, generics: &ParsedGenerics, trait_type_defs: &mut TokenStream, - types: &mut BTreeMap, WrappedType>, + types: &mut BTreeMap, WrappedType>, crate_path: &TokenStream, ) { let c_void = crate::util::void_type(); @@ -113,12 +114,12 @@ pub fn process_item( .parse_args::() .expect("Invalid type in wrap_with."); - if let Some(ty_ident) = ty_ident { - trait_type_defs.extend(quote!(type #ty_ident = #new_ty;)); + if let Some(ty_def) = ty_def { + trait_type_defs.extend(quote!(type #ty_def = #new_ty #ty_where_clause;)); } types.insert( - ty_ident.clone(), + ty_def.clone(), WrappedType { ty: new_ty.clone(), ty_ret_tmp: Some(new_ty), @@ -140,7 +141,7 @@ pub fn process_item( .expect("A valid closure must be supplied accepting the wrapped type!"); types - .get_mut(ty_ident) + .get_mut(ty_def) .expect("Type must be first wrapped with #[wrap_with(T)] atribute.") .return_conv = Some(closure); } @@ -160,7 +161,7 @@ pub fn process_item( new_ty.target = format_ident!("{}Base", target.to_string()).to_token_stream(); } - // These variables model a `CGlueF::#ty_ident: Into` bound. + // These variables model a `CGlueF::#ty_def: Into` bound. let mut from_new_ty = new_ty.clone(); let mut from_new_ty_ref = TokenStream::new(); let mut from_new_ty_simple = new_ty.clone(); @@ -227,10 +228,11 @@ pub fn process_item( quote!(#from_lifetime_simple) }; - let cglue_f_tys = ty_ident.as_ref().map(|ty_ident| { + let cglue_f_tys = ty_def.as_ref().map(|ty_def| { + let ty_def = ty_def.remap_for_hrtb(); ( - quote!(>::#ty_ident), - quote!(>::#ty_ident), + quote!(>::#ty_def), + quote!(>::#ty_def), ) }); @@ -257,10 +259,9 @@ pub fn process_item( new_ty_static.push_types_start( quote!(#crate_path::boxed::CBox<'static, #c_void>, CGlueCtx,), ); - if let Some((cglue_f_ty_ident, cglue_f_ty_simple_ident)) = &cglue_f_tys - { + if let Some((cglue_f_ty_def, cglue_f_ty_simple_ident)) = &cglue_f_tys { from_new_ty.push_types_start( - quote!(#crate_path::boxed::CBox<#from_lifetime, #cglue_f_ty_ident>, CGlueC::Context, ), + quote!(#crate_path::boxed::CBox<#from_lifetime, #cglue_f_ty_def>, CGlueC::Context, ), ); from_new_ty_simple.push_types_start( quote!(#crate_path::boxed::CBox<#from_lifetime_simple, #cglue_f_ty_simple_ident>, CGlueC::Context,), @@ -281,11 +282,11 @@ pub fn process_item( ); new_ty_static.push_types_start(quote!(&'static #c_void, CGlueCtx,)); from_new_ty.push_types_start( - quote!(&#from_lifetime >::#ty_ident, #no_context,), + quote!(&#from_lifetime >::#ty_def, #no_context,), ); from_new_ty_ref.extend(quote!(&#from_lifetime)); from_new_ty_simple.push_types_start( - quote!(&#from_lifetime_simple >::#ty_ident, #no_context,), + quote!(&#from_lifetime_simple >::#ty_def, #no_context,), ); from_new_ty_simple_ref.extend(quote!(&#from_lifetime_simple)); } else if x == "wrap_with_group_mut" || x == "wrap_with_obj_mut" { @@ -304,10 +305,9 @@ pub fn process_item( quote!(&#from_lifetime_simple mut #c_void, CGlueC::Context,), ); new_ty_static.push_types_start(quote!(&'static mut #c_void, CGlueCtx,)); - if let Some((cglue_f_ty_ident, cglue_f_ty_simple_ident)) = &cglue_f_tys - { + if let Some((cglue_f_ty_def, cglue_f_ty_simple_ident)) = &cglue_f_tys { from_new_ty.push_types_start( - quote!(&#from_lifetime mut #cglue_f_ty_ident, #no_context,), + quote!(&#from_lifetime mut #cglue_f_ty_def, #no_context,), ); from_new_ty_ref.extend(quote!(&#from_lifetime mut)); from_new_ty_simple.push_types_start( @@ -319,10 +319,10 @@ pub fn process_item( unreachable!() } - if let Some((cglue_f_ty_ident, cglue_f_ty_simple_ident)) = cglue_f_tys { + if let Some((cglue_f_ty_def, cglue_f_ty_simple_ident)) = cglue_f_tys { let (ty_ref, ty_ref_simple) = { ( - quote!((#from_new_ty_ref #cglue_f_ty_ident, CGlueC::Context)), + quote!((#from_new_ty_ref #cglue_f_ty_def, CGlueC::Context)), quote!((#from_new_ty_simple_ref #cglue_f_ty_simple_ident, CGlueC::Context)), ) }; @@ -347,8 +347,9 @@ pub fn process_item( } }; - if let Some(ty_ident) = ty_ident { - trait_type_defs.extend(quote!(type #ty_ident = #new_ty_trait_impl;)); + if let Some(ty_def) = ty_def { + trait_type_defs + .extend(quote!(type #ty_def = #new_ty_trait_impl #ty_where_clause;)); } (type_bounds, type_bounds_simple) @@ -450,7 +451,7 @@ pub fn process_item( //let lifetime_type_bound = lifetime_bound.clone(); types.insert( - ty_ident.clone(), + ty_def.clone(), WrappedType { ty: new_ty, ty_ret_tmp: Some(new_ty_ret_tmp), @@ -477,14 +478,15 @@ pub fn parse_trait( also_parse_vtbl_only: bool, mut process_item: impl FnMut( ( - &Option, + &Option, &Punctuated, + Option<&WhereClause>, &[Attribute], ), &Ident, &ParsedGenerics, &mut TokenStream, - &mut BTreeMap, WrappedType>, + &mut BTreeMap, WrappedType>, &TokenStream, ), ) -> (Vec, ParsedGenerics, TokenStream) { @@ -497,7 +499,7 @@ pub fn parse_trait( let trait_name = &tr.ident; types.insert( - Some(format_ident!("Self")), + Some(AssocType::from(format_ident!("Self"))), WrappedType { ty: parse2(quote!(CGlueC)).unwrap(), // TODO: should we forward ty in here?? @@ -535,7 +537,12 @@ pub fn parse_trait( match item { // We assume types are defined before methods here... TraitItem::Type(ty) => process_item( - (&Some(ty.ident.clone()), &ty.bounds, &ty.attrs), + ( + &Some(AssocType::new(ty.ident.clone(), ty.generics.clone())), + &ty.bounds, + ty.generics.where_clause.as_ref(), + &ty.attrs, + ), &tr.ident, &generics, &mut trait_type_defs, @@ -601,7 +608,7 @@ pub fn parse_trait( let attr_slice = std::slice::from_ref(&attr); process_item( - (&None, &punctuated, attr_slice), + (&None, &punctuated, None, attr_slice), &tr.ident, &generics, &mut trait_type_defs, diff --git a/cglue-gen/src/util.rs b/cglue-gen/src/util.rs index 07a8d5d..7bcd79a 100644 --- a/cglue-gen/src/util.rs +++ b/cglue-gen/src/util.rs @@ -106,6 +106,45 @@ pub fn split_path_ident(in_path: &Path) -> Result<(Path, Ident, GenericsOut)> { Ok((path, ident, generics)) } +/// Extract heuristically generic arguments from the type. +/// +/// This function looks for AngleBracketed path arguments and saves the last one. +pub fn extract_generics(ty: &mut Type) -> GenericsOut { + recurse_type_to_path(ty, |path| { + let mut generics = None; + for part in path.segments.pairs() { + match part { + punctuated::Pair::End(p) => { + if let PathArguments::AngleBracketed(arg) = &p.arguments { + generics = Some(arg.args.clone()); + } + } + _ => {} + } + } + generics + }) +} + +/// Recurse down to TypePath and call closure. +pub fn recurse_type_to_path( + ty: &mut Type, + func: impl FnOnce(&mut Path) -> Option, +) -> Option { + match ty { + Type::Path(TypePath { path, .. }) => func(path), + Type::Array(TypeArray { elem, .. }) => recurse_type_to_path(&mut *elem, func), + Type::Group(TypeGroup { elem, .. }) => recurse_type_to_path(&mut *elem, func), + Type::Paren(TypeParen { elem, .. }) => recurse_type_to_path(&mut *elem, func), + Type::Ptr(TypePtr { elem, .. }) => recurse_type_to_path(&mut *elem, func), + Type::Reference(TypeReference { elem, .. }) => recurse_type_to_path(&mut *elem, func), + Type::Slice(TypeSlice { elem, .. }) => recurse_type_to_path(&mut *elem, func), + _ => None, + //Type::Tuple(TypeTuple), + //Type::Verbatim(TokenStream), + } +} + /// Checks whether the type could be null pointer optimizable. /// /// Note that this is not a foolproof solution, and might have both false positives and negatives. diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 2c33fc7..006f2cd 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -19,6 +19,9 @@ try_default = { version = "= 1.0.0", optional = true } abi_stable = { version = "0.10", optional = true } log = { version = "0.4", optional = true } +[build-dependencies] +rustc_version = "0.4" + [features] default = ["std"] std = ["no-std-compat/std"] diff --git a/cglue/build.rs b/cglue/build.rs new file mode 100644 index 0000000..f9f441b --- /dev/null +++ b/cglue/build.rs @@ -0,0 +1,7 @@ +use rustc_version::{version, Version}; + +fn main() { + if version().unwrap() >= Version::parse("1.65.0").unwrap() { + println!("cargo:rustc-cfg=gats_on_stable"); + } +} diff --git a/cglue/src/tests/extra/custom_impl.rs b/cglue/src/tests/extra/custom_impl.rs index 48d2b5d..b6b13f2 100644 --- a/cglue/src/tests/extra/custom_impl.rs +++ b/cglue/src/tests/extra/custom_impl.rs @@ -37,7 +37,7 @@ pub trait CustomImpl { bool, // Conversion in trait impl to C arguments (signature names are expected). { - This shouldn't even be used in compilation! + This should not even be used in compilation! }, // This is the body of C impl minus the automatic wrapping. { diff --git a/cglue/src/tests/generics/generic_associated.rs b/cglue/src/tests/generics/generic_associated.rs new file mode 100644 index 0000000..749ee32 --- /dev/null +++ b/cglue/src/tests/generics/generic_associated.rs @@ -0,0 +1,31 @@ +use super::super::simple::structs::*; +use super::super::simple::trait_defs::*; +use super::super::simple::trait_groups::*; +use cglue_macro::*; + +#[cglue_trait] +pub trait GroupGatReturn { + #[wrap_with_group(TestGroup)] + type ReturnType<'abc>: TA + 'abc + where + Self: 'abc; + + fn ggr_1(&mut self) -> Self::ReturnType<'_>; +} + +impl GroupGatReturn for SA { + type ReturnType<'a> = &'a SA; + + fn ggr_1(&mut self) -> &SA { + self + } +} + +#[test] +fn use_gat_return() { + use crate::prelude::v1::*; + let sa = SA {}; + let mut obj = trait_obj!(sa as GroupGatReturn); + let ta = obj.ggr_1(); + assert_eq!(ta.ta_1(), 5); +} diff --git a/cglue/src/tests/generics/mod.rs b/cglue/src/tests/generics/mod.rs index cc49ee2..6d0975d 100644 --- a/cglue/src/tests/generics/mod.rs +++ b/cglue/src/tests/generics/mod.rs @@ -1,5 +1,7 @@ pub mod associated; pub mod associated_ref; +#[cfg(gats_on_stable)] +pub mod generic_associated; pub mod generic_structs; pub mod groups; pub mod param; diff --git a/cglue/src/tests/simple/structs.rs b/cglue/src/tests/simple/structs.rs index 17eb691..0a772b6 100644 --- a/cglue/src/tests/simple/structs.rs +++ b/cglue/src/tests/simple/structs.rs @@ -17,6 +17,12 @@ impl TA for SA { } } +impl<'a> TA for &'a SA { + extern "C" fn ta_1(&self) -> usize { + (**self).ta_1() + } +} + impl AsRef for SA { fn as_ref(&self) -> &SA { self @@ -46,12 +52,12 @@ impl TC for SA { #[test] fn call_a() { - let a = SA {}; - let mut b = SB {}; + let mut a = SA {}; + let b = SB {}; let c = SB {}; - let obja = trait_obj!(&a as TA); - let objb = trait_obj!(&mut b as TA); + let obja = trait_obj!(&mut a as TA); + let objb = trait_obj!(&b as TA); let objc = trait_obj!(c as TA); assert_eq!(obja.ta_1() + objb.ta_1() + objc.ta_1(), 17); diff --git a/cglue/src/tests/simple/trait_groups.rs b/cglue/src/tests/simple/trait_groups.rs index fbf53da..83b25c0 100644 --- a/cglue/src/tests/simple/trait_groups.rs +++ b/cglue/src/tests/simple/trait_groups.rs @@ -7,6 +7,8 @@ cglue_trait_group!(TestGroup, TA, { TB, TC }); cglue_impl_group!(SA, TestGroup, { TC }); +cglue_impl_group!(&'a SA, TestGroup, {}); + cglue_impl_group!(SB, super::trait_groups::TestGroup, { TB }); #[test] diff --git a/cglue/src/trait_group.rs b/cglue/src/trait_group.rs index 8a22e17..ab03b2d 100644 --- a/cglue/src/trait_group.rs +++ b/cglue/src/trait_group.rs @@ -205,6 +205,21 @@ where } } } +impl< + 'a, + T: Deref, + F, + V: CGlueVtbl, Context = C, RetTmp = R>, + C: ContextBounds, + R: Default, + > CGlueTraitObj<'a, T, V, V::Context, V::RetTmp> +where + &'a V: Default, +{ + pub fn from_thingies(d: (T, V::Context)) -> Self { + Self::from(d) + } +} impl< 'a, From 078bd7556db73ca120843d48c5ab612b39642d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Wed, 16 Nov 2022 18:48:47 +0200 Subject: [PATCH 05/41] Attempt at fixing crates.io index fetching in actions --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3c8754e..ffb02c1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,6 +4,7 @@ on: [push, pull_request] env: CARGO_TERM_COLOR: always + CARGO_NET_GIT_FETCH_WITH_CLI: true jobs: From 6783bf6d3ecfbd89a3ab28daaa0b93c1fdb19db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Wed, 16 Nov 2022 20:17:37 +0200 Subject: [PATCH 06/41] Fix test regression in unstable features. --- cglue/src/tests/simple/trait_groups.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cglue/src/tests/simple/trait_groups.rs b/cglue/src/tests/simple/trait_groups.rs index 83b25c0..5cb3735 100644 --- a/cglue/src/tests/simple/trait_groups.rs +++ b/cglue/src/tests/simple/trait_groups.rs @@ -15,11 +15,16 @@ cglue_impl_group!(SB, super::trait_groups::TestGroup, { TB }); fn test_group() { let mut a = SA {}; - // Slight regression in 0.2, can not use const ref, because + // Slight regression in 0.2, can not use TestGroupRef, because // (optional) TC requires mutable refs for the impl to work. - // Can be fixed through unstable features. - #[cfg(feature = "unstable")] - let _ = group_obj!(&a as TestGroup); + // Can be fixed through unstable features or forcing boxing + // and a ref group impl. + // + // Having both requres explicitly specifying inner type like done here. + fn into_test<'a, T: Into> + 'a>(t: T) -> TestGroupBox<'a> { + group_obj!(t as TestGroup) + } + let _ = into_test(&a); let _ = group_obj!(&mut a as TestGroup); From 11a769fb507b0de50a1b72bb472161b7e5b7be17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Thu, 17 Nov 2022 00:51:55 +0200 Subject: [PATCH 07/41] Improve GATs robustness, expand docs --- EXPLANATIONS.md | 14 ++ README.md | 46 +++++- cglue-gen/src/func.rs | 70 +++++++-- cglue-gen/src/generics.rs | 92 +++++++----- cglue-gen/src/traits.rs | 8 +- cglue-gen/src/util.rs | 133 ++++++++++++++++++ cglue-macro/Cargo.toml | 2 +- cglue-macro/src/lib.rs | 49 ++----- cglue/Cargo.toml | 2 +- cglue/src/lib.rs | 62 +++++++- .../src/tests/generics/generic_associated.rs | 6 +- 11 files changed, 388 insertions(+), 96 deletions(-) diff --git a/EXPLANATIONS.md b/EXPLANATIONS.md index d735ba8..6a4463d 100644 --- a/EXPLANATIONS.md +++ b/EXPLANATIONS.md @@ -48,3 +48,17 @@ extern "C" fn cglue_do_thing<'a, T: Trait>(&'a mut T) -> CBoxRef<'a, T::SubObj> This will apply the exact same bound for all lifetimes `'a`, which makes the function types uniform and compatible to be with vtable creation. This is very important, because all instances of a function must resolve to the same underlying function, otherwise we'd have non-deterministic number of cfunc instantiations with slightly different characteristics. This becomes extremely important in GATs. + +### Lifetime changes when wrapping + +Within cfuncs lifetimes in associated type definitions (`type Type<'a>: 'a`) take precedence over lifetimes defined by trait functions. This is to make types the source of truth. + +During codegen, we may encounter a function as follows: + +```rust +fn do_something<'b>(&'b mut self) -> Self::Type<'b> { + // ... +} +``` + +Since `Self::Type` was defined with lifetime `'a`, the implementation will match `'a` to `'b` and replace `'b` with `'a` within cfuncs. diff --git a/README.md b/README.md index 238a965..3cc556e 100644 --- a/README.md +++ b/README.md @@ -512,7 +512,7 @@ types in anonymous lifetime references. It should be okay, but the situation is 1. Due to no GAT, `CGlueObjRef/Mut<'_>` is being promoted to `CGlueObjRef/Mut<'static>`. This should be okay, given it is not possible to clone non-CBox objects, and these objects are - returned by-reference, not value. + returned by-reference, not value (see GATs section for how to avoid this). 2. Trait bounds are only checked for one lifetime (lifetime of the vtable), and the C function is being cast into a HRTB one unsafely. This is because it is not possible to specify the @@ -530,6 +530,48 @@ note that if there is a trait that returns a combination of these types, it is n use wrapping, because the underlying object types differ. If possible, split up the type to multiple associated types. +### Generic associated types + +CGlue has limited support for GATs! More specifically, single lifetime GATs are supported, +which allows one to implement a form of `LendingIterator`: + +```rust +use cglue::*; +#[cglue_trait] +pub trait LendingPrinter { + #[wrap_with_obj(InfoPrinter)] + type Printer<'a>: InfoPrinter + 'a where Self: 'a; + + fn borrow_printer<'a>(&'a mut self) -> Self::Printer<'a>; +} + +impl<'a> InfoPrinter for &'a mut Info { + fn print_info(&self) { + (**self).print_info(); + } +} + +struct InfoStore { + info: Info, +} + +impl LendingPrinter for InfoStore { + type Printer<'a> = &'a mut Info; + + fn borrow_printer(&mut self) -> Self::Printer<'_> { + &mut self.info + } +} + +let builder = InfoStore { info: Info { value: 50 } }; + +let mut obj = trait_obj!(builder as LendingPrinter); + +let info_printer = obj.borrow_printer(); + +info_printer.print_info(); +``` + ### Plugin system A full example is available in the repo's `examples` subdirectory. @@ -696,3 +738,5 @@ If you want your project to be added to the list, please open an issue report :) It is available in [CHANGELOG.md](https://github.com/h33p/cglue/blob/main/CHANGELOG.md) file. + +License: MIT diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index 38e69bd..5a718aa 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -1,5 +1,6 @@ use super::generics::{GenericType, ParsedGenerics}; use super::util::parse_brace_content; +use crate::util::{merge_lifetime_declarations, remap_lifetime_defs, remap_type_lifetimes}; use proc_macro2::TokenStream; use quote::*; use std::cmp::Ordering; @@ -157,6 +158,9 @@ fn ret_wrap_type<'a>( ty: &mut Type, targets: &'a BTreeMap, WrappedType>, ) -> Option<(Type, Option, &'a WrappedType)> { + // None means handle only the C side - the function will not be called on Rust side. + // This is useful for providing functionality for C users that can be done faster in Rust. + // TODO: perhaps switch targets to an enum to indicate C side or not. if let Some(wrapped) = targets.get(&None) { let WrappedType { ty: new_ty, .. } = wrapped; @@ -261,6 +265,7 @@ impl TraitArgConv { crate_path: &TokenStream, inject_lifetime: Option<&Lifetime>, inject_lifetime_cast: Option<&Lifetime>, + lifetime_map: &BTreeMap, ) -> Self { let (to_c_args, call_c_args, c_args, c_cast_args, to_trait_arg) = match arg { FnArg::Receiver(r) => { @@ -317,20 +322,31 @@ impl TraitArgConv { let mut ret = None; + // Map all lifetimes + let mut ty = ty.clone(); + remap_type_lifetimes(&mut ty, lifetime_map); + // TODO: deal with nested conversion //if let (Some(old), Type::Path(p)) = { //} - match ty { + match &ty { Type::Reference(r) => { let is_mut = r.mutability.is_some(); + + let lt = r + .lifetime + .as_ref() + .map(|lt| lifetime_map.get(lt).unwrap_or(lt)) + .map(|v| quote!(#v,)); + let new_ty = match &*r.elem { Type::Slice(s) => { let ty = &*s.elem; Some(if is_mut { - quote!(#crate_path::slice::CSliceMut<#ty>) + quote!(#crate_path::slice::CSliceMut<#lt #ty>) } else { - quote!(#crate_path::slice::CSliceRef<#ty>) + quote!(#crate_path::slice::CSliceRef<#lt #ty>) }) .map(|v| (v, false)) } @@ -338,9 +354,9 @@ impl TraitArgConv { p.path.get_ident().map(|i| i.to_string()).as_deref() { Some(if is_mut { - quote!(#crate_path::slice::CSliceMut) + quote!(#crate_path::slice::CSliceMut<#lt u8>) } else { - quote!(#crate_path::slice::CSliceRef) + quote!(#crate_path::slice::CSliceRef<#lt u8>) }) } else { None @@ -518,6 +534,7 @@ impl ParsedFunc { crate_path, out.lifetime.as_ref(), out.lifetime_cast.as_ref(), + &out.lifetime_map, )); } @@ -534,6 +551,7 @@ impl ParsedFunc { crate_path, out.lifetime.as_ref(), out.lifetime_cast.as_ref(), + &out.lifetime_map, ); args.push(func); @@ -763,6 +781,7 @@ impl ParsedFunc { lifetime, lifetime_cast, unbounded_hrtb, + lifetime_map, .. } = &self.out; @@ -771,6 +790,8 @@ impl ParsedFunc { .. } = &self.sig_generics; + let sig_life_declare = remap_lifetime_defs(sig_life_declare, lifetime_map); + let (hrtb, args, c_out) = match ( lifetime.as_ref().filter(|lt| lt.ident != "cglue_a"), lifetime_cast, @@ -781,8 +802,10 @@ impl ParsedFunc { _ => (quote!(), args, c_out), }; + let sig_life_declare = merge_lifetime_declarations(sig_life_declare, &parse_quote!(#hrtb)); + let gen = quote! { - #name: for<#sig_life_declare #hrtb> extern "C" fn(#args #c_ret_params) #c_out, + #name: for<#sig_life_declare> extern "C" fn(#args #c_ret_params) #c_out, }; stream.extend(gen); @@ -799,6 +822,7 @@ impl ParsedFunc { lifetime, lifetime_cast, unbounded_hrtb, + lifetime_map, .. } = &self.out; @@ -807,6 +831,8 @@ impl ParsedFunc { .. } = &self.sig_generics; + let sig_life_declare = remap_lifetime_defs(sig_life_declare, lifetime_map); + let (hrtb, args, c_out) = match ( lifetime.as_ref().filter(|lt| lt.ident != "cglue_a"), lifetime_cast, @@ -817,6 +843,8 @@ impl ParsedFunc { _ => (quote!(), args, c_out), }; + let sig_life_declare = merge_lifetime_declarations(sig_life_declare, &parse_quote!(#hrtb)); + let doc_text = format!(" Getter for {}.", name); let gen = quote! { @@ -824,7 +852,7 @@ impl ParsedFunc { /// /// Note that this function is wrapped into unsafe, because if already were is an /// opaque one, it would allow to invoke undefined behaviour. - pub fn #name(&self) -> for<#sig_life_declare #hrtb> unsafe extern "C" fn(#args #c_ret_params) #c_out { + pub fn #name(&self) -> for<#sig_life_declare> unsafe extern "C" fn(#args #c_ret_params) #c_out { unsafe { ::core::mem::transmute(self.#name) } } }; @@ -887,6 +915,7 @@ impl ParsedFunc { lifetime, lifetime_cast, unbounded_hrtb, + lifetime_map, .. } = &self.out; let call_args = self.to_trait_call_args(); @@ -909,6 +938,8 @@ impl ParsedFunc { .. } = &self.sig_generics; + let sig_life_declare = remap_lifetime_defs(sig_life_declare, lifetime_map); + let tmp_lifetime = if *use_hrtb && !life_use.is_empty() { quote!('cglue_b, ) } else { @@ -917,12 +948,14 @@ impl ParsedFunc { // Inject 'cglue_a if there are no lifetimes declared by the trait, // and temp lifetime is needed - let life_declare = if lifetime.is_some() && life_declare.is_empty() { - quote!(#lifetime, ) + let life_declare = if lifetime.is_none() || !life_declare.is_empty() { + life_declare.clone() } else { - life_declare.to_token_stream() + parse_quote!(#lifetime,) }; + let sig_life_declare = merge_lifetime_declarations(sig_life_declare, &life_declare); + let mut container_bound = quote!(); let (c_pre_call, cglue_c_into_inner) = if self.receiver.reference.is_none() { @@ -973,7 +1006,7 @@ impl ParsedFunc { let ctx_bound = super::traits::ctx_bound(); let gen = quote! { - #safety extern "C" fn #fnname<#sig_life_declare #life_declare CGlueC: #container_bound, CGlueCtx: #ctx_bound, #gen_declare>(#args #c_ret_params) #c_out where #gen_where_bounds #c_where_bounds #cglue_c_into_inner CGlueC::ObjType: for<'cglue_b> #trname<#tmp_lifetime #gen_use>, { + #safety extern "C" fn #fnname<#sig_life_declare CGlueC: #container_bound, CGlueCtx: #ctx_bound, #gen_declare>(#args #c_ret_params) #c_out where #gen_where_bounds #c_where_bounds #cglue_c_into_inner CGlueC::ObjType: for<'cglue_b> #trname<#tmp_lifetime #gen_use>, { #c_pre_call let ret = #inner_impl; #c_ret @@ -1218,6 +1251,8 @@ struct ParsedReturnType { unbounded_hrtb: bool, return_self: bool, use_wrap: bool, + // Map in-function lifetimes to type lifetimes + lifetime_map: BTreeMap, } // TODO: handle more cases @@ -1281,6 +1316,7 @@ impl ParsedReturnType { unbounded_hrtb: false, return_self: false, use_wrap: false, + lifetime_map: Default::default(), }; if let ReturnType::Type(_, ty) = &mut c_ty { @@ -1299,9 +1335,21 @@ impl ParsedReturnType { impl_return_conv, ty_static, ty_ret_tmp, + ty: + GenericType { + generic_lifetimes: old_lifetimes, + .. + }, .. } = wrapped.2; + // Swap to check if trait_ty even exists before cloning + ret.lifetime_map = trait_ty + .iter() + .flat_map(|assoc| assoc.generics.lifetimes().map(|v| &v.lifetime).cloned()) + .zip(old_lifetimes.iter().cloned()) + .collect(); + // TODO: sort out the order let (mutable, lifetime) = match (inject_ret_tmp, &**ty) { diff --git a/cglue-gen/src/generics.rs b/cglue-gen/src/generics.rs index a8e98e6..5293440 100644 --- a/cglue-gen/src/generics.rs +++ b/cglue-gen/src/generics.rs @@ -1,4 +1,4 @@ -use crate::util::recurse_type_to_path; +use crate::util::{parse_punctuated, recurse_type_to_path}; use proc_macro2::TokenStream; use quote::*; use std::collections::{HashMap, HashSet}; @@ -525,19 +525,7 @@ impl From<&Generics> for ParsedGenerics { } fn parse_generic_arguments(input: ParseStream) -> Punctuated { - let mut punct = Punctuated::new(); - - while let Ok(arg) = input.parse::() { - punct.push_value(arg); - - if let Ok(comma) = input.parse::() { - punct.push_punct(comma); - } else { - break; - } - } - - punct + parse_punctuated(input) } impl Parse for ParsedGenerics { @@ -588,29 +576,43 @@ impl Parse for GenericCastType { #[derive(Clone)] pub struct GenericType { + /// Path to type (core:: in core::Option) pub path: Path, + /// Separator to use, this depends on `cast_to_group` parameter pub gen_separator: TokenStream, - pub generics: TokenStream, + /// Generic lifetime parameters (there isn't an example in core::Option) + pub generic_lifetimes: Punctuated, + /// Generic type parameters (T in core::Option) + pub generic_types: Punctuated, + /// The resulting type (Option in core::Option) pub target: TokenStream, } impl GenericType { pub fn push_lifetime_start(&mut self, lifetime: &Lifetime) { - let gen = &self.generics; - self.generics = quote!(#lifetime, #gen); + self.generic_lifetimes.insert(0, lifetime.clone()); + if !self.generic_lifetimes.trailing_punct() { + self.generic_lifetimes.push_punct(Default::default()); + } } pub fn push_types_start(&mut self, types: TokenStream) { - let generics = std::mem::replace(&mut self.generics, TokenStream::new()); + let mut types = + syn::parse::Parser::parse2(Punctuated::::parse_terminated, types) + .expect("Invalid types provided"); - let ParsedGenerics { - life_declare, - gen_declare, - .. - } = parse2::(quote!(<#generics>)).expect("Gen 3"); + if !types.trailing_punct() { + types.push_punct(Default::default()); + } + + // Swap here, because types becomes the start + std::mem::swap(&mut self.generic_types, &mut types); + + self.generic_types.extend(types.into_iter()); - self.generics - .extend(quote!(#life_declare #types #gen_declare)); + if !self.generic_types.trailing_punct() { + self.generic_types.push_punct(Default::default()); + } } fn from_type(target: &Type, cast_to_group: bool) -> Self { @@ -630,24 +632,35 @@ impl GenericType { ), }; - let (gen_separator, generics) = match (cast_to_group, generics) { - (true, Some(params)) => { - let pg = ParsedGenerics::from(¶ms); - - let life = &pg.life_use; - let gen = &pg.gen_use; + let (generic_lifetimes, mut generic_types) = match &generics { + Some(params) => { + let pg = ParsedGenerics::from(params); + (pg.life_use, pg.gen_use) + } + _ => Default::default(), + }; - (quote!(::), quote!(#life _, _, #gen)) + let gen_separator = if cast_to_group { + if generics.is_some() { + let infer = Type::Infer(TypeInfer { + underscore_token: Default::default(), + }); + generic_types.insert(0, infer.clone()); + generic_types.insert(0, infer); + if !generic_types.trailing_punct() { + generic_types.push_punct(Default::default()); + } } - (false, Some(params)) => (quote!(), quote!(#params)), - (true, _) => (quote!(::), quote!()), - _ => (quote!(), quote!()), + quote!(::) + } else { + quote!() }; Self { path, gen_separator, - generics, + generic_lifetimes, + generic_types, target, } } @@ -657,10 +670,11 @@ impl ToTokens for GenericType { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.extend(self.path.to_token_stream()); tokens.extend(self.target.clone()); - let generics = &self.generics; - if !generics.is_empty() { + let generic_lifetimes = &self.generic_lifetimes; + let generic_types = &self.generic_types; + if !generic_lifetimes.is_empty() || !generic_types.is_empty() { tokens.extend(self.gen_separator.clone()); - tokens.extend(quote!(<#generics>)); + tokens.extend(quote!(<#generic_lifetimes #generic_types>)); } } } diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index 5ce5f5f..aebfd6f 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -494,7 +494,7 @@ pub fn parse_trait( let generics = ParsedGenerics::from(&tr.generics); let mut trait_type_defs = TokenStream::new(); let mut types = BTreeMap::new(); - let mut types_vtbl = BTreeMap::new(); + let mut types_c_side_vtbl = BTreeMap::new(); let trait_name = &tr.ident; @@ -598,7 +598,7 @@ pub fn parse_trait( continue; } - types_vtbl.clear(); + types_c_side_vtbl.clear(); if let Some((lt, attr)) = attr { let mut punctuated = Punctuated::default(); @@ -612,11 +612,11 @@ pub fn parse_trait( &tr.ident, &generics, &mut trait_type_defs, - &mut types_vtbl, + &mut types_c_side_vtbl, crate_path, ); } - (true, &types_vtbl) + (true, &types_c_side_vtbl) } else { (false, &types) }; diff --git a/cglue-gen/src/util.rs b/cglue-gen/src/util.rs index 7bcd79a..8b12d84 100644 --- a/cglue-gen/src/util.rs +++ b/cglue-gen/src/util.rs @@ -1,6 +1,7 @@ use proc_macro2::TokenStream; use proc_macro_crate::{crate_name, FoundCrate}; use quote::{format_ident, quote}; +use std::collections::{BTreeMap, HashSet}; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::token::Colon2; @@ -46,6 +47,22 @@ pub fn crate_path_fixed() -> Option { Some(ret) } +pub fn parse_punctuated(input: ParseStream) -> Punctuated { + let mut punct = Punctuated::new(); + + while let Ok(arg) = input.parse::() { + punct.push_value(arg); + + if let Ok(comma) = input.parse::

() { + punct.push_punct(comma); + } else { + break; + } + } + + punct +} + pub fn parse_brace_content(input: ParseStream) -> Result { let content; syn::braced!(content in input); @@ -145,6 +162,122 @@ pub fn recurse_type_to_path( } } +pub fn map_lifetimes( + lifetimes: &mut Punctuated, + map: &BTreeMap, +) { + for lt in lifetimes.iter_mut() { + if let Some(target) = map.get(lt) { + *lt = target.clone(); + } + } +} + +pub fn map_lifetime_defs( + lifetimes: &mut Punctuated, + map: &BTreeMap, +) { + for lt in lifetimes.iter_mut() { + if let Some(target) = map.get(<.lifetime) { + lt.lifetime = target.clone(); + } + map_lifetimes(&mut lt.bounds, map); + } +} + +pub fn remap_lifetime_defs( + lifetimes: &Punctuated, + map: &BTreeMap, +) -> Punctuated { + let mut lifetimes = lifetimes.clone(); + map_lifetime_defs(&mut lifetimes, map); + lifetimes +} + +/// Recursively remap lifetimes of a type. +pub fn remap_type_lifetimes(ty: &mut Type, map: &BTreeMap) { + match ty { + Type::Reference(TypeReference { + elem, + ref mut lifetime, + .. + }) => { + if let Some(new_lt) = lifetime.as_ref().and_then(|lt| map.get(lt)) { + *lifetime = Some(new_lt.clone()); + } + remap_type_lifetimes(&mut *elem, map) + } + Type::Path(TypePath { path, qself, .. }) => { + if let Some(s) = qself.as_mut() { + remap_type_lifetimes(&mut *s.ty, map); + } + for seg in path.segments.iter_mut() { + match &mut seg.arguments { + PathArguments::AngleBracketed(args) => { + for arg in args.args.iter_mut() { + match arg { + GenericArgument::Lifetime(lt) => { + if let Some(new_lt) = map.get(lt) { + *lt = new_lt.clone(); + } + } + GenericArgument::Type(ty) => remap_type_lifetimes(ty, map), + _ => (), + } + } + } + PathArguments::Parenthesized(args) => { + for arg in args.inputs.iter_mut() { + remap_type_lifetimes(arg, map); + } + if let ReturnType::Type(_, ty) = &mut args.output { + remap_type_lifetimes(&mut *ty, map); + } + } + _ => (), + } + } + } + Type::Array(TypeArray { elem, .. }) => remap_type_lifetimes(&mut *elem, map), + Type::Group(TypeGroup { elem, .. }) => remap_type_lifetimes(&mut *elem, map), + Type::Paren(TypeParen { elem, .. }) => remap_type_lifetimes(&mut *elem, map), + Type::Ptr(TypePtr { elem, .. }) => remap_type_lifetimes(&mut *elem, map), + Type::Slice(TypeSlice { elem, .. }) => remap_type_lifetimes(&mut *elem, map), + Type::Tuple(TypeTuple { elems, .. }) => { + for elem in elems.iter_mut() { + remap_type_lifetimes(elem, map) + } + } + _ => (), + //Type::Tuple(TypeTuple), + //Type::Verbatim(TokenStream), + } +} + +pub fn merge_lifetime_declarations( + a: Punctuated, + b: &Punctuated, +) -> Punctuated { + let mut life_declare = Punctuated::new(); + let mut life_declared = HashSet::<&Ident>::new(); + + for val in std::iter::IntoIterator::into_iter([&a, b]) { + for life in val.pairs() { + let (val, punct) = life.into_tuple(); + if life_declared.contains(&val.lifetime.ident) { + continue; + } + life_declare.push_value(val.clone()); + if let Some(punct) = punct { + life_declare.push_punct(*punct); + } + life_declared.insert(&val.lifetime.ident); + } + } + + life_declare +} + /// Checks whether the type could be null pointer optimizable. /// /// Note that this is not a foolproof solution, and might have both false positives and negatives. diff --git a/cglue-macro/Cargo.toml b/cglue-macro/Cargo.toml index 51b709f..acdc4fb 100644 --- a/cglue-macro/Cargo.toml +++ b/cglue-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-macro" -version = "0.2.2" +version = "0.2.3" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe code generation macros for making plugins and C-compatible libraries" diff --git a/cglue-macro/src/lib.rs b/cglue-macro/src/lib.rs index c6ca7b9..62c001d 100644 --- a/cglue-macro/src/lib.rs +++ b/cglue-macro/src/lib.rs @@ -54,30 +54,20 @@ pub fn cglue_trait_ext(_args: TokenStream, input: TokenStream) -> TokenStream { pub fn trait_obj(args: TokenStream) -> TokenStream { let crate_path = cglue_gen::util::crate_path(); - let GenericCastType { - ident, - target: - GenericType { - path, - target, - generics, - .. - }, - } = parse_macro_input!(args as GenericCastType); - - let path = if let Ok(ident) = parse2::(target.clone()) { - ext_abs_remap(prelude_remap_with_ident(path, &ident)) - } else { - path - }; + let GenericCastType { ident, mut target } = parse_macro_input!(args as GenericCastType); + + if let Ok(ident) = parse2::(target.target.clone()) { + target.path = ext_abs_remap(prelude_remap_with_ident(target.path, &ident)) + } - let target = format_ident!("{}Base", target.to_token_stream().to_string()); + target.target = + format_ident!("{}Base", target.target.to_token_stream().to_string()).to_token_stream(); let gen = quote! { #crate_path::trait_group::Opaquable::into_opaque({ // We need rust to infer lifetimes and generics, thus we use a wrapper trait use #crate_path::from2::From2; - #path #target :: <#generics>::from2(#ident) + #target ::from2(#ident) }) }; @@ -138,28 +128,17 @@ pub fn cglue_impl_group(args: TokenStream) -> TokenStream { pub fn group_obj(args: TokenStream) -> TokenStream { let crate_path = cglue_gen::util::crate_path(); - let GenericCastType { - ident, - target: - GenericType { - path, - target, - generics, - .. - }, - } = parse_macro_input!(args as GenericCastType); - - let path = if let Ok(ident) = parse2::(target.clone()) { - ext_abs_remap(prelude_remap_with_ident(path, &ident)) - } else { - path - }; + let GenericCastType { ident, mut target } = parse_macro_input!(args as GenericCastType); + + if let Ok(ident) = parse2::(target.target.clone()) { + target.path = ext_abs_remap(prelude_remap_with_ident(target.path, &ident)) + } let gen = quote! { #crate_path::trait_group::Opaquable::into_opaque({ // We need rust to infer lifetimes and generics, thus we use a wrapper trait use #crate_path::from2::From2; - #path #target :: <#generics>::from2(#ident) + #target ::from2(#ident) }) }; diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 006f2cd..2049dd4 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue" -version = "0.2.11" +version = "0.2.12" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe abstractions for making plugins and C-compatible libraries" diff --git a/cglue/src/lib.rs b/cglue/src/lib.rs index 53935b0..1137c31 100644 --- a/cglue/src/lib.rs +++ b/cglue/src/lib.rs @@ -724,7 +724,7 @@ //! //! 1. Due to no GAT, `CGlueObjRef/Mut<'_>` is being promoted to `CGlueObjRef/Mut<'static>`. This //! should be okay, given it is not possible to clone non-CBox objects, and these objects are -//! returned by-reference, not value. +//! returned by-reference, not value (see GATs section for how to avoid this). //! //! 2. Trait bounds are only checked for one lifetime (lifetime of the vtable), and the C function //! is being cast into a HRTB one unsafely. This is because it is not possible to specify the @@ -742,6 +742,66 @@ //! use wrapping, because the underlying object types differ. If possible, split up the type to //! multiple associated types. //! +//! ### Generic associated types +//! +//! CGlue has limited support for GATs! More specifically, single lifetime GATs are supported, +//! which allows one to implement a form of `LendingIterator`: +//! +//! ``` +//! # #[cfg(gats_on_stable)] +//! # mod gats { +//! use cglue::*; +//! # // Previous definitions +//! # #[cglue_trait] +//! # pub trait InfoPrinter { +//! # fn print_info(&self); +//! # } +//! # struct Info { +//! # value: usize +//! # } +//! # impl InfoPrinter for Info { +//! # fn print_info(&self) { +//! # println!("Info struct: {}", self.value); +//! # } +//! # } +//! #[cglue_trait] +//! pub trait LendingPrinter { +//! #[wrap_with_obj(InfoPrinter)] +//! type Printer<'a>: InfoPrinter + 'a where Self: 'a; +//! +//! fn borrow_printer<'a>(&'a mut self) -> Self::Printer<'a>; +//! } +//! +//! impl<'a> InfoPrinter for &'a mut Info { +//! fn print_info(&self) { +//! (**self).print_info(); +//! } +//! } +//! +//! struct InfoStore { +//! info: Info, +//! } +//! +//! impl LendingPrinter for InfoStore { +//! type Printer<'a> = &'a mut Info; +//! +//! fn borrow_printer(&mut self) -> Self::Printer<'_> { +//! &mut self.info +//! } +//! } +//! +//! # fn main() { +//! let builder = InfoStore { info: Info { value: 50 } }; +//! +//! let mut obj = trait_obj!(builder as LendingPrinter); +//! +//! let info_printer = obj.borrow_printer(); +//! +//! info_printer.print_info(); +//! # } +//! # } +//! ``` +//! //! ### Plugin system //! //! A full example is available in the repo's `examples` subdirectory. diff --git a/cglue/src/tests/generics/generic_associated.rs b/cglue/src/tests/generics/generic_associated.rs index 749ee32..b7d5705 100644 --- a/cglue/src/tests/generics/generic_associated.rs +++ b/cglue/src/tests/generics/generic_associated.rs @@ -10,13 +10,13 @@ pub trait GroupGatReturn { where Self: 'abc; - fn ggr_1(&mut self) -> Self::ReturnType<'_>; + fn ggr_1<'a>(&'a mut self, val: &'a u32) -> Self::ReturnType<'a>; } impl GroupGatReturn for SA { type ReturnType<'a> = &'a SA; - fn ggr_1(&mut self) -> &SA { + fn ggr_1(&mut self, val: &u32) -> &SA { self } } @@ -26,6 +26,6 @@ fn use_gat_return() { use crate::prelude::v1::*; let sa = SA {}; let mut obj = trait_obj!(sa as GroupGatReturn); - let ta = obj.ggr_1(); + let ta = obj.ggr_1(&0); assert_eq!(ta.ta_1(), 5); } From bc8e3b087b379ee69062b4b3813d4c7f8d695757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Thu, 17 Nov 2022 00:58:41 +0200 Subject: [PATCH 08/41] 1.45.0 fixes --- Cargo.lock | 4 ++-- cglue-gen/src/func.rs | 6 +++--- cglue-gen/src/util.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ccbd8b..d6eabf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,7 +96,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cglue" -version = "0.2.11" +version = "0.2.12" dependencies = [ "abi_stable", "cglue-macro", @@ -132,7 +132,7 @@ dependencies = [ [[package]] name = "cglue-macro" -version = "0.2.2" +version = "0.2.3" dependencies = [ "cglue-gen", "proc-macro2", diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index 5a718aa..e415910 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -802,7 +802,7 @@ impl ParsedFunc { _ => (quote!(), args, c_out), }; - let sig_life_declare = merge_lifetime_declarations(sig_life_declare, &parse_quote!(#hrtb)); + let sig_life_declare = merge_lifetime_declarations(&sig_life_declare, &parse_quote!(#hrtb)); let gen = quote! { #name: for<#sig_life_declare> extern "C" fn(#args #c_ret_params) #c_out, @@ -843,7 +843,7 @@ impl ParsedFunc { _ => (quote!(), args, c_out), }; - let sig_life_declare = merge_lifetime_declarations(sig_life_declare, &parse_quote!(#hrtb)); + let sig_life_declare = merge_lifetime_declarations(&sig_life_declare, &parse_quote!(#hrtb)); let doc_text = format!(" Getter for {}.", name); @@ -954,7 +954,7 @@ impl ParsedFunc { parse_quote!(#lifetime,) }; - let sig_life_declare = merge_lifetime_declarations(sig_life_declare, &life_declare); + let sig_life_declare = merge_lifetime_declarations(&sig_life_declare, &life_declare); let mut container_bound = quote!(); diff --git a/cglue-gen/src/util.rs b/cglue-gen/src/util.rs index 8b12d84..21bccfe 100644 --- a/cglue-gen/src/util.rs +++ b/cglue-gen/src/util.rs @@ -255,13 +255,13 @@ pub fn remap_type_lifetimes(ty: &mut Type, map: &BTreeMap) { } pub fn merge_lifetime_declarations( - a: Punctuated, + a: &Punctuated, b: &Punctuated, ) -> Punctuated { let mut life_declare = Punctuated::new(); let mut life_declared = HashSet::<&Ident>::new(); - for val in std::iter::IntoIterator::into_iter([&a, b]) { + for val in &[a, b] { for life in val.pairs() { let (val, punct) = life.into_tuple(); if life_declared.contains(&val.lifetime.ident) { From 3363187e54713c01ae25a18a008b54bb2d5974c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Thu, 17 Nov 2022 01:12:09 +0200 Subject: [PATCH 09/41] Clippy fix --- Cargo.lock | 2 -- cglue-bindgen/src/main.rs | 2 +- cglue-bindgen/src/types.rs | 2 +- cglue-gen/src/func.rs | 16 ++++++---------- cglue-gen/src/generics.rs | 23 ++++++++++------------- cglue-gen/src/traits.rs | 2 +- cglue-gen/src/util.rs | 11 ++++------- cglue-macro/src/lib.rs | 2 +- cglue/src/arc.rs | 2 +- cglue/src/boxed.rs | 2 +- cglue/src/callback.rs | 3 ++- cglue/src/trait_group.rs | 4 ++-- cglue/src/vec.rs | 8 ++++++-- 13 files changed, 36 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6eabf3..3b1d32d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "abi_stable" version = "0.10.4" diff --git a/cglue-bindgen/src/main.rs b/cglue-bindgen/src/main.rs index e8aae4f..86b59ee 100644 --- a/cglue-bindgen/src/main.rs +++ b/cglue-bindgen/src/main.rs @@ -124,7 +124,7 @@ fn main() -> Result<()> { let mut cmd = if use_nightly { let mut cmd = Command::new("rustup"); - cmd.args(&["run", "nightly", "cbindgen"]); + cmd.args(["run", "nightly", "cbindgen"]); cmd } else { diff --git a/cglue-bindgen/src/types.rs b/cglue-bindgen/src/types.rs index d4d3249..1f989ec 100644 --- a/cglue-bindgen/src/types.rs +++ b/cglue-bindgen/src/types.rs @@ -455,7 +455,7 @@ impl Vtable { ("", "", false), ); - ret += ®ex.replace_all(&wrapper.replace("\n", "\n "), "$1$2"); + ret += ®ex.replace_all(&wrapper.replace('\n', "\n "), "$1$2"); } ret diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index e415910..340edd9 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -180,8 +180,8 @@ fn do_wrap_type<'a>( targets: &'a BTreeMap, WrappedType>, ) -> Option<(Type, Option, &'a WrappedType)> { match ty { - Type::Reference(r) => do_wrap_type(&mut *r.elem, targets), - Type::Slice(s) => do_wrap_type(&mut *s.elem, targets), + Type::Reference(r) => do_wrap_type(&mut r.elem, targets), + Type::Slice(s) => do_wrap_type(&mut s.elem, targets), Type::Path(p) => { let mut iter = p.path.segments.iter(); match (&p.qself, p.path.leading_colon, iter.next(), iter.next()) { @@ -247,12 +247,8 @@ fn do_wrap_type<'a>( None } - Type::Ptr(ptr) => do_wrap_type(&mut *ptr.elem, targets), - Type::Tuple(tup) => tup - .elems - .iter_mut() - .filter_map(|e| do_wrap_type(e, targets)) - .next(), + Type::Ptr(ptr) => do_wrap_type(&mut ptr.elem, targets), + Type::Tuple(tup) => tup.elems.iter_mut().find_map(|e| do_wrap_type(e, targets)), // TODO: Other types _ => None, } @@ -308,7 +304,7 @@ impl TraitArgConv { } FnArg::Typed(t) => { let mut t = t.clone(); - let _old = do_wrap_type(&mut *t.ty, targets); + let _old = do_wrap_type(&mut t.ty, targets); let name = &*t.pat; @@ -589,7 +585,7 @@ impl ParsedFunc { self.out .injected_ret_tmp_static .as_ref() - .or_else(|| self.out.injected_ret_tmp.as_ref()), + .or(self.out.injected_ret_tmp.as_ref()), ) { let gen = if self.receiver.mutability.is_some() { quote!(#name: ::core::mem::MaybeUninit<#ty>,) diff --git a/cglue-gen/src/generics.rs b/cglue-gen/src/generics.rs index 5293440..b4bafda 100644 --- a/cglue-gen/src/generics.rs +++ b/cglue-gen/src/generics.rs @@ -272,13 +272,10 @@ impl ParsedGenerics { recurse_type_to_path(ty, |path| { let mut generics = None; for part in path.segments.pairs_mut() { - match part { - punctuated::Pair::End(p) => { - if let PathArguments::AngleBracketed(arg) = &mut p.arguments { - generics = Some(arg); - } + if let punctuated::Pair::End(p) = part { + if let PathArguments::AngleBracketed(arg) = &mut p.arguments { + generics = Some(arg); } - _ => {} } } @@ -296,17 +293,17 @@ impl ParsedGenerics { pub fn extract_lifetimes(&mut self, ty: &Type) { fn extract_nonpath_lifetimes(ty: &Type, out: &mut HashSet) { match ty { - Type::Array(TypeArray { elem, .. }) => extract_nonpath_lifetimes(&*elem, out), - Type::Group(TypeGroup { elem, .. }) => extract_nonpath_lifetimes(&*elem, out), - Type::Paren(TypeParen { elem, .. }) => extract_nonpath_lifetimes(&*elem, out), - Type::Ptr(TypePtr { elem, .. }) => extract_nonpath_lifetimes(&*elem, out), + Type::Array(TypeArray { elem, .. }) => extract_nonpath_lifetimes(elem, out), + Type::Group(TypeGroup { elem, .. }) => extract_nonpath_lifetimes(elem, out), + Type::Paren(TypeParen { elem, .. }) => extract_nonpath_lifetimes(elem, out), + Type::Ptr(TypePtr { elem, .. }) => extract_nonpath_lifetimes(elem, out), Type::Reference(TypeReference { elem, lifetime, .. }) => { if let Some(lifetime) = lifetime { out.insert(lifetime.clone()); } - extract_nonpath_lifetimes(&*elem, out) + extract_nonpath_lifetimes(elem, out) } - Type::Slice(TypeSlice { elem, .. }) => extract_nonpath_lifetimes(&*elem, out), + Type::Slice(TypeSlice { elem, .. }) => extract_nonpath_lifetimes(elem, out), _ => (), } } @@ -568,7 +565,7 @@ impl Parse for GenericCastType { let cast: ExprCast = input.parse()?; let ident = cast.expr; - let target = GenericType::from_type(&*cast.ty, true); + let target = GenericType::from_type(&cast.ty, true); Ok(Self { ident, target }) } diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index aebfd6f..99b8de1 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -640,7 +640,7 @@ pub fn parse_trait( }) .next(); - let int_result = int_result_new.as_ref().or_else(|| int_result.as_ref()); + let int_result = int_result_new.as_ref().or(int_result.as_ref()); funcs.extend(ParsedFunc::new( m.sig.clone(), diff --git a/cglue-gen/src/util.rs b/cglue-gen/src/util.rs index 21bccfe..0683ec8 100644 --- a/cglue-gen/src/util.rs +++ b/cglue-gen/src/util.rs @@ -130,13 +130,10 @@ pub fn extract_generics(ty: &mut Type) -> GenericsOut { recurse_type_to_path(ty, |path| { let mut generics = None; for part in path.segments.pairs() { - match part { - punctuated::Pair::End(p) => { - if let PathArguments::AngleBracketed(arg) = &p.arguments { - generics = Some(arg.args.clone()); - } + if let punctuated::Pair::End(p) = part { + if let PathArguments::AngleBracketed(arg) = &p.arguments { + generics = Some(arg.args.clone()); } - _ => {} } } generics @@ -209,7 +206,7 @@ pub fn remap_type_lifetimes(ty: &mut Type, map: &BTreeMap) { } Type::Path(TypePath { path, qself, .. }) => { if let Some(s) = qself.as_mut() { - remap_type_lifetimes(&mut *s.ty, map); + remap_type_lifetimes(&mut s.ty, map); } for seg in path.segments.iter_mut() { match &mut seg.arguments { diff --git a/cglue-macro/src/lib.rs b/cglue-macro/src/lib.rs index 62c001d..5f972c5 100644 --- a/cglue-macro/src/lib.rs +++ b/cglue-macro/src/lib.rs @@ -4,7 +4,7 @@ extern crate proc_macro; use cglue_gen::ext::{ext_abs_remap, prelude_remap_with_ident}; use cglue_gen::forward::gen_forward; -use cglue_gen::generics::{GenericCastType, GenericType}; +use cglue_gen::generics::GenericCastType; use cglue_gen::trait_groups::*; use proc_macro::TokenStream; use quote::ToTokens; diff --git a/cglue/src/arc.rs b/cglue/src/arc.rs index 059309c..0dc37a3 100644 --- a/cglue/src/arc.rs +++ b/cglue/src/arc.rs @@ -238,7 +238,7 @@ impl CArcSome { /// Converts `CArcSome` into `Arc` /// - /// # SAFETY: + /// # Safety /// /// This function is only safe when the underlying arc was created in the same binary/library. /// If a third-party arc is used, the behavior is undefined. diff --git a/cglue/src/boxed.rs b/cglue/src/boxed.rs index e40d6c2..1af477c 100644 --- a/cglue/src/boxed.rs +++ b/cglue/src/boxed.rs @@ -130,7 +130,7 @@ unsafe impl<'a, T> Opaquable for CSliceBox<'a, T> { type OpaqueTarget = CSliceBox<'a, c_void>; } -unsafe extern "C" fn cglue_drop_slice_box<'a, T>(this: &mut CSliceMut<'a, T>) { +unsafe extern "C" fn cglue_drop_slice_box(this: &mut CSliceMut<'_, T>) { // SAFETY: we extend the lifetime of the reference but free the underlying data immediately and // not use the reference again. let extended_instance = (this as *mut CSliceMut<_>).as_mut().unwrap(); diff --git a/cglue/src/callback.rs b/cglue/src/callback.rs index 059cdf4..635b952 100644 --- a/cglue/src/callback.rs +++ b/cglue/src/callback.rs @@ -106,7 +106,7 @@ pub trait FeedCallback { } } -impl<'a, I: std::iter::IntoIterator, T> FeedCallback for I { +impl, T> FeedCallback for I { fn feed_into_mut(self, callback: &mut OpaqueCallback) -> usize { let mut cnt = 0; for v in self { @@ -120,6 +120,7 @@ impl<'a, I: std::iter::IntoIterator, T> FeedCallback for I { } pub trait FromExtend: Extend + Sized { + #[allow(clippy::wrong_self_convention)] fn from_extend(&mut self) -> OpaqueCallback { extern "C" fn callback, T>(v: &mut C, context: T) -> bool { v.extend(Some(context)); diff --git a/cglue/src/trait_group.rs b/cglue/src/trait_group.rs index ab03b2d..1df5f87 100644 --- a/cglue/src/trait_group.rs +++ b/cglue/src/trait_group.rs @@ -157,7 +157,7 @@ impl GetVtbl for CGlueTraitObj<'_, T, V, C, R> { // Conversions into container type itself. // Needed when generated code returns Self -impl<'a, T: Deref, F, C: ContextBounds, R: Default> From<(T, C)> +impl, F, C: ContextBounds, R: Default> From<(T, C)> for CGlueObjContainer { fn from((instance, context): (T, C)) -> Self { @@ -169,7 +169,7 @@ impl<'a, T: Deref, F, C: ContextBounds, R: Default> From<(T, C)> } } -impl<'a, T: Deref, F, R: Default> From for CGlueObjContainer { +impl, F, R: Default> From for CGlueObjContainer { fn from(this: T) -> Self { Self::from((this, Default::default())) } diff --git a/cglue/src/vec.rs b/cglue/src/vec.rs index b51dad1..225dd6a 100644 --- a/cglue/src/vec.rs +++ b/cglue/src/vec.rs @@ -56,7 +56,7 @@ impl core::fmt::Debug for CVec { } } -impl<'a, T> core::ops::Deref for CVec { +impl core::ops::Deref for CVec { type Target = [T]; fn deref(&self) -> &Self::Target { @@ -64,7 +64,7 @@ impl<'a, T> core::ops::Deref for CVec { } } -impl<'a, T> core::ops::DerefMut for CVec { +impl core::ops::DerefMut for CVec { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { core::slice::from_raw_parts_mut(self.data, self.len) } } @@ -75,6 +75,10 @@ impl CVec { self.len } + pub fn is_empty(&self) -> bool { + self.len == 0 + } + pub fn capacity(&self) -> usize { self.capacity } From 626ef545b7206c9551c5440f0f35461d7a4dba8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Thu, 17 Nov 2022 01:16:19 +0200 Subject: [PATCH 10/41] Update CHANGELOG, fix old builds --- CHANGELOG.md | 4 ++++ README.md | 1 + cglue-bindgen/src/main.rs | 2 +- cglue-gen/Cargo.toml | 2 +- cglue/src/lib.rs | 1 + 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e097ad6..d3e3226 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CGlue changelog +## Changes in 0.2.12: + +[Initial support for GAT lifetimes](https://github.com/h33p/cglue/commit/1a8098181896bb730d276aea59464d577e5d8927) + ## Changes in 0.2.11: [Fix a safety bug with slices](https://github.com/h33p/cglue/commit/cbb25367cf7867f07b0a2c7718f894de437f22eb) diff --git a/README.md b/README.md index 3cc556e..eed3590 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ If all code is glued together, our glue is the safest on the market. - [External traits](#external-traits) - [Type wrapping](#type-wrapping) - [Associated type wrapping](#associated-type-wrapping) + - [Generic associated types](#generic-associated-types) - [Plugin system](#plugin-system) - [Working with cbindgen](#working-with-cbindgen) - [Setup](#setup) diff --git a/cglue-bindgen/src/main.rs b/cglue-bindgen/src/main.rs index 86b59ee..e8aae4f 100644 --- a/cglue-bindgen/src/main.rs +++ b/cglue-bindgen/src/main.rs @@ -124,7 +124,7 @@ fn main() -> Result<()> { let mut cmd = if use_nightly { let mut cmd = Command::new("rustup"); - cmd.args(["run", "nightly", "cbindgen"]); + cmd.args(&["run", "nightly", "cbindgen"]); cmd } else { diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index 39b414a..e5f02d5 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-gen" -version = "0.2.5" +version = "0.2.6" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe code generation for making plugins and C-compatible libraries" diff --git a/cglue/src/lib.rs b/cglue/src/lib.rs index 1137c31..1fa3678 100644 --- a/cglue/src/lib.rs +++ b/cglue/src/lib.rs @@ -28,6 +28,7 @@ //! - [External traits](#external-traits) //! - [Type wrapping](#type-wrapping) //! - [Associated type wrapping](#associated-type-wrapping) +//! - [Generic associated types](#generic-associated-types) //! - [Plugin system](#plugin-system) //! - [Working with cbindgen](#working-with-cbindgen) //! - [Setup](#setup) From febce1167090947b13486585dca8226b5269bca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Thu, 17 Nov 2022 18:28:48 +0000 Subject: [PATCH 11/41] Fix flight regression in cglue_impl_group generation --- Cargo.lock | 4 +- cglue-gen/Cargo.toml | 2 +- cglue-gen/src/trait_groups.rs | 60 +++++++++++++++++---- cglue/src/tests/generics/generic_structs.rs | 20 +++++++ 4 files changed, 74 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b1d32d..9cf0089 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "abi_stable" version = "0.10.4" @@ -118,7 +120,7 @@ dependencies = [ [[package]] name = "cglue-gen" -version = "0.2.5" +version = "0.2.7" dependencies = [ "itertools", "lazy_static", diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index e5f02d5..1809c0b 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-gen" -version = "0.2.6" +version = "0.2.7" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe code generation for making plugins and C-compatible libraries" diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index 0a0cbf2..de9bb8e 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -334,14 +334,42 @@ impl TraitGroupImpl { let ParsedGenerics { gen_declare, gen_where_bounds, - life_declare, + mut life_declare, + mut life_use, .. } = [&self.ty_generics, &self.generics] .iter() .copied() .collect(); - let gen_lt_bounds = self.generics.declare_lt_for_all("e!('cglue_a)); + // If no lifetimes are used, default to 'cglue_a + if life_use.is_empty() { + assert!(life_declare.is_empty()); + let lifetime = Lifetime { + apostrophe: proc_macro2::Span::call_site(), + ident: format_ident!("cglue_a"), + }; + life_use.push_value(lifetime.clone()); + life_declare.push_value(LifetimeDef { + lifetime, + attrs: Default::default(), + bounds: Default::default(), + colon_token: Default::default(), + }); + } + + if !life_declare.trailing_punct() { + life_declare.push_punct(Default::default()); + } + + if !life_use.trailing_punct() { + life_use.push_punct(Default::default()); + } + + // Lifetime should always exist based on previous code + let first_life = life_use.first().unwrap(); + + let gen_lt_bounds = self.generics.declare_lt_for_all("e!(#first_life)); let gen_sabi_bounds = self.generics.declare_sabi_for_all(&crate_path); let gen_where_bounds = quote! { @@ -362,13 +390,14 @@ impl TraitGroupImpl { quote!(CGlueCtx), &self.generics, Some(quote!(Self)).as_ref(), + first_life, ); let gen = quote! { - impl<'cglue_a, #life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> - #group_path #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use> for #ty + impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + #group_path #filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use> for #ty where #gen_where_bounds #vtbl_where_bounds { - fn fill_table(table: #group_path #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> #group_path #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use> { + fn fill_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use> { table #implemented_tables } } @@ -377,7 +406,7 @@ impl TraitGroupImpl { if let Some(fwd_vtbl) = &self.fwd_implemented_vtbl { let fwd_filler_trait = format_ident!("{}FwdVtableFiller", group); - let fwd_ty = quote!(#crate_path::forward::Fwd<&'cglue_a mut #ty>); + let fwd_ty = quote!(#crate_path::forward::Fwd<&#first_life mut #ty>); let implemented_tables = TraitGroup::enable_opt_vtbls(fwd_vtbl.iter()); let vtbl_where_bounds = TraitGroup::vtbl_where_bounds( @@ -387,18 +416,19 @@ impl TraitGroupImpl { quote!(CGlueCtx), &self.generics, Some(quote!(Self)).as_ref(), + first_life, ); quote! { #gen - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> - #group_path #fwd_filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use> for #ty + impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + #group_path #fwd_filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use> for #ty where #cont_name: #crate_path::trait_group::CGlueObjBase, #gen_where_bounds #vtbl_where_bounds { - fn fill_fwd_table(table: #group_path #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> #group_path #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use> { + fn fill_fwd_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use> { table #implemented_tables } } @@ -570,6 +600,11 @@ impl TraitGroup { #gen_sabi_bounds }; + let cglue_a_lifetime = Lifetime { + apostrophe: proc_macro2::Span::call_site(), + ident: format_ident!("cglue_a"), + }; + let mandatory_vtbl_defs = self.mandatory_vtbl_defs(self.mandatory_vtbl.iter()); let optional_vtbl_defs = self.optional_vtbl_defs(quote!(CGlueInst), quote!(CGlueCtx)); let optional_vtbl_defs_boxed = self.optional_vtbl_defs( @@ -600,6 +635,7 @@ impl TraitGroup { quote!(CGlueCtx), &self.generics, None, + &cglue_a_lifetime, ); let vtbl_where_bounds_noctx = Self::vtbl_where_bounds( self.mandatory_vtbl.iter(), @@ -608,6 +644,7 @@ impl TraitGroup { quote!(#trg_path::NoContext), &self.generics, None, + &cglue_a_lifetime, ); let vtbl_where_bounds_boxed = Self::vtbl_where_bounds( self.mandatory_vtbl.iter(), @@ -616,6 +653,7 @@ impl TraitGroup { quote!(#crate_path::trait_group::NoContext), &self.generics, None, + &cglue_a_lifetime, ); let vtbl_where_bounds_ctxboxed = Self::vtbl_where_bounds( self.mandatory_vtbl.iter(), @@ -624,6 +662,7 @@ impl TraitGroup { quote!(CGlueCtx), &self.generics, None, + &cglue_a_lifetime, ); let ret_tmp_defs = self.ret_tmp_defs(self.optional_vtbl.iter()); @@ -1962,6 +2001,7 @@ impl TraitGroup { ctx_ident: TokenStream, all_generics: &ParsedGenerics, trait_bound: Option<&TokenStream>, + vtbl_lifetime: &Lifetime, ) -> TokenStream { let mut ret = TokenStream::new(); @@ -1990,7 +2030,7 @@ impl TraitGroup { ret.extend(quote!(#trait_bound: #path #ident<#life_use #gen_use>,)); } - ret.extend(quote!(&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name<#container_ident, #ctx_ident, #all_gen_use>, #gen_use>: 'cglue_a + Default,)); + ret.extend(quote!(&#vtbl_lifetime #path #vtbl_typename<#vtbl_lifetime, #cont_name<#container_ident, #ctx_ident, #all_gen_use>, #gen_use>: #vtbl_lifetime + Default,)); } ret diff --git a/cglue/src/tests/generics/generic_structs.rs b/cglue/src/tests/generics/generic_structs.rs index 0030a29..dbd7cdc 100644 --- a/cglue/src/tests/generics/generic_structs.rs +++ b/cglue/src/tests/generics/generic_structs.rs @@ -23,9 +23,29 @@ impl TA for GA { } } +#[derive(Clone)] +pub struct Lifetimed<'a, T> { + val: &'a T, +} + +impl<'a, T> Getter for Lifetimed<'a, T> { + fn get_val(&self) -> &T { + self.val + } +} + +impl<'a> TA for Lifetimed<'a, usize> { + extern "C" fn ta_1(&self) -> usize { + *self.val + } +} + cglue_trait_group!(GenGroup, Getter, { TA }); cglue_impl_group!(GA, GenGroup, { TA }); cglue_impl_group!(GA, GenGroup, {}); +// Internally, the macro prefers to emit 'cglue_a and both of these cases should "just work" +cglue_impl_group!(Lifetimed<'a, T: Eq>, GenGroup, { TA }); +cglue_impl_group!(Lifetimed<'cglue_a, T = u64>, GenGroup, {}); #[test] fn use_getter() { From 081c590f4eb97b1be10eaeaa9cbf87e7278ea8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Fri, 9 Jun 2023 14:37:23 +0200 Subject: [PATCH 12/41] Automatically wrap 'Into' arguments --- Cargo.lock | 4 +--- cglue-gen/Cargo.toml | 2 +- cglue-gen/src/func.rs | 40 ++++++++++++++++++++++++++++++-- cglue-gen/src/generics.rs | 3 ++- cglue-gen/src/traits.rs | 20 +++++++++------- cglue/src/tests/simple/traits.rs | 13 +++++++++++ 6 files changed, 66 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9cf0089..3b1d32d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "abi_stable" version = "0.10.4" @@ -120,7 +118,7 @@ dependencies = [ [[package]] name = "cglue-gen" -version = "0.2.7" +version = "0.2.5" dependencies = [ "itertools", "lazy_static", diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index 1809c0b..0a9d8be 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-gen" -version = "0.2.7" +version = "0.2.9" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe code generation for making plugins and C-compatible libraries" diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index 340edd9..0407e3e 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -426,6 +426,31 @@ impl TraitArgConv { } } } + Type::ImplTrait(t) => { + // Convert `impl Into` to `T`. + if t.bounds.len() == 1 { + if let TypeParamBound::Trait(t) = t.bounds.first().unwrap() { + if t.path.segments.len() == 1 { + let seg = t.path.segments.first().unwrap(); + if seg.ident == format_ident!("Into") { + if let PathArguments::AngleBracketed(a) = &seg.arguments { + if a.args.len() == 1 { + let ty = a.args.first().unwrap(); + + ret = Some(( + quote!(let #name = #name.into();), + quote!(#name,), + quote!(#name: #ty,), + quote!(#name: #ty,), + quote!(#name,), + )) + } + } + } + } + } + } + } _ => {} } @@ -942,6 +967,12 @@ impl ParsedFunc { quote!(#life_use) }; + let tmp_lifetime_anon = if *use_hrtb && !life_use.is_empty() { + quote!('_, ) + } else { + quote!(#life_use) + }; + // Inject 'cglue_a if there are no lifetimes declared by the trait, // and temp lifetime is needed let life_declare = if lifetime.is_none() || !life_declare.is_empty() { @@ -990,7 +1021,7 @@ impl ParsedFunc { let inner_impl = if let Some(body) = self.custom_conv.c_inner_body.as_ref() { body.clone() } else { - quote!(this.#name(#call_args)) + quote!(>::#name(this, #call_args)) }; let c_where_bounds = if lifetime_cast.is_some() && *unbounded_hrtb { @@ -1353,7 +1384,12 @@ impl ParsedReturnType { (ty.mutability.is_some(), ty.lifetime.as_ref().cloned()) } (false, _) => (false, None), - _ => panic!("Wrapped ref return currently only valid for references!"), + _ => { + panic!( + "Wrapped ref return currently only valid for references! (ty: {ty})", + ty = ty.to_token_stream() + ) + } }; let unbounded_hrtb = lifetime.is_none() && lifetime_type_bound.is_none(); diff --git a/cglue-gen/src/generics.rs b/cglue-gen/src/generics.rs index b4bafda..59f1fb9 100644 --- a/cglue-gen/src/generics.rs +++ b/cglue-gen/src/generics.rs @@ -594,9 +594,10 @@ impl GenericType { } pub fn push_types_start(&mut self, types: TokenStream) { + let typestr = types.to_string(); let mut types = syn::parse::Parser::parse2(Punctuated::::parse_terminated, types) - .expect("Invalid types provided"); + .expect(&format!("Invalid types provided: {}", typestr)); if !types.trailing_punct() { types.push_punct(Default::default()); diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index 99b8de1..f2437c5 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -268,7 +268,7 @@ pub fn process_item( ); } } else if x == "wrap_with_group_ref" || x == "wrap_with_obj_ref" { - let no_context = quote!(CGlueC::Context); //#crate_path::trait_group::NoContext); + let no_context = quote!(CGlueC::Context); new_ty.push_types_start(quote!(&#lifetime #c_void, CGlueC::Context,)); new_ty_ret_tmp.push_types_start(quote!(&#lifetime #c_void, CGlueCtx,)); new_ty_trait_impl.push_types_start( @@ -281,14 +281,16 @@ pub fn process_item( quote!(&#from_lifetime_simple #c_void, CGlueC::Context,), ); new_ty_static.push_types_start(quote!(&'static #c_void, CGlueCtx,)); - from_new_ty.push_types_start( - quote!(&#from_lifetime >::#ty_def, #no_context,), - ); - from_new_ty_ref.extend(quote!(&#from_lifetime)); - from_new_ty_simple.push_types_start( - quote!(&#from_lifetime_simple >::#ty_def, #no_context,), - ); - from_new_ty_simple_ref.extend(quote!(&#from_lifetime_simple)); + if let Some((cglue_f_ty_def, cglue_f_ty_simple_ident)) = &cglue_f_tys { + from_new_ty.push_types_start( + quote!(&#from_lifetime #cglue_f_ty_def, #no_context,), + ); + from_new_ty_ref.extend(quote!(&#from_lifetime)); + from_new_ty_simple.push_types_start( + quote!(&#from_lifetime_simple #cglue_f_ty_simple_ident, #no_context,), + ); + from_new_ty_simple_ref.extend(quote!(&#from_lifetime_simple)); + } } else if x == "wrap_with_group_mut" || x == "wrap_with_obj_mut" { let no_context = quote!(CGlueC::Context); new_ty diff --git a/cglue/src/tests/simple/traits.rs b/cglue/src/tests/simple/traits.rs index a291e49..eb6f988 100644 --- a/cglue/src/tests/simple/traits.rs +++ b/cglue/src/tests/simple/traits.rs @@ -47,12 +47,18 @@ pub trait WithAliasIntResult { } } +#[cglue_trait] +pub trait WithInto { + fn winto_1(&self, _into: impl Into) {} +} + struct Implementor {} impl WithSlice for Implementor {} impl WithOptions for Implementor {} impl WithIntResult for Implementor {} impl WithAliasIntResult for Implementor {} +impl WithInto for Implementor {} type ICont = crate::trait_group::CGlueObjContainer; type IRefCont = ICont<&'static Implementor, C>; @@ -62,6 +68,7 @@ type WSCont = IMutCont>; type WOCont = IMutCont>; type WIRCont = IRefCont>; type WAIRCont = IRefCont>; +type WINTOCont = IRefCont>; #[test] fn slices_wrapped() { @@ -119,3 +126,9 @@ fn alias_no_int_result() { let _: unsafe extern "C" fn(&WAIRCont, usize) -> crate::result::CResult = vtbl.waint_2(); } + +#[test] +fn into_t_wrapped() { + let vtbl = <&WithIntoVtbl>::default(); + let _: unsafe extern "C" fn(&WINTOCont, usize) = vtbl.winto_1(); +} From 9fbee903963b1b407ca218609e43a65cfd1eb219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Tue, 20 Jun 2023 18:49:56 +0200 Subject: [PATCH 13/41] Add unstable task feature --- .github/workflows/build.yml | 45 ++- Cargo.lock | 157 +++++----- cglue/Cargo.toml | 12 + cglue/src/lib.rs | 5 + cglue/src/option.rs | 4 + cglue/src/task/mod.rs | 132 +++++++++ cglue/src/task/sound.rs | 271 ++++++++++++++++++ cglue/src/task/unsound.rs | 125 ++++++++ .../src/tests/generics/generic_associated.rs | 2 +- 9 files changed, 668 insertions(+), 85 deletions(-) create mode 100644 cglue/src/task/mod.rs create mode 100644 cglue/src/task/sound.rs create mode 100644 cglue/src/task/unsound.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ffb02c1..d986017 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, ubuntu-latest, windows-latest] + os: [macos-11, ubuntu-latest, windows-latest] toolchain: ["1.45.0", "stable"] steps: - uses: actions/checkout@v2 @@ -22,13 +22,40 @@ jobs: override: true - name: Build without examples - run: cargo build --verbose -p cglue + run: | + cd cglue + cargo build --verbose + + build-extra-features: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-12, ubuntu-latest, windows-latest] + # 1.57 is needed for const panic + # panic in const is used to verify waker layouts + toolchain: ["1.57.0", "stable"] + features: [ + "--features task_unstable", + "--features task_unstable,task_unsound", + "--features layout_checks" + ] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.toolchain }} + override: true + + - name: Build without examples + run: | + cd cglue + cargo build --verbose ${{ matrix.features }} build-with-layouts: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, ubuntu-latest, windows-latest] + os: [macos-11, ubuntu-latest, windows-latest] toolchain: ["1.46.0", "stable"] steps: - uses: actions/checkout@v2 @@ -47,8 +74,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, ubuntu-latest, windows-latest] - toolchain: ["1.46.0", "stable", "nightly-2021-11-05"] + os: [macos-11, ubuntu-latest, windows-latest] + toolchain: ["1.57.0", "stable", "nightly-2021-11-05"] steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -88,7 +115,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, ubuntu-latest, windows-latest] + os: [macos-11, ubuntu-latest, windows-latest] toolchain: ["1.45.0", "stable"] steps: - uses: actions/checkout@v2 @@ -104,8 +131,8 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, ubuntu-latest, windows-latest] - toolchain: ["1.46.0", "stable", "nightly-2021-11-05"] + os: [macos-11, ubuntu-latest, windows-latest] + toolchain: ["1.57.0", "stable", "nightly-2021-11-05"] steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -122,7 +149,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - features: ["--all-features", ""] + features: ["--all-features", "", "-p cglue --features task_unstable", "-p cglue --features task_unstable,task_unsound"] steps: - uses: actions/checkout@v2 - run: rustup component add clippy diff --git a/Cargo.lock b/Cargo.lock index 3b1d32d..d48db50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,9 +49,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -102,6 +102,7 @@ dependencies = [ "no-std-compat", "rustc_version 0.4.0", "serde", + "tarc", "try_default", ] @@ -118,7 +119,7 @@ dependencies = [ [[package]] name = "cglue-gen" -version = "0.2.5" +version = "0.2.9" dependencies = [ "itertools", "lazy_static", @@ -140,24 +141,24 @@ dependencies = [ [[package]] name = "core_extensions" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b110b7cd430bd590fa60a5ba58a383488dab61912318bfb05d968a80cdda6d" +checksum = "92c71dc07c9721607e7a16108336048ee978c3a8b129294534272e8bac96c0ee" dependencies = [ "core_extensions_proc_macros", ] [[package]] name = "core_extensions_proc_macros" -version = "1.5.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c348a81513f573054124b9f10e258a654a0519b65f2dba0142307bd3c7b5b8b6" +checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6" [[package]] name = "crossbeam-channel" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -165,27 +166,26 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.10" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if 1.0.0", - "once_cell", ] [[package]] name = "either" -version = "1.6.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "generational-arena" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d3b771574f62d0548cee0ad9057857e9fc25d7a3335f140c84f6acd0bf601" +checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", ] [[package]] @@ -199,18 +199,18 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "lazy_static" @@ -220,15 +220,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "libloading" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ "cfg-if 1.0.0", "winapi", @@ -236,9 +236,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -246,11 +246,11 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 0.1.10", ] [[package]] @@ -267,9 +267,9 @@ checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" [[package]] name = "once_cell" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" [[package]] name = "parking_lot" @@ -284,9 +284,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if 1.0.0", "instant", @@ -298,9 +298,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.7" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "plugin-api" @@ -322,46 +322,47 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ + "once_cell", "thiserror", "toml", ] [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.20" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -370,15 +371,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "repr_offset" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "663e92f38214b9e51fa305902788f5fb45fb60027b727556618fc53ba1946112" +checksum = "fb1070755bd29dffc19d0971cab794e607839ba2ef4b69a9e6fbc8733c1b72ea" dependencies = [ "tstr", ] @@ -398,14 +399,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.10", + "semver 1.0.17", ] [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "scopeguard" @@ -424,9 +425,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.10" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "semver-parser" @@ -436,18 +437,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" dependencies = [ "proc-macro2", "quote", @@ -456,9 +457,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" dependencies = [ "itoa", "ryu", @@ -467,35 +468,41 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "syn" -version = "1.0.98" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "tarc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cda220d0551690e4c54ba6c0c229ee298544fe52a93ee6cf022c94b72883f5" + [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ "proc-macro2", "quote", @@ -504,9 +511,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -534,15 +541,15 @@ checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a" [[package]] name = "typed-arena" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "user-bin" diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 2049dd4..4c757a9 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -18,13 +18,25 @@ serde = { version = "1", optional = true, default-features = false, features = [ try_default = { version = "= 1.0.0", optional = true } abi_stable = { version = "0.10", optional = true } log = { version = "0.4", optional = true } +tarc = "0.1" [build-dependencies] rustc_version = "0.4" +# Need to uncomment these before cargo update to keep hashbrown on rust 2018 edition +#indexmap = "~1.8" +#once_cell = "~1.14" +#thiserror = "=1.0.24" +#thiserror-impl = "=1.0.24" +#serde = "=1.0.127" [features] default = ["std"] std = ["no-std-compat/std"] rust_void = ["cglue-macro/rust_void"] unstable = ["cglue-macro/unstable", "try_default"] +task_unstable = [] +task_unsound = [] layout_checks = ["cglue-macro/layout_checks", "abi_stable"] + +[package.metadata.docs.rs] +features = ["std", "task_unstable"] diff --git a/cglue/src/lib.rs b/cglue/src/lib.rs index 1fa3678..4fb781e 100644 --- a/cglue/src/lib.rs +++ b/cglue/src/lib.rs @@ -988,6 +988,7 @@ //! It is available in [CHANGELOG.md](https://github.com/h33p/cglue/blob/main/CHANGELOG.md) file. //! +#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(not(feature = "std"), no_std)] extern crate no_std_compat as std; @@ -1005,6 +1006,10 @@ pub mod trait_group; pub mod tuple; pub mod vec; +#[cfg(feature = "task_unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "task_unstable")))] +pub mod task; + pub use ::cglue_macro::{ as_mut, as_ref, cast, cglue_forward, cglue_forward_ext, cglue_impl_group, cglue_trait, cglue_trait_ext, cglue_trait_group, custom_impl, group_obj, int_result, into, no_int_result, diff --git a/cglue/src/option.rs b/cglue/src/option.rs index 2eb4cf0..5e01092 100644 --- a/cglue/src/option.rs +++ b/cglue/src/option.rs @@ -63,6 +63,10 @@ impl COption { COption::None => None, } } + + pub fn take(&mut self) -> Option { + core::mem::take(self).into() + } } #[cfg(feature = "serde")] diff --git a/cglue/src/task/mod.rs b/cglue/src/task/mod.rs new file mode 100644 index 0000000..880ee7a --- /dev/null +++ b/cglue/src/task/mod.rs @@ -0,0 +1,132 @@ +//! C-compatible task structures. + +#[cfg(not(feature = "task_unsound"))] +mod sound; +#[cfg(not(feature = "task_unsound"))] +pub use sound::*; + +#[cfg(feature = "task_unsound")] +mod unsound; +#[cfg(feature = "task_unsound")] +pub use unsound::*; + +use core::task::*; + +/// Actual type: unsafe fn(_: *const ()) -> RawWaker; +/// +/// However, we don't want to expose it since it's not ABI safe. +#[cfg(not(feature = "task_unsound"))] +type CloneFn = *const (); +#[cfg(feature = "task_unsound")] +type CloneFn = unsafe fn(_: *const ()) -> RawWaker; + +/// Actual type: unsafe fn(_: *const ()); +/// +/// However, we do not want to expose it since it's not ABI safe. +#[cfg(not(feature = "task_unsound"))] +type OtherFn = *const (); +#[cfg(feature = "task_unsound")] +type OtherFn = unsafe fn(_: *const ()); + +#[repr(C)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +#[cfg_attr( + all(feature = "abi_stable", feature = "task_unsound"), + sabi(unsafe_opaque_fields) +)] +pub struct CRawWakerVTable { + clone: CloneFn, + wake: OtherFn, + wake_by_ref: OtherFn, + drop: OtherFn, +} + +#[repr(C)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +pub struct CRawWaker { + data: *const (), + vtable: &'static CRawWakerVTable, +} + +impl From<&Waker> for &CRawWaker { + fn from(w: &Waker) -> Self { + unsafe { &*(w as *const Waker as *const CRawWaker) } + } +} + +// Verify the layouts of reimplemented data structures +// +// Unfortunately, we cannot verify function ABI. +#[allow(clippy::useless_transmute)] +#[cfg(not(miri))] +const _: () = { + use core::mem::{size_of, transmute}; + + if size_of::() != size_of::() { + panic!("Raw waker size mismatch") + } + + if size_of::() != size_of::() { + panic!("Raw waker size mismatch") + } + + if size_of::() != size_of::() { + panic!("Raw waker vtbl size mismatch") + } + + macro_rules! comp_arr { + ($a:ident, $b:ident) => { + let mut cnt = 0; + while cnt < $a.len() { + if $a[cnt] != $b[cnt] { + panic!("buffers not equal!"); + } + cnt += 1; + } + }; + } + + // Verify the layout of the vtable. + + let clone: CloneFn = unsafe { transmute(1usize) }; + let wake: OtherFn = unsafe { transmute(2usize) }; + let wake_by_ref: OtherFn = unsafe { transmute(3usize) }; + let drop: OtherFn = unsafe { transmute(4usize) }; + + let vtbl = unsafe { + RawWakerVTable::new( + transmute(clone), + transmute(wake), + transmute(wake_by_ref), + transmute(drop), + ) + }; + let vtbl_c = CRawWakerVTable { + clone, + wake, + wake_by_ref, + drop, + }; + + let bvtbl = unsafe { transmute::<_, [u8; size_of::()]>(vtbl) }; + let bvtbl_c = unsafe { transmute::<_, [u8; size_of::()]>(vtbl_c) }; + + comp_arr!(bvtbl, bvtbl_c); + + // Verify the layout of the raw waker. + + let data = 10usize as *const (); + let vtbl: &'static RawWakerVTable = unsafe { transmute(20usize) }; + let vtbl_c: &'static CRawWakerVTable = unsafe { transmute(20usize) }; + + let waker = RawWaker::new(data, vtbl); + let waker_c = CRawWaker { + data, + vtable: vtbl_c, + }; + + let bwaker = unsafe { transmute::<_, [u8; size_of::()]>(waker) }; + let bwaker_c = unsafe { transmute::<_, [u8; size_of::()]>(waker_c) }; + + comp_arr!(bwaker, bwaker_c); +}; diff --git a/cglue/src/task/sound.rs b/cglue/src/task/sound.rs new file mode 100644 index 0000000..fbb1f9f --- /dev/null +++ b/cglue/src/task/sound.rs @@ -0,0 +1,271 @@ +use super::*; + +use core::cell::UnsafeCell; +use core::ptr::NonNull; +use core::sync::atomic::{AtomicBool, Ordering}; +use core::task::*; +use tarc::BaseArc; + +unsafe extern "C" fn clone_adapter(data: *const (), clone: *const ()) -> CRawWaker { + let clone: unsafe fn(*const ()) -> CRawWaker = core::mem::transmute(clone); + clone(data) +} + +unsafe extern "C" fn other_adapter(data: *const (), other: *const ()) { + let other: unsafe fn(_: *const ()) = core::mem::transmute(other); + other(data) +} + +#[repr(C)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +pub struct CWaker { + raw: CRawWaker, + clone_adapter: unsafe extern "C" fn(*const (), *const ()) -> CRawWaker, + other_adapter: unsafe extern "C" fn(*const (), *const ()), +} + +impl CWaker { + pub fn into_waker(this: BaseArc) -> Waker { + unsafe { Waker::from_raw(Self::into_raw_waker(this)) } + } + + pub fn into_raw_waker(this: BaseArc) -> RawWaker { + unsafe fn clone(data: *const ()) -> RawWaker { + let waker = data as *const CWaker; + BaseArc::increment_strong_count(waker); + CWaker::into_raw_waker(BaseArc::from_raw(waker)) + } + + unsafe fn wake(data: *const ()) { + let waker = &*(data as *const CWaker); + (waker.other_adapter)(waker.raw.data, waker.raw.vtable.wake_by_ref as _); + BaseArc::decrement_strong_count(waker); + } + + unsafe fn wake_by_ref(data: *const ()) { + let waker = &*(data as *const CWaker); + (waker.other_adapter)(waker.raw.data, waker.raw.vtable.wake_by_ref as _); + } + + unsafe fn drop(data: *const ()) { + BaseArc::decrement_strong_count(data as *const CWaker); + } + + let vtbl = &RawWakerVTable::new(clone, wake, wake_by_ref, drop); + RawWaker::new(this.into_raw() as *const (), vtbl) + } + + pub fn wake(self) { + let other_adapter = self.other_adapter; + let wake = self.raw.vtable.wake; + let data = self.raw.data; + // Don't call `drop` -- the waker will be consumed by `wake`. + core::mem::forget(self); + // SAFETY: This is safe because `Waker::from_raw` is the only way + // to initialize `wake` and `data` requiring the user to acknowledge + // that the contract of `RawWaker` is upheld. + + // This is also FFI-safe because `other_adapter` adapts the calling convention. + unsafe { (other_adapter)(data, wake as _) }; + } + + pub fn wake_by_ref(&self) { + let other_adapter = self.other_adapter; + let wake_by_ref = self.raw.vtable.wake_by_ref; + let data = self.raw.data; + // SAFETY: This is safe because `Waker::from_raw` is the only way + // to initialize `wake` and `data` requiring the user to acknowledge + // that the contract of `RawWaker` is upheld. + + // This is also FFI-safe because `other_adapter` adapts the calling convention. + unsafe { (other_adapter)(data, wake_by_ref as _) }; + } + + pub unsafe fn from_raw(raw: RawWaker) -> Self { + let raw: CRawWaker = core::mem::transmute(raw); + + Self { + raw, + clone_adapter, + other_adapter, + } + } +} + +impl Drop for CWaker { + fn drop(&mut self) { + let other_adapter = self.other_adapter; + let drop = self.raw.vtable.drop; + let data = self.raw.data; + // SAFETY: This is safe because `Waker::from_raw` is the only way + // to initialize `wake` and `data` requiring the user to acknowledge + // that the contract of `RawWaker` is upheld. + + // This is also FFI-safe because `other_adapter` adapts the calling convention. + unsafe { (other_adapter)(data, drop as *const ()) }; + } +} + +impl Clone for CWaker { + #[inline] + fn clone(&self) -> Self { + Self { + // SAFETY: This is safe because `Waker::from_raw` is the only way + // to initialize `clone` and `data` requiring the user to acknowledge + // that the contract of [`RawWaker`] is upheld. + raw: unsafe { (self.clone_adapter)(self.raw.data, self.raw.vtable.clone as *const ()) }, + clone_adapter: self.clone_adapter, + other_adapter: self.other_adapter, + } + } +} + +impl From for CWaker { + fn from(waker: Waker) -> Self { + unsafe { Self::from_raw(core::mem::transmute(waker)) } + } +} + +#[repr(C, u8)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +enum FastCWakerState<'a> { + Borrowed { + waker: &'a CRawWaker, + clone_adapter: unsafe extern "C" fn(*const (), *const ()) -> CRawWaker, + other_adapter: unsafe extern "C" fn(*const (), *const ()), + }, + Owned(NonNull), +} + +#[repr(C)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +pub struct FastCWaker<'a> { + lock: AtomicBool, + state: UnsafeCell>, +} + +impl<'a> FastCWaker<'a> { + #[allow(clippy::mut_from_ref)] + unsafe fn lock(&self) -> &mut FastCWakerState<'a> { + while self.lock.fetch_or(true, Ordering::Acquire) { + while self.lock.load(Ordering::Relaxed) { + #[allow(deprecated)] + core::sync::atomic::spin_loop_hint(); + } + } + unsafe { &mut *self.state.get() } + } + + fn release(&self) { + self.lock.store(false, Ordering::Release); + } +} + +impl<'a> Drop for FastCWakerState<'a> { + fn drop(&mut self) { + if let Self::Owned(s) = self { + unsafe { BaseArc::decrement_strong_count(s) }; + } + } +} + +impl<'a> From<&'a Waker> for FastCWaker<'a> { + fn from(waker: &'a Waker) -> Self { + Self { + lock: Default::default(), + state: UnsafeCell::new(FastCWakerState::Borrowed { + waker: waker.into(), + clone_adapter, + other_adapter, + }), + } + } +} + +impl<'a> FastCWaker<'a> { + pub fn with_waker(&self, cb: impl FnOnce(&Waker) -> T) -> T { + if let FastCWakerState::Owned(owned) = unsafe { self.lock() } { + let owned = unsafe { + let owned = owned.as_ptr(); + BaseArc::increment_strong_count(owned); + BaseArc::from_raw(owned) + }; + self.release(); + cb(&CWaker::into_waker(owned)) + } else { + self.release(); + // Create a waker that modifies self upon clone + + unsafe fn unreach(_: *const ()) { + unreachable!() + } + unsafe fn clone(data: *const ()) -> RawWaker { + let this = &*(data as *const FastCWaker); + CWaker::into_raw_waker(this.c_waker()) + } + unsafe fn wake_by_ref(data: *const ()) { + let this = &*(data as *const FastCWaker); + let (data, wake, adapter) = match unsafe { this.lock() } { + FastCWakerState::Borrowed { + waker, + other_adapter, + .. + } => (waker.data, waker.vtable.wake_by_ref, *other_adapter), + FastCWakerState::Owned(d) => { + let waker = &*d.as_ptr(); + ( + waker.raw.data, + waker.raw.vtable.wake_by_ref, + waker.other_adapter, + ) + } + }; + this.release(); + + adapter(data, wake as _) + } + + let vtbl = &RawWakerVTable::new(clone, unreach, wake_by_ref, unreach); + let waker = RawWaker::new(self as *const Self as *const (), vtbl); + let waker = unsafe { Waker::from_raw(waker) }; + + cb(&waker) + } + } + + pub fn clone_waker(&self) -> Waker { + self.with_waker(|w| w.clone()) + } + + pub fn c_waker(&self) -> BaseArc { + let state = unsafe { self.lock() }; + + let ret = match state { + FastCWakerState::Owned(owned) => unsafe { + let owned = owned.as_ptr(); + BaseArc::increment_strong_count(owned); + BaseArc::from_raw(owned) + }, + FastCWakerState::Borrowed { + waker, + clone_adapter, + other_adapter, + } => { + let waker = unsafe { clone_adapter(waker.data, waker.vtable.clone as _) }; + let owned: BaseArc = BaseArc::from(CWaker { + raw: waker, + clone_adapter: *clone_adapter, + other_adapter: *other_adapter, + }); + *state = FastCWakerState::Owned(unsafe { + NonNull::new_unchecked(owned.clone().into_raw() as *mut _) + }); + owned + } + }; + + self.release(); + + ret + } +} diff --git a/cglue/src/task/unsound.rs b/cglue/src/task/unsound.rs new file mode 100644 index 0000000..98aac10 --- /dev/null +++ b/cglue/src/task/unsound.rs @@ -0,0 +1,125 @@ +use super::*; + +use core::task::*; +use tarc::BaseArc; + +#[repr(transparent)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +pub struct CWaker { + raw: CRawWaker, +} + +impl CWaker { + pub fn into_waker(this: BaseArc) -> Waker { + unsafe { Waker::from_raw(Self::into_raw_waker(this)) } + } + + pub fn into_raw_waker(this: BaseArc) -> RawWaker { + unsafe fn clone(data: *const ()) -> RawWaker { + let waker = data as *const CWaker; + BaseArc::increment_strong_count(waker); + CWaker::into_raw_waker(BaseArc::from_raw(waker)) + } + + unsafe fn wake(data: *const ()) { + let waker = &*(data as *const CWaker); + (waker.raw.vtable.wake_by_ref)(waker.raw.data); + BaseArc::decrement_strong_count(waker); + } + + unsafe fn wake_by_ref(data: *const ()) { + let waker = &*(data as *const CWaker); + (waker.raw.vtable.wake_by_ref)(waker.raw.data); + } + + unsafe fn drop(data: *const ()) { + BaseArc::decrement_strong_count(data as *const CWaker); + } + + let vtbl = &RawWakerVTable::new(clone, wake, wake_by_ref, drop); + RawWaker::new(this.into_raw() as *const (), vtbl) + } + + pub fn wake(self) { + let wake = self.raw.vtable.wake; + let data = self.raw.data; + // Don't call `drop` -- the waker will be consumed by `wake`. + core::mem::forget(self); + // SAFETY: This is somewhat safe because `Waker::from_raw` is the only way + // to initialize `wake` and `data` requiring the user to acknowledge + // that the contract of `RawWaker` is upheld. + // NOTE: function ABI is unverified. + unsafe { wake(data) }; + } + + pub fn wake_by_ref(&self) { + let wake_by_ref = self.raw.vtable.wake_by_ref; + let data = self.raw.data; + // SAFETY: This is somewhat safe because `Waker::from_raw` is the only way + // to initialize `wake` and `data` requiring the user to acknowledge + // that the contract of `RawWaker` is upheld. + // NOTE: function ABI is unverified. + unsafe { wake_by_ref(data) }; + } + + pub unsafe fn from_raw(raw: RawWaker) -> Self { + let raw: CRawWaker = core::mem::transmute(raw); + + Self { raw } + } +} + +impl Drop for CWaker { + fn drop(&mut self) { + let data = self.raw.data; + // SAFETY: This is safe because `Waker::from_raw` is the only way + // to initialize `wake` and `data` requiring the user to acknowledge + // that the contract of `RawWaker` is upheld. + // NOTE: function ABI is unverified. + unsafe { (self.raw.vtable.drop)(data) }; + } +} + +impl Clone for CWaker { + #[inline] + fn clone(&self) -> Self { + Self { + // SAFETY: This is safe because `Waker::from_raw` is the only way + // to initialize `clone` and `data` requiring the user to acknowledge + // that the contract of [`RawWaker`] is upheld. + // NOTE: function ABI is unverified. + raw: unsafe { core::mem::transmute((self.raw.vtable.clone)(self.raw.data)) }, + } + } +} + +impl From for CWaker { + fn from(waker: Waker) -> Self { + unsafe { Self::from_raw(core::mem::transmute(waker)) } + } +} + +#[repr(C)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +pub struct FastCWaker<'a> { + waker: &'a CWaker, +} + +impl<'a> From<&'a Waker> for FastCWaker<'a> { + fn from(waker: &'a Waker) -> Self { + Self { + waker: unsafe { &*(waker as *const Waker as *const CWaker) }, + } + } +} + +impl<'a> FastCWaker<'a> { + pub fn with_waker(&self, cb: impl FnOnce(&Waker) -> T) -> T { + let waker = unsafe { &*(self.waker as *const CWaker as *const Waker) }; + cb(waker) + } + + pub fn clone_waker(&self) -> Waker { + self.with_waker(|w| w.clone()) + } +} diff --git a/cglue/src/tests/generics/generic_associated.rs b/cglue/src/tests/generics/generic_associated.rs index b7d5705..647148d 100644 --- a/cglue/src/tests/generics/generic_associated.rs +++ b/cglue/src/tests/generics/generic_associated.rs @@ -16,7 +16,7 @@ pub trait GroupGatReturn { impl GroupGatReturn for SA { type ReturnType<'a> = &'a SA; - fn ggr_1(&mut self, val: &u32) -> &SA { + fn ggr_1(&mut self, _val: &u32) -> &SA { self } } From a8afbe053b1da4011991553dc147d27994925792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Fri, 23 Jun 2023 16:38:53 +0200 Subject: [PATCH 14/41] cglue-bindgen: fix multi-line matching of vtable function entries --- cglue-bindgen/Cargo.toml | 2 +- cglue-bindgen/src/types.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cglue-bindgen/Cargo.toml b/cglue-bindgen/Cargo.toml index 41abb1b..997e63e 100644 --- a/cglue-bindgen/Cargo.toml +++ b/cglue-bindgen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-bindgen" -version = "0.2.2" +version = "0.2.3" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" license = "MIT" diff --git a/cglue-bindgen/src/types.rs b/cglue-bindgen/src/types.rs index 1f989ec..f2a6385 100644 --- a/cglue-bindgen/src/types.rs +++ b/cglue-bindgen/src/types.rs @@ -393,8 +393,9 @@ impl Vtable { pub fn new(name: String, functions_str: &str, container_ty: &str) -> Result { let mut functions = vec![]; + // (?s) allows matching across lines let reg = Regex::new(&format!( - r"(?P[^;]+)\(\*(?P\w+)\)\((?P({cont_ty} \*|const {cont_ty} \*|{cont_ty} ))cont(?P.*)\)", + r"(?s)(?P[^;]+)\(\*(?P\w+)\)\((?P({cont_ty} \*|const {cont_ty} \*|{cont_ty} ))cont(?P.*)\)", cont_ty = container_ty ))?; From 5e7221c34d49ca68baaadfcb2cb5cfc330ed0201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Thu, 27 Jul 2023 18:20:46 +0100 Subject: [PATCH 15/41] Fix task on rustc 1.71, remove unsound task feature --- Cargo.lock | 178 ++++++++++++++++++++++++++------------ cglue/Cargo.toml | 1 - cglue/src/task/mod.rs | 141 ++++++++++++++++++++++++------ cglue/src/task/sound.rs | 49 ++++++++--- cglue/src/task/unsound.rs | 125 -------------------------- 5 files changed, 275 insertions(+), 219 deletions(-) delete mode 100644 cglue/src/task/unsound.rs diff --git a/Cargo.lock b/Cargo.lock index d48db50..f9437dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "abi_stable" version = "0.10.4" @@ -49,9 +51,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -80,12 +82,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -98,17 +94,21 @@ version = "0.2.12" dependencies = [ "abi_stable", "cglue-macro", + "indexmap 1.8.2", "log", "no-std-compat", + "once_cell", "rustc_version 0.4.0", "serde", "tarc", + "thiserror", + "thiserror-impl", "try_default", ] [[package]] name = "cglue-bindgen" -version = "0.2.2" +version = "0.2.3" dependencies = [ "itertools", "log", @@ -160,7 +160,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -170,14 +170,20 @@ version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "generational-arena" @@ -185,7 +191,39 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "indexmap" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +dependencies = [ + "autocfg", + "hashbrown 0.11.2", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", ] [[package]] @@ -194,7 +232,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -208,9 +246,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "lazy_static" @@ -220,9 +258,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.146" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" @@ -230,7 +268,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "winapi", ] @@ -246,12 +284,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.11" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if 0.1.10", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "memchr" @@ -288,7 +323,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -298,9 +333,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "plugin-api" @@ -322,29 +357,28 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "thiserror", - "toml", + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -360,9 +394,21 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.3" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ "aho-corasick", "memchr", @@ -371,9 +417,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "repr_offset" @@ -399,20 +445,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.17", + "semver 1.0.18", ] [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" @@ -425,9 +471,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "semver-parser" @@ -457,9 +503,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.97" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", @@ -468,9 +514,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "syn" @@ -518,6 +564,23 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +dependencies = [ + "indexmap 2.0.0", + "toml_datetime", + "winnow", +] + [[package]] name = "try_default" version = "1.0.0" @@ -547,9 +610,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "user-bin" @@ -580,3 +643,12 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winnow" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b5872fa2e10bd067ae946f927e726d7d603eaeb6e02fa6a350e0722d2b8c11" +dependencies = [ + "memchr", +] diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 4c757a9..0257ff8 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -35,7 +35,6 @@ std = ["no-std-compat/std"] rust_void = ["cglue-macro/rust_void"] unstable = ["cglue-macro/unstable", "try_default"] task_unstable = [] -task_unsound = [] layout_checks = ["cglue-macro/layout_checks", "abi_stable"] [package.metadata.docs.rs] diff --git a/cglue/src/task/mod.rs b/cglue/src/task/mod.rs index 880ee7a..f98b325 100644 --- a/cglue/src/task/mod.rs +++ b/cglue/src/task/mod.rs @@ -1,15 +1,8 @@ //! C-compatible task structures. -#[cfg(not(feature = "task_unsound"))] mod sound; -#[cfg(not(feature = "task_unsound"))] pub use sound::*; -#[cfg(feature = "task_unsound")] -mod unsound; -#[cfg(feature = "task_unsound")] -pub use unsound::*; - use core::task::*; /// Actual type: unsafe fn(_: *const ()) -> RawWaker; @@ -41,11 +34,11 @@ pub struct CRawWakerVTable { drop: OtherFn, } -#[repr(C)] +#[repr(transparent)] #[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +#[derive(Clone, Copy)] pub struct CRawWaker { - data: *const (), - vtable: &'static CRawWakerVTable, + ptrs: [*const (); 2], } impl From<&Waker> for &CRawWaker { @@ -54,6 +47,23 @@ impl From<&Waker> for &CRawWaker { } } +impl CRawWaker { + fn data(&self, order: &CRawWakerOrder) -> *const () { + self.ptrs[order.data] + } + + unsafe fn vtable(&self, order: &CRawWakerOrder) -> &'static CRawWakerVTable { + &*(self.ptrs[order.vtable] as *const CRawWakerVTable) + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +struct CRawWakerOrder { + data: usize, + vtable: usize, +} + // Verify the layouts of reimplemented data structures // // Unfortunately, we cannot verify function ABI. @@ -74,16 +84,60 @@ const _: () = { panic!("Raw waker vtbl size mismatch") } + macro_rules! expand { + ($c:literal, $s:literal, $($e:expr),*) => { + [$(concat!($c, " ", $s, " idx ", stringify!($e)),)*] + } + } + macro_rules! comp_arr { - ($a:ident, $b:ident) => { + ($a:ident, $b:ident, $c:literal) => {{ + const BUF: &[&str] = &expand!( + $c, + "buffers not equal!", + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32 + ); + let mut cnt = 0; while cnt < $a.len() { if $a[cnt] != $b[cnt] { - panic!("buffers not equal!"); + panic!("{}", BUF[cnt]); } cnt += 1; } - }; + }}; } // Verify the layout of the vtable. @@ -111,22 +165,55 @@ const _: () = { let bvtbl = unsafe { transmute::<_, [u8; size_of::()]>(vtbl) }; let bvtbl_c = unsafe { transmute::<_, [u8; size_of::()]>(vtbl_c) }; - comp_arr!(bvtbl, bvtbl_c); + comp_arr!(bvtbl, bvtbl_c, "vtable"); +}; + +macro_rules! __order { + () => {{ + use core::mem::transmute; - // Verify the layout of the raw waker. + // Verify the layout of the raw waker. - let data = 10usize as *const (); - let vtbl: &'static RawWakerVTable = unsafe { transmute(20usize) }; - let vtbl_c: &'static CRawWakerVTable = unsafe { transmute(20usize) }; + let data = core::ptr::null(); - let waker = RawWaker::new(data, vtbl); - let waker_c = CRawWaker { - data, - vtable: vtbl_c, - }; + #[cfg(miri)] + let vtbl = unsafe { + unsafe fn clone(data: *const ()) -> RawWaker { + todo!() + } - let bwaker = unsafe { transmute::<_, [u8; size_of::()]>(waker) }; - let bwaker_c = unsafe { transmute::<_, [u8; size_of::()]>(waker_c) }; + unsafe fn null(data: *const ()) {} - comp_arr!(bwaker, bwaker_c); -}; + &RawWakerVTable::new(clone, null, null, null) + }; + #[cfg(not(miri))] + let vtbl = unsafe { transmute(1 as *const ()) }; + + let waker = RawWaker::new(data, vtbl); + + // This verifies the size of the object - will not compile if RawWaker is not the size of 2 + // pointers, or if usize != pointer size. + let bwaker = unsafe { transmute::<_, [usize; 2]>(waker) }; + + // This will return us the order + let data = if bwaker[0] == 0 { 0 } else { 1 }; + let vtable = if bwaker[0] == 0 { 1 } else { 0 }; + + CRawWakerOrder { data, vtable } + }}; +} + +#[cfg(miri)] +#[allow(clippy::useless_transmute)] +fn get_order() -> CRawWakerOrder { + __order!() +} + +#[allow(clippy::useless_transmute)] +#[cfg(not(miri))] +const ORDER: CRawWakerOrder = { __order!() }; + +#[cfg(not(miri))] +const fn get_order() -> CRawWakerOrder { + ORDER +} diff --git a/cglue/src/task/sound.rs b/cglue/src/task/sound.rs index fbb1f9f..09e3d1d 100644 --- a/cglue/src/task/sound.rs +++ b/cglue/src/task/sound.rs @@ -20,11 +20,22 @@ unsafe extern "C" fn other_adapter(data: *const (), other: *const ()) { #[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] pub struct CWaker { raw: CRawWaker, + order: CRawWakerOrder, clone_adapter: unsafe extern "C" fn(*const (), *const ()) -> CRawWaker, other_adapter: unsafe extern "C" fn(*const (), *const ()), } impl CWaker { + fn data(&self) -> *const () { + self.raw.data(&self.order) + } + + fn vtable(&self) -> &'static CRawWakerVTable { + // SAFETY: we ensure safety during construction of `CWaker` - the order used is always + // correct and tied to the raw vtable. + unsafe { self.raw.vtable(&self.order) } + } + pub fn into_waker(this: BaseArc) -> Waker { unsafe { Waker::from_raw(Self::into_raw_waker(this)) } } @@ -38,13 +49,13 @@ impl CWaker { unsafe fn wake(data: *const ()) { let waker = &*(data as *const CWaker); - (waker.other_adapter)(waker.raw.data, waker.raw.vtable.wake_by_ref as _); + (waker.other_adapter)(waker.data(), waker.vtable().wake_by_ref as _); BaseArc::decrement_strong_count(waker); } unsafe fn wake_by_ref(data: *const ()) { let waker = &*(data as *const CWaker); - (waker.other_adapter)(waker.raw.data, waker.raw.vtable.wake_by_ref as _); + (waker.other_adapter)(waker.data(), waker.vtable().wake_by_ref as _); } unsafe fn drop(data: *const ()) { @@ -57,8 +68,8 @@ impl CWaker { pub fn wake(self) { let other_adapter = self.other_adapter; - let wake = self.raw.vtable.wake; - let data = self.raw.data; + let wake = self.vtable().wake; + let data = self.data(); // Don't call `drop` -- the waker will be consumed by `wake`. core::mem::forget(self); // SAFETY: This is safe because `Waker::from_raw` is the only way @@ -71,8 +82,8 @@ impl CWaker { pub fn wake_by_ref(&self) { let other_adapter = self.other_adapter; - let wake_by_ref = self.raw.vtable.wake_by_ref; - let data = self.raw.data; + let wake_by_ref = self.vtable().wake_by_ref; + let data = self.data(); // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `wake` and `data` requiring the user to acknowledge // that the contract of `RawWaker` is upheld. @@ -86,6 +97,7 @@ impl CWaker { Self { raw, + order: get_order(), clone_adapter, other_adapter, } @@ -95,8 +107,8 @@ impl CWaker { impl Drop for CWaker { fn drop(&mut self) { let other_adapter = self.other_adapter; - let drop = self.raw.vtable.drop; - let data = self.raw.data; + let drop = self.vtable().drop; + let data = self.data(); // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `wake` and `data` requiring the user to acknowledge // that the contract of `RawWaker` is upheld. @@ -113,7 +125,8 @@ impl Clone for CWaker { // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `clone` and `data` requiring the user to acknowledge // that the contract of [`RawWaker`] is upheld. - raw: unsafe { (self.clone_adapter)(self.raw.data, self.raw.vtable.clone as *const ()) }, + raw: unsafe { (self.clone_adapter)(self.data(), self.vtable().clone as *const ()) }, + order: self.order, clone_adapter: self.clone_adapter, other_adapter: self.other_adapter, } @@ -131,6 +144,7 @@ impl From for CWaker { enum FastCWakerState<'a> { Borrowed { waker: &'a CRawWaker, + order: CRawWakerOrder, clone_adapter: unsafe extern "C" fn(*const (), *const ()) -> CRawWaker, other_adapter: unsafe extern "C" fn(*const (), *const ()), }, @@ -175,6 +189,7 @@ impl<'a> From<&'a Waker> for FastCWaker<'a> { lock: Default::default(), state: UnsafeCell::new(FastCWakerState::Borrowed { waker: waker.into(), + order: get_order(), clone_adapter, other_adapter, }), @@ -208,14 +223,19 @@ impl<'a> FastCWaker<'a> { let (data, wake, adapter) = match unsafe { this.lock() } { FastCWakerState::Borrowed { waker, + order, other_adapter, .. - } => (waker.data, waker.vtable.wake_by_ref, *other_adapter), + } => ( + waker.data(order), + waker.vtable(order).wake_by_ref, + *other_adapter, + ), FastCWakerState::Owned(d) => { let waker = &*d.as_ptr(); ( - waker.raw.data, - waker.raw.vtable.wake_by_ref, + waker.data(), + waker.vtable().wake_by_ref, waker.other_adapter, ) } @@ -248,12 +268,15 @@ impl<'a> FastCWaker<'a> { }, FastCWakerState::Borrowed { waker, + order, clone_adapter, other_adapter, } => { - let waker = unsafe { clone_adapter(waker.data, waker.vtable.clone as _) }; + let waker = + unsafe { clone_adapter(waker.data(order), waker.vtable(order).clone as _) }; let owned: BaseArc = BaseArc::from(CWaker { raw: waker, + order: *order, clone_adapter: *clone_adapter, other_adapter: *other_adapter, }); diff --git a/cglue/src/task/unsound.rs b/cglue/src/task/unsound.rs deleted file mode 100644 index 98aac10..0000000 --- a/cglue/src/task/unsound.rs +++ /dev/null @@ -1,125 +0,0 @@ -use super::*; - -use core::task::*; -use tarc::BaseArc; - -#[repr(transparent)] -#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] -pub struct CWaker { - raw: CRawWaker, -} - -impl CWaker { - pub fn into_waker(this: BaseArc) -> Waker { - unsafe { Waker::from_raw(Self::into_raw_waker(this)) } - } - - pub fn into_raw_waker(this: BaseArc) -> RawWaker { - unsafe fn clone(data: *const ()) -> RawWaker { - let waker = data as *const CWaker; - BaseArc::increment_strong_count(waker); - CWaker::into_raw_waker(BaseArc::from_raw(waker)) - } - - unsafe fn wake(data: *const ()) { - let waker = &*(data as *const CWaker); - (waker.raw.vtable.wake_by_ref)(waker.raw.data); - BaseArc::decrement_strong_count(waker); - } - - unsafe fn wake_by_ref(data: *const ()) { - let waker = &*(data as *const CWaker); - (waker.raw.vtable.wake_by_ref)(waker.raw.data); - } - - unsafe fn drop(data: *const ()) { - BaseArc::decrement_strong_count(data as *const CWaker); - } - - let vtbl = &RawWakerVTable::new(clone, wake, wake_by_ref, drop); - RawWaker::new(this.into_raw() as *const (), vtbl) - } - - pub fn wake(self) { - let wake = self.raw.vtable.wake; - let data = self.raw.data; - // Don't call `drop` -- the waker will be consumed by `wake`. - core::mem::forget(self); - // SAFETY: This is somewhat safe because `Waker::from_raw` is the only way - // to initialize `wake` and `data` requiring the user to acknowledge - // that the contract of `RawWaker` is upheld. - // NOTE: function ABI is unverified. - unsafe { wake(data) }; - } - - pub fn wake_by_ref(&self) { - let wake_by_ref = self.raw.vtable.wake_by_ref; - let data = self.raw.data; - // SAFETY: This is somewhat safe because `Waker::from_raw` is the only way - // to initialize `wake` and `data` requiring the user to acknowledge - // that the contract of `RawWaker` is upheld. - // NOTE: function ABI is unverified. - unsafe { wake_by_ref(data) }; - } - - pub unsafe fn from_raw(raw: RawWaker) -> Self { - let raw: CRawWaker = core::mem::transmute(raw); - - Self { raw } - } -} - -impl Drop for CWaker { - fn drop(&mut self) { - let data = self.raw.data; - // SAFETY: This is safe because `Waker::from_raw` is the only way - // to initialize `wake` and `data` requiring the user to acknowledge - // that the contract of `RawWaker` is upheld. - // NOTE: function ABI is unverified. - unsafe { (self.raw.vtable.drop)(data) }; - } -} - -impl Clone for CWaker { - #[inline] - fn clone(&self) -> Self { - Self { - // SAFETY: This is safe because `Waker::from_raw` is the only way - // to initialize `clone` and `data` requiring the user to acknowledge - // that the contract of [`RawWaker`] is upheld. - // NOTE: function ABI is unverified. - raw: unsafe { core::mem::transmute((self.raw.vtable.clone)(self.raw.data)) }, - } - } -} - -impl From for CWaker { - fn from(waker: Waker) -> Self { - unsafe { Self::from_raw(core::mem::transmute(waker)) } - } -} - -#[repr(C)] -#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] -pub struct FastCWaker<'a> { - waker: &'a CWaker, -} - -impl<'a> From<&'a Waker> for FastCWaker<'a> { - fn from(waker: &'a Waker) -> Self { - Self { - waker: unsafe { &*(waker as *const Waker as *const CWaker) }, - } - } -} - -impl<'a> FastCWaker<'a> { - pub fn with_waker(&self, cb: impl FnOnce(&Waker) -> T) -> T { - let waker = unsafe { &*(self.waker as *const CWaker as *const Waker) }; - cb(waker) - } - - pub fn clone_waker(&self) -> Waker { - self.with_waker(|w| w.clone()) - } -} From 0d9071cb6b6bf4c62d65369ee5d60a17375ed3e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Thu, 5 Oct 2023 21:05:02 +0100 Subject: [PATCH 16/41] Bump cglue version --- cglue/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 0257ff8..11374bd 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue" -version = "0.2.12" +version = "0.2.13" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe abstractions for making plugins and C-compatible libraries" From 31953947813c2721a0cdcd411ee5d280bde96eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Sat, 4 Nov 2023 10:26:14 +0000 Subject: [PATCH 17/41] Allow using no_std tarc --- Cargo.lock | 89 ++++++++++++++++++++++++------------------------ cglue/Cargo.toml | 6 ++-- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9437dc..30bce54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,9 +51,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -90,7 +90,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cglue" -version = "0.2.12" +version = "0.2.14" dependencies = [ "abi_stable", "cglue-macro", @@ -202,9 +202,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "indexmap" @@ -218,12 +218,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.2", ] [[package]] @@ -258,9 +258,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libloading" @@ -274,9 +274,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -284,15 +284,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "no-std-compat" @@ -357,28 +357,27 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.3.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" dependencies = [ - "once_cell", "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -394,9 +393,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -406,9 +405,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -417,9 +416,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "repr_offset" @@ -445,7 +444,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.18", + "semver 1.0.20", ] [[package]] @@ -471,9 +470,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "semver-parser" @@ -514,9 +513,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "syn" @@ -531,9 +530,9 @@ dependencies = [ [[package]] name = "tarc" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6cda220d0551690e4c54ba6c0c229ee298544fe52a93ee6cf022c94b72883f5" +checksum = "88da97cd34718f47df2adae0c2310ee305e061c794b9c07fd33d8387f4ee2e1c" [[package]] name = "thiserror" @@ -566,17 +565,17 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.1.0", "toml_datetime", "winnow", ] @@ -610,9 +609,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "user-bin" @@ -646,9 +645,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winnow" -version = "0.5.1" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b5872fa2e10bd067ae946f927e726d7d603eaeb6e02fa6a350e0722d2b8c11" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 11374bd..5d70abb 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue" -version = "0.2.13" +version = "0.2.14" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe abstractions for making plugins and C-compatible libraries" @@ -18,7 +18,7 @@ serde = { version = "1", optional = true, default-features = false, features = [ try_default = { version = "= 1.0.0", optional = true } abi_stable = { version = "0.10", optional = true } log = { version = "0.4", optional = true } -tarc = "0.1" +tarc = { version = "0.1", default-features = false } [build-dependencies] rustc_version = "0.4" @@ -31,7 +31,7 @@ rustc_version = "0.4" [features] default = ["std"] -std = ["no-std-compat/std"] +std = ["no-std-compat/std", "tarc/std"] rust_void = ["cglue-macro/rust_void"] unstable = ["cglue-macro/unstable", "try_default"] task_unstable = [] From 35b0da5bdf6cfe6ecaeedf07ba795d618113477f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Mon, 5 Feb 2024 22:12:46 +0000 Subject: [PATCH 18/41] Add trait group optional trait aliasing --- Cargo.lock | 152 ++++++------------------- cglue-gen/src/trait_groups.rs | 123 +++++++++++++------- cglue-macro/src/lib.rs | 7 +- cglue/Cargo.toml | 13 ++- cglue/src/task/mod.rs | 1 + cglue/src/tests/simple/structs.rs | 15 +++ cglue/src/tests/simple/trait_defs.rs | 5 + cglue/src/tests/simple/trait_groups.rs | 22 +++- 8 files changed, 173 insertions(+), 165 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30bce54..2fba8b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "abi_stable" version = "0.10.4" @@ -51,9 +49,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -94,15 +92,11 @@ version = "0.2.14" dependencies = [ "abi_stable", "cglue-macro", - "indexmap 1.8.2", "log", "no-std-compat", - "once_cell", "rustc_version 0.4.0", "serde", "tarc", - "thiserror", - "thiserror-impl", "try_default", ] @@ -156,22 +150,18 @@ checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6" [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "either" @@ -179,12 +169,6 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - [[package]] name = "generational-arena" version = "0.2.9" @@ -194,38 +178,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hashbrown" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" - -[[package]] -name = "indexmap" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" -dependencies = [ - "autocfg", - "hashbrown 0.11.2", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown 0.14.2", -] - [[package]] name = "instant" version = "0.1.12" @@ -246,9 +198,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "lazy_static" @@ -258,9 +210,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" @@ -284,15 +236,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "memchr" -version = "2.6.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "no-std-compat" @@ -357,27 +309,29 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "2.0.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ - "toml_edit", + "once_cell", + "thiserror", + "toml", ] [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "92de25114670a878b1261c79c9f8f729fb97e95bac93f6312f583c60dd6a1dfe" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "5907a1b7c277254a8b15170f6e7c97cfa60ee7872a3217663bb81151e48184bb" dependencies = [ "proc-macro2", ] @@ -393,21 +347,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "aho-corasick", "memchr", @@ -416,9 +358,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "repr_offset" @@ -444,14 +386,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.20", + "semver 1.0.21", ] [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "scopeguard" @@ -470,9 +412,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "semver-parser" @@ -513,9 +455,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "syn" @@ -563,23 +505,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" - -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.1.0", - "toml_datetime", - "winnow", -] - [[package]] name = "try_default" version = "1.0.0" @@ -642,12 +567,3 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "winnow" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" -dependencies = [ - "memchr", -] diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index de9bb8e..62ae419 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -8,10 +8,46 @@ use std::collections::HashMap; use syn::parse::{Parse, ParseStream}; use syn::*; +pub struct AliasPath { + path: Path, + alias: Option, +} + +impl Parse for AliasPath { + fn parse(input: ParseStream) -> Result { + let path = input.parse()?; + + let alias = if input.parse::().is_ok() { + Some(input.parse::()?) + } else { + None + }; + + Ok(Self { path, alias }) + } +} + +impl AliasPath { + fn prelude_remap(self) -> Self { + Self { + path: prelude_remap(self.path), + alias: self.alias, + } + } + + fn ext_abs_remap(self) -> Self { + Self { + path: ext_abs_remap(self.path), + alias: self.alias, + } + } +} + /// Describes information about a single trait. pub struct TraitInfo { path: Path, - ident: Ident, + raw_ident: Ident, + name_ident: Ident, generics: ParsedGenerics, vtbl_name: Ident, ret_tmp_typename: Ident, @@ -23,7 +59,7 @@ pub struct TraitInfo { impl PartialEq for TraitInfo { fn eq(&self, o: &Self) -> bool { - self.ident == o.ident + self.name_ident == o.name_ident } } @@ -31,7 +67,7 @@ impl Eq for TraitInfo {} impl Ord for TraitInfo { fn cmp(&self, o: &Self) -> std::cmp::Ordering { - self.ident.cmp(&o.ident) + self.name_ident.cmp(&o.name_ident) } } @@ -41,22 +77,30 @@ impl PartialOrd for TraitInfo { } } -impl From for TraitInfo { - fn from(in_path: Path) -> Self { - let (path, ident, gens) = - split_path_ident(&in_path).expect("Failed to split path by idents"); +impl From for TraitInfo { + fn from(in_path: AliasPath) -> Self { + let (path, raw_ident, gens) = + split_path_ident(&in_path.path).expect("Failed to split path by idents"); - let lc_ident = ident.to_string().to_lowercase(); + let mut name_ident = raw_ident.clone(); + + let mut lc_ident = raw_ident.to_string().to_lowercase(); + + if let Some(alias) = in_path.alias { + lc_ident = alias.to_string().to_lowercase(); + name_ident = alias; + } Self { vtbl_name: format_ident!("vtbl_{}", lc_ident), lc_name: format_ident!("{}", lc_ident), - vtbl_typename: format_ident!("{}Vtbl", ident), - ret_tmp_typename: format_ident!("{}RetTmp", ident), + vtbl_typename: format_ident!("{}Vtbl", raw_ident), + ret_tmp_typename: format_ident!("{}RetTmp", raw_ident), ret_tmp_name: format_ident!("ret_tmp_{}", lc_ident), - enable_vtbl_name: format_ident!("enable_{}", ident.to_string().to_lowercase()), + enable_vtbl_name: format_ident!("enable_{}", lc_ident), path, - ident, + raw_ident, + name_ident, generics: ParsedGenerics::from(gens.as_ref()), } } @@ -84,10 +128,10 @@ impl Parse for TraitGroup { parse_brace_content(input).ok(); input.parse::()?; - let mandatory_traits = parse_maybe_braced::(input)?; + let mandatory_traits = parse_maybe_braced::(input)?; input.parse::()?; - let optional_traits = parse_maybe_braced::(input)?; + let optional_traits = parse_maybe_braced::(input)?; let ext_trait_defs = if input.parse::().is_ok() { parse_maybe_braced::(input)? @@ -99,14 +143,14 @@ impl Parse for TraitGroup { let mut mandatory_vtbl: Vec = mandatory_traits .into_iter() - .map(prelude_remap) + .map(AliasPath::prelude_remap) .map(TraitInfo::from) .collect(); mandatory_vtbl.sort(); let mut optional_vtbl: Vec = optional_traits .into_iter() - .map(prelude_remap) + .map(AliasPath::prelude_remap) .map(TraitInfo::from) .collect(); optional_vtbl.sort(); @@ -134,7 +178,7 @@ impl Parse for TraitGroup { } // If the user has supplied a custom implementation. - if let Some(tr) = ext_trait_defs.iter().find(|tr| tr.ident == vtbl.ident) { + if let Some(tr) = ext_trait_defs.iter().find(|tr| tr.ident == vtbl.raw_ident) { // Keep the leading colon so as to allow going from the root or relatively let leading_colon = std::mem::replace(&mut vtbl.path.leading_colon, None); @@ -162,11 +206,11 @@ impl Parse for TraitGroup { } else { // Check the store otherwise let tr = store_traits - .get(&(vtbl.path.clone(), vtbl.ident.clone())) + .get(&(vtbl.path.clone(), vtbl.raw_ident.clone())) .or_else(|| { - store_exports.get(&vtbl.ident).and_then(|p| { + store_exports.get(&vtbl.raw_ident).and_then(|p| { vtbl.path = p.clone(); - store_traits.get(&(p.clone(), vtbl.ident.clone())) + store_traits.get(&(p.clone(), vtbl.raw_ident.clone())) }) }); @@ -188,7 +232,7 @@ impl Parse for TraitGroup { } else { eprintln!( "Could not find external trait {}. Not changing paths.", - vtbl.ident + vtbl.raw_ident ); } } @@ -261,12 +305,12 @@ impl Parse for TraitGroupImpl { generics.merge_and_remap(&mut ty_generics); let implemented_vtbl = if input.parse::().is_ok() { - let implemented_traits = parse_maybe_braced::(input)?; + let implemented_traits = parse_maybe_braced::(input)?; let mut implemented_vtbl: Vec = implemented_traits .into_iter() - .map(prelude_remap) - .map(ext_abs_remap) + .map(AliasPath::prelude_remap) + .map(AliasPath::ext_abs_remap) .map(From::from) .collect(); @@ -278,12 +322,12 @@ impl Parse for TraitGroupImpl { }; let fwd_implemented_vtbl = if input.parse::().is_ok() { - let implemented_traits = parse_maybe_braced::(input)?; + let implemented_traits = parse_maybe_braced::(input)?; let mut implemented_vtbl: Vec = implemented_traits .into_iter() - .map(prelude_remap) - .map(ext_abs_remap) + .map(AliasPath::prelude_remap) + .map(AliasPath::ext_abs_remap) .map(From::from) .collect(); @@ -468,7 +512,10 @@ impl Parse for TraitCastGroup { .bounds .into_iter() .filter_map(|b| match b { - TypeParamBound::Trait(tr) => Some(tr.path), + TypeParamBound::Trait(tr) => Some(AliasPath { + path: tr.path, + alias: None, + }), _ => None, }) .map(From::from) @@ -517,8 +564,8 @@ impl TraitGroup { ) -> Ident { let mut all_traits = String::new(); - for TraitInfo { ident, .. } in traits { - all_traits.push_str(&ident.to_string()); + for TraitInfo { name_ident, .. } in traits { + all_traits.push_str(&name_ident.to_string()); } format_ident!("{}{}With{}", name, postfix, all_traits) @@ -1466,7 +1513,7 @@ impl TraitGroup { for TraitInfo { path, - ident, + raw_ident, generics: ParsedGenerics { life_use: tr_life_use, @@ -1476,10 +1523,10 @@ impl TraitGroup { .. } in iter { - if let Some((ext_path, tr_info)) = self.ext_traits.get(ident) { + if let Some((ext_path, tr_info)) = self.ext_traits.get(raw_ident) { let mut impls = TokenStream::new(); - let ext_name = format_ident!("{}Ext", ident); + let ext_name = format_ident!("{}Ext", raw_ident); let (funcs, _, _) = super::traits::parse_trait( tr_info, @@ -1494,7 +1541,7 @@ impl TraitGroup { let gen = quote! { impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_use> - #path #ident <#tr_life_use #tr_gen_use> for #self_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + #path #raw_ident <#tr_life_use #tr_gen_use> for #self_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where #cont_name: #crate_path::trait_group::CGlueObjBase, Self: #ext_path #ext_name<#tr_life_use #tr_gen_use> @@ -1553,7 +1600,7 @@ impl TraitGroup { i, TraitInfo { path, - ident, + raw_ident, generics: ParsedGenerics { life_use, gen_use, .. @@ -1572,7 +1619,7 @@ impl TraitGroup { (quote!(for<'cglue_c>), quote!('cglue_c,)) }; - ret.extend(quote!(#hrtb #path #ident <#life_use #gen_use>)); + ret.extend(quote!(#hrtb #path #raw_ident <#life_use #gen_use>)); } ret @@ -2009,7 +2056,7 @@ impl TraitGroup { for TraitInfo { path, - ident, + raw_ident, vtbl_typename, generics: ParsedGenerics { gen_use, life_use, .. @@ -2027,7 +2074,7 @@ impl TraitGroup { Some(quote!('cglue_a,)) }; - ret.extend(quote!(#trait_bound: #path #ident<#life_use #gen_use>,)); + ret.extend(quote!(#trait_bound: #path #raw_ident<#life_use #gen_use>,)); } ret.extend(quote!(&#vtbl_lifetime #path #vtbl_typename<#vtbl_lifetime, #cont_name<#container_ident, #ctx_ident, #all_gen_use>, #gen_use>: #vtbl_lifetime + Default,)); diff --git a/cglue-macro/src/lib.rs b/cglue-macro/src/lib.rs index 5f972c5..1f7a01a 100644 --- a/cglue-macro/src/lib.rs +++ b/cglue-macro/src/lib.rs @@ -85,6 +85,10 @@ pub fn trait_obj(args: TokenStream) -> TokenStream { /// 3. Optionally implemented traits for the group. Either a single trait name, or a braced /// list of traits. /// +/// 3.1. If the same trait is listed twice (with different generic parameters), it may be aliased +/// with `OrigTrait = TraitAlias`. Then, all subsequent operations, such as `cast!` need +/// to use the alias, as opposed to the original trait. +/// /// 4. Optional block for external trait definitions. This block is needed when using non-standard /// external traits. #[proc_macro] @@ -102,7 +106,8 @@ pub fn cglue_trait_group(args: TokenStream) -> TokenStream { /// 2. The name of the group to implement. /// /// 3. Optional traits that this object contains. Either a single trait, or a braced list of -/// traits. +/// traits. Note that the list must redefine identical aliases, as defined in +/// `cglue_trait_group!` invokation. #[proc_macro] #[cfg_attr(feature = "unstable", allow(unused))] pub fn cglue_impl_group(args: TokenStream) -> TokenStream { diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 5d70abb..39039c9 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -23,11 +23,14 @@ tarc = { version = "0.1", default-features = false } [build-dependencies] rustc_version = "0.4" # Need to uncomment these before cargo update to keep hashbrown on rust 2018 edition -#indexmap = "~1.8" -#once_cell = "~1.14" -#thiserror = "=1.0.24" -#thiserror-impl = "=1.0.24" -#serde = "=1.0.127" +# indexmap = "~1.8" +# once_cell = "~1.14" +# thiserror = "=1.0.24" +# thiserror-impl = "=1.0.24" +# serde = "=1.0.127" +# proc-macro2 = "=1.0.65" +# memchr = "=2.4.1" +# log = "=0.4.18" [features] default = ["std"] diff --git a/cglue/src/task/mod.rs b/cglue/src/task/mod.rs index f98b325..4f4dae1 100644 --- a/cglue/src/task/mod.rs +++ b/cglue/src/task/mod.rs @@ -58,6 +58,7 @@ impl CRawWaker { } #[repr(C)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] #[derive(Clone, Copy)] struct CRawWakerOrder { data: usize, diff --git a/cglue/src/tests/simple/structs.rs b/cglue/src/tests/simple/structs.rs index 0a772b6..dc59e87 100644 --- a/cglue/src/tests/simple/structs.rs +++ b/cglue/src/tests/simple/structs.rs @@ -50,6 +50,12 @@ impl TC for SA { extern "C" fn tc_2(&mut self) {} } +impl TT for SA { + fn tt_1(&self, v: T) -> T { + v + } +} + #[test] fn call_a() { let mut a = SA {}; @@ -71,3 +77,12 @@ fn get_b() { assert_eq!(objb.tb_2(objb.tb_1(10)), 400); } + +#[test] +fn get_b_arc() { + let b = SB {}; + + let objb = trait_obj!(crate::arc::CArcSome::from(b) as TB); + + assert_eq!(objb.tb_2(objb.tb_1(10)), 400); +} diff --git a/cglue/src/tests/simple/trait_defs.rs b/cglue/src/tests/simple/trait_defs.rs index 6ed63fd..528b118 100644 --- a/cglue/src/tests/simple/trait_defs.rs +++ b/cglue/src/tests/simple/trait_defs.rs @@ -22,3 +22,8 @@ pub trait TC { #[cglue_trait] pub trait TE {} + +#[cglue_trait] +pub trait TT { + fn tt_1(&self, v: T) -> T; +} diff --git a/cglue/src/tests/simple/trait_groups.rs b/cglue/src/tests/simple/trait_groups.rs index 5cb3735..d63c211 100644 --- a/cglue/src/tests/simple/trait_groups.rs +++ b/cglue/src/tests/simple/trait_groups.rs @@ -4,13 +4,13 @@ use super::trait_defs::*; use cglue_macro::*; cglue_trait_group!(TestGroup, TA, { TB, TC }); - cglue_impl_group!(SA, TestGroup, { TC }); - cglue_impl_group!(&'a SA, TestGroup, {}); - cglue_impl_group!(SB, super::trait_groups::TestGroup, { TB }); +cglue_trait_group!(TestGroupGen, TT, { TT = TTUsize, TT = TTUSixtyFour }); +cglue_impl_group!(SA, TestGroupGen, { TT = TTUsize }); + #[test] fn test_group() { let mut a = SA {}; @@ -64,3 +64,19 @@ fn test_group_2() { tb.tb_1(1); } + +#[test] +fn test_group_3() { + let mut a = SA {}; + + let group = group_obj!(&mut a as TestGroupGen); + assert!(check!(group impl TTUsize)); + #[cfg(not(feature = "unstable"))] + assert!(!check!(group impl TTUSixtyFour)); + #[cfg(feature = "unstable")] + assert!(check!(group impl TTUSixtyFour)); + + let tusize = as_ref!(group impl TTUsize).unwrap(); + + tusize.tt_1(1usize); +} From 6f17f719c3d7612c408d108cba94521963609728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Sat, 24 Feb 2024 12:43:32 +0000 Subject: [PATCH 19/41] Groundwork for supporting associated types --- cglue-gen/src/trait_groups.rs | 6 +++++- cglue-gen/src/traits.rs | 27 ++++++++++++++++++++------ cglue/src/tests/generics/associated.rs | 4 ++++ cglue/src/trait_group.rs | 20 +++++++++++++------ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index 62ae419..1fe1712 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -55,6 +55,7 @@ pub struct TraitInfo { enable_vtbl_name: Ident, lc_name: Ident, vtbl_typename: Ident, + vtbl_info_typename: Ident, } impl PartialEq for TraitInfo { @@ -95,6 +96,7 @@ impl From for TraitInfo { vtbl_name: format_ident!("vtbl_{}", lc_ident), lc_name: format_ident!("{}", lc_ident), vtbl_typename: format_ident!("{}Vtbl", raw_ident), + vtbl_info_typename: format_ident!("{}VtblInfo", raw_ident), ret_tmp_typename: format_ident!("{}RetTmp", raw_ident), ret_tmp_name: format_ident!("ret_tmp_{}", lc_ident), enable_vtbl_name: format_ident!("enable_{}", lc_ident), @@ -1881,6 +1883,7 @@ impl TraitGroup { vtbl_name, path, vtbl_typename, + vtbl_info_typename, generics: ParsedGenerics { gen_use, .. }, .. } in traits @@ -1889,9 +1892,10 @@ impl TraitGroup { // TODO: bring back CGlueObjBuild - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #all_gen_declare> #trg_path::GetVtbl<#path #vtbl_typename<'cglue_a, #cont_name, #gen_use>> + impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #all_gen_declare> #trg_path::GetVtbl<'cglue_a, (#gen_use), #path #vtbl_info_typename> for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use> where + ::Target: Sized, #cont_name: #trg_path::CGlueObjBase, #all_gen_where_bounds { diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index f2437c5..fceb6ef 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -673,6 +673,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { // Need to preserve the same visibility as the trait itself. let vis = tr.vis.to_token_stream(); + let unsafety = tr.unsafety; let trait_name = tr.ident.clone(); let trait_name = &trait_name; @@ -682,6 +683,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { // Additional identifiers let vtbl_ident = format_ident!("{}Vtbl", trait_name); + let vtbl_info_ident = format_ident!("{}VtblInfo", trait_name); let ret_tmp_ident = format_ident!("{}RetTmp", trait_name); let ret_tmp_ident_phantom = format_ident!("{}RetTmpPhantom", trait_name); let accessor_trait_ident = format_ident!("{}OpaqueObj", trait_name); @@ -740,6 +742,8 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { let gen_lt_bounds = generics.declare_lt_for_all("e!('cglue_a)); let gen_sabi_bounds = generics.declare_sabi_for_all(&crate_path); + let gen_where_bounds_base_nolt = gen_where_bounds.clone(); + let gen_where_bounds_base = quote! { #gen_where_bounds #gen_lt_bounds @@ -867,7 +871,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { } quote! { - impl<#life_declare CGlueT, CGlueV, CGlueC, CGlueR, #gen_declare> #trait_name<#life_use #gen_use> + #unsafety impl<#life_declare CGlueT, CGlueV, CGlueC, CGlueR, #gen_declare> #trait_name<#life_use #gen_use> for #trg_path::CGlueTraitObj<'_, CGlueT, CGlueV, CGlueC, CGlueR> where Self: #ext_name<#life_use #gen_use> @@ -1020,6 +1024,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { #vis use cglue_internal::{ #vtbl_ident, + #vtbl_info_ident, #ret_tmp_ident, #accessor_trait_ident, @@ -1051,6 +1056,16 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /* Primary vtable definition. */ + pub struct #vtbl_info_ident; + + impl<#gen_declare_stripped> #trg_path::TraitInfo<(#gen_use)> for #vtbl_info_ident + where + #gen_where_bounds_base_nolt + { + type Assocs = (); + type Vtbl<'cglue_a, CGlueC: #trg_path::CGlueObjBase> = #vtbl_ident<'cglue_a, CGlueC, #gen_use> where CGlueC: 'cglue_a; + } + #[doc = #vtbl_doc] /// /// This virtual function table contains ABI-safe interface for the given trait. @@ -1058,7 +1073,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { #derive_layouts pub struct #vtbl_ident<'cglue_a, CGlueC: 'cglue_a + #trg_path::CGlueObjBase, #gen_declare_stripped> where - #gen_where_bounds_base + #gen_where_bounds_base_nolt { #vtbl_func_defintions _lt_cglue_a: ::core::marker::PhantomData<&'cglue_a CGlueC>, @@ -1216,7 +1231,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /* Define trait for simpler type accesses */ pub trait #accessor_trait_ident<'cglue_a #cglue_a_outlives, #life_declare #gen_declare> - : 'cglue_a + #trg_path::GetContainer + #trg_path::GetVtbl<#vtbl_ident<'cglue_a, ::ContType, #gen_use>> #supertrait_bounds + : 'cglue_a + #trg_path::GetContainer + #trg_path::GetVtbl<'cglue_a, (#gen_use), #vtbl_info_ident> #supertrait_bounds where #gen_where_bounds { @@ -1224,7 +1239,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { } impl<'cglue_a #cglue_a_outlives, #life_declare - CGlueO: 'cglue_a + #trg_path::GetContainer + #trg_path::GetVtbl<#vtbl_ident<'cglue_a, ::ContType, #gen_use>> #supertrait_bounds, #gen_declare> + CGlueO: 'cglue_a + #trg_path::GetContainer + #trg_path::GetVtbl<'cglue_a, (#gen_use), #vtbl_info_ident> #supertrait_bounds, #gen_declare> #accessor_trait_ident<'cglue_a, #life_use #gen_use> for CGlueO where #objcont_accessor_bound @@ -1235,8 +1250,8 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /* Trait implementation. */ - impl<'cglue_a #cglue_a_outlives, #life_declare - CGlueO: 'cglue_a + #trg_path::GetContainer + #trg_path::GetVtbl<#vtbl_ident<'cglue_a, ::ContType, #gen_use>> #supertrait_bounds + #unsafety impl<'cglue_a #cglue_a_outlives, #life_declare + CGlueO: 'cglue_a + /*#trg_path::GetContainer + */#trg_path::GetVtbl<'cglue_a, (#gen_use), #vtbl_info_ident> #supertrait_bounds // We essentially need only this bound, but we repeat the previous ones because // otherwise we get conflicting impl errors. // TODO: Is this a bug? Typically Rust typesystem doesn't complain in such cases. diff --git a/cglue/src/tests/generics/associated.rs b/cglue/src/tests/generics/associated.rs index 33bc171..a5ab78b 100644 --- a/cglue/src/tests/generics/associated.rs +++ b/cglue/src/tests/generics/associated.rs @@ -47,6 +47,10 @@ pub trait ObjResultReturn { #[allow(clippy::result_unit_err)] fn orr_1(&self) -> Result; + // NOTE: cbindgen breaks here whenever there is an explicit () type in params. + // + // You can workaround it by defining a `type Void = ()`, and use `Void` instead of `()`. This + // should be reported to cbindgen folks with MRE. #[no_int_result] #[allow(clippy::result_unit_err)] fn orr_2(&self) -> Result { diff --git a/cglue/src/trait_group.rs b/cglue/src/trait_group.rs index 1df5f87..9f7a67b 100644 --- a/cglue/src/trait_group.rs +++ b/cglue/src/trait_group.rs @@ -1,5 +1,3 @@ -//! Core definitions for traits, and their groups. -//! //! These are essentially the internals of CGlue. // TODO: split everything up @@ -144,12 +142,22 @@ unsafe impl<'a, T: Opaquable, F: CGlueBaseVtbl, C: Cont type OpaqueTarget = CGlueTraitObj<'a, T::OpaqueTarget, F::OpaqueVtbl, C, R>; } -pub trait GetVtbl { - fn get_vtbl(&self) -> &V; +pub trait TraitInfo { + type Vtbl<'cglue_a, CGlueC: CGlueObjBase> + where + CGlueC: 'cglue_a; + type Assocs; } -impl GetVtbl for CGlueTraitObj<'_, T, V, C, R> { - fn get_vtbl(&self) -> &V { +pub trait GetVtbl<'a, Generics, T: TraitInfo>: GetContainer { + fn get_vtbl(&self) -> &T::Vtbl<'a, ::ContType>; +} + +impl<'a, T: Deref, F, Tr: TraitInfo, Generics, C: ContextBounds, R> + GetVtbl<'a, Generics, Tr> + for CGlueTraitObj<'a, T, Tr::Vtbl<'a, CGlueObjContainer>, C, R> +{ + fn get_vtbl(&self) -> &Tr::Vtbl<'a, ::ContType> { self.vtbl } } From be543492884f223507972142f20d84fe98f1f7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Sat, 16 Mar 2024 18:19:21 +0000 Subject: [PATCH 20/41] Groundwork for supporting associated types pt 2 --- .github/workflows/build.yml | 3 +- Cargo.lock | 2 + cglue-gen/src/func.rs | 4 +- cglue-gen/src/generics.rs | 65 +++- cglue-gen/src/trait_groups.rs | 434 ++++++++++++++++--------- cglue-gen/src/traits.rs | 339 +++++++++++++------ cglue-macro/src/lib.rs | 28 +- cglue/src/lib.rs | 17 +- cglue/src/tests/generics/associated.rs | 20 +- cglue/src/tests/simple/hrtb.rs | 2 +- cglue/src/tests/simple/trait_groups.rs | 1 + cglue/src/tests/simple/traits.rs | 28 +- cglue/src/trait_group.rs | 21 +- cglue/src/trait_group/specify.rs | 74 +++++ 14 files changed, 715 insertions(+), 323 deletions(-) create mode 100644 cglue/src/trait_group/specify.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d986017..a7525f6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,7 +36,6 @@ jobs: toolchain: ["1.57.0", "stable"] features: [ "--features task_unstable", - "--features task_unstable,task_unsound", "--features layout_checks" ] steps: @@ -149,7 +148,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - features: ["--all-features", "", "-p cglue --features task_unstable", "-p cglue --features task_unstable,task_unsound"] + features: ["--all-features", "", "-p cglue --features task_unstable", "-p cglue --features task_unstable"] steps: - uses: actions/checkout@v2 - run: rustup component add clippy diff --git a/Cargo.lock b/Cargo.lock index 2fba8b1..b391858 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "abi_stable" version = "0.10.4" diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index 0407e3e..65a0f8c 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -918,6 +918,8 @@ impl ParsedFunc { tokens: &mut TokenStream, trg_path: &TokenStream, ret_tmp: &TokenStream, + vtbl_assocs_ident: &Ident, + trait_assocs_ident: &Ident, ) -> Option<&TokenStream> { if !self.is_wrapped() { return None; @@ -1033,7 +1035,7 @@ impl ParsedFunc { let ctx_bound = super::traits::ctx_bound(); let gen = quote! { - #safety extern "C" fn #fnname<#sig_life_declare CGlueC: #container_bound, CGlueCtx: #ctx_bound, #gen_declare>(#args #c_ret_params) #c_out where #gen_where_bounds #c_where_bounds #cglue_c_into_inner CGlueC::ObjType: for<'cglue_b> #trname<#tmp_lifetime #gen_use>, { + #safety extern "C" fn #fnname<#sig_life_declare CGlueC: #container_bound, CGlueCtx: #ctx_bound, CGlueAssocs: #vtbl_assocs_ident<#gen_use>, #gen_declare>(#args #c_ret_params) #c_out where #gen_where_bounds #c_where_bounds #cglue_c_into_inner CGlueC::ObjType: for<'cglue_b> #trname<#tmp_lifetime #gen_use> + #trait_assocs_ident<#gen_use Assocs = CGlueAssocs>, { #c_pre_call let ret = #inner_impl; #c_ret diff --git a/cglue-gen/src/generics.rs b/cglue-gen/src/generics.rs index 59f1fb9..4b8d33a 100644 --- a/cglue-gen/src/generics.rs +++ b/cglue-gen/src/generics.rs @@ -556,18 +556,46 @@ impl Parse for ParsedGenerics { } pub struct GenericCastType { - pub ident: Box, + pub expr: Box, pub target: GenericType, + pub ident: TokenStream, } impl Parse for GenericCastType { fn parse(input: ParseStream) -> Result { let cast: ExprCast = input.parse()?; - let ident = cast.expr; + let expr = cast.expr; let target = GenericType::from_type(&cast.ty, true); + let ident = GenericType::from_type(&cast.ty, false).target; - Ok(Self { ident, target }) + Ok(Self { + expr, + target, + ident, + }) + } +} + +pub struct GroupCastType { + pub expr: Box, + pub target: GenericType, + pub ident: TokenStream, +} + +impl Parse for GroupCastType { + fn parse(input: ParseStream) -> Result { + let cast: ExprCast = input.parse()?; + + let expr = cast.expr; + let target = GenericType::from_type(&cast.ty, true); + let ident = GenericType::from_type(&cast.ty, false).target; + + Ok(Self { + expr, + target, + ident, + }) } } @@ -613,8 +641,26 @@ impl GenericType { } } - fn from_type(target: &Type, cast_to_group: bool) -> Self { - let (path, target, generics) = match target { + pub fn push_types_end(&mut self, types: TokenStream) { + let typestr = types.to_string(); + let types = syn::parse::Parser::parse2(Punctuated::::parse_terminated, types) + .expect(&format!("Invalid types provided: {}", typestr)); + + // Unlike in push_types_start, we do not swap them + + if !self.generic_types.trailing_punct() { + self.generic_types.push_punct(Default::default()); + } + + self.generic_types.extend(types.into_iter()); + + if !self.generic_types.trailing_punct() { + self.generic_types.push_punct(Default::default()); + } + } + + fn from_type(target: &Type, cast_to_obj: bool) -> Self { + let (path, mut target, generics) = match target { Type::Path(ty) => { let (path, target, generics) = crate::util::split_path_ident(&ty.path).expect("Gen 3"); @@ -638,16 +684,23 @@ impl GenericType { _ => Default::default(), }; - let gen_separator = if cast_to_group { + let gen_separator = if cast_to_obj { if generics.is_some() { let infer = Type::Infer(TypeInfer { underscore_token: Default::default(), }); generic_types.insert(0, infer.clone()); generic_types.insert(0, infer); + + let base_assocs_ident = format_ident!("{}BaseAssocs", target.to_string()); + generic_types.push(parse_quote!(#path #base_assocs_ident)); + if !generic_types.trailing_punct() { generic_types.push_punct(Default::default()); } + target = format_ident!("{}Base", target.to_string()).to_token_stream(); + } else { + target = format_ident!("{}BaseBaseAssocs", target.to_string()).to_token_stream(); } quote!(::) } else { diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index 1fe1712..1a0d193 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -50,12 +50,13 @@ pub struct TraitInfo { name_ident: Ident, generics: ParsedGenerics, vtbl_name: Ident, + assocs_typename: Ident, ret_tmp_typename: Ident, ret_tmp_name: Ident, enable_vtbl_name: Ident, lc_name: Ident, vtbl_typename: Ident, - vtbl_info_typename: Ident, + vtbl_get_ident: Ident, } impl PartialEq for TraitInfo { @@ -96,7 +97,8 @@ impl From for TraitInfo { vtbl_name: format_ident!("vtbl_{}", lc_ident), lc_name: format_ident!("{}", lc_ident), vtbl_typename: format_ident!("{}Vtbl", raw_ident), - vtbl_info_typename: format_ident!("{}VtblInfo", raw_ident), + vtbl_get_ident: format_ident!("{}VtblGet", raw_ident), + assocs_typename: format_ident!("{}VtblAssocs", raw_ident), ret_tmp_typename: format_ident!("{}RetTmp", raw_ident), ret_tmp_name: format_ident!("ret_tmp_{}", lc_ident), enable_vtbl_name: format_ident!("enable_{}", lc_ident), @@ -113,6 +115,7 @@ impl From for TraitInfo { pub struct TraitGroup { name: Ident, cont_name: Ident, + assocs_trait: Ident, generics: ParsedGenerics, mandatory_vtbl: Vec, optional_vtbl: Vec, @@ -247,10 +250,12 @@ impl Parse for TraitGroup { }; let cont_name = format_ident!("{}Container", name); + let assocs_trait = format_ident!("{}VtblAssocs", name); Ok(Self { name, cont_name, + assocs_trait, generics, mandatory_vtbl, optional_vtbl, @@ -427,6 +432,7 @@ impl TraitGroupImpl { let filler_trait = format_ident!("{}VtableFiller", group); let vtable_type = format_ident!("{}Vtables", group); let cont_name = format_ident!("{}Container", group); + let assocs_trait = format_ident!("{}VtblAssocs", group); let implemented_tables = TraitGroup::enable_opt_vtbls(self.implemented_vtbl.iter()); let vtbl_where_bounds = TraitGroup::vtbl_where_bounds( @@ -440,10 +446,10 @@ impl TraitGroupImpl { ); let gen = quote! { - impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> - #group_path #filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use> for #ty + impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #group_path #assocs_trait<#gen_use>> + #group_path #filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs> for #ty where #gen_where_bounds #vtbl_where_bounds { - fn fill_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use> { + fn fill_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs> { table #implemented_tables } } @@ -468,13 +474,13 @@ impl TraitGroupImpl { quote! { #gen - impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> - #group_path #fwd_filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use> for #ty + impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #group_path #assocs_trait<#gen_use>> + #group_path #fwd_filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs> for #ty where - #cont_name: #crate_path::trait_group::CGlueObjBase, + #cont_name: #crate_path::trait_group::CGlueObjBase, #gen_where_bounds #vtbl_where_bounds { - fn fill_fwd_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use> { + fn fill_fwd_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use> { table #implemented_tables } } @@ -626,6 +632,7 @@ impl TraitGroup { let name = &self.name; let cont_name = &self.cont_name; + let assocs_trait = &self.assocs_trait; let ParsedGenerics { gen_declare, @@ -669,7 +676,8 @@ impl TraitGroup { let full_opt_vtbl_list = self.vtbl_list(self.optional_vtbl.iter()); let mandatory_as_ref_impls = self.mandatory_as_ref_impls(&trg_path); - let get_container_impl = self.get_container_impl(name, &trg_path, &self.generics); + let get_container_impl = + self.get_container_impl(name, &assocs_trait, &trg_path, &self.generics); let mandatory_internal_trait_impls = self.internal_trait_impls( name, @@ -719,7 +727,8 @@ impl TraitGroup { let mut enable_funcs_vtbl = TokenStream::new(); #[cfg(feature = "layout_checks")] - let derive_layouts = quote!(#[derive(::abi_stable::StableAbi)]); + let derive_layouts = + quote!(#[derive(::abi_stable::StableAbi)] #[sabi(unsafe_unconstrained(CGlueAssocs))]); #[cfg(not(feature = "layout_checks"))] let derive_layouts = quote!(); @@ -736,6 +745,7 @@ impl TraitGroup { enable_vtbl_name, vtbl_typename, vtbl_name, + name_ident, path, generics: ParsedGenerics { gen_use, .. }, .. @@ -747,7 +757,7 @@ impl TraitGroup { ] { funcs.extend(quote! { pub fn #enable_vtbl_name (self) -> Self - where &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use>: Default { + where &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>: Default { Self { #vtbl_name: Some(Default::default()),#fill_rest } @@ -764,6 +774,9 @@ impl TraitGroup { let impl_traits = self.impl_traits(self.mandatory_vtbl.iter().chain(self.optional_vtbl.iter())); + let (assoc_gen_defs, assoc_gen_use, assoc_decls, assoc_defs, assocs_num_void) = + self.trait_assocs(self.mandatory_vtbl.iter().chain(self.optional_vtbl.iter())); + let base_doc = format!( " Trait group potentially implementing `{}` traits.", impl_traits @@ -771,6 +784,9 @@ impl TraitGroup { let trback_doc = format!("be transformed back into `{}` without losing data.", name); let new_doc = format!(" Create new instance of {}.", name); + let assocs_base_type = format_ident!("{}BaseAssocs", name); + let base_name = format_ident!("{}Base", name); + let base_baseassocs_name = format_ident!("{}BaseBaseAssocs", name); let base_name_ref = format_ident!("{}BaseRef", name); let base_name_ctx_ref = format_ident!("{}BaseCtxRef", name); let base_name_arc_ref = format_ident!("{}BaseArcRef", name); @@ -818,7 +834,8 @@ impl TraitGroup { let mixed_opt_vtbl_unwrap = self.mixed_opt_vtbl_unwrap_list(traits.iter().copied()); - let get_container_impl = self.get_container_impl(&opt_name, &trg_path, &self.generics); + let get_container_impl = + self.get_container_impl(&opt_name, &assocs_trait, &trg_path, &self.generics); let opt_as_ref_impls = self.as_ref_impls( &opt_name, @@ -835,7 +852,7 @@ impl TraitGroup { ); let get_container_impl_final = - self.get_container_impl(&opt_final_name, &trg_path, &self.generics); + self.get_container_impl(&opt_final_name, &assocs_trait, &trg_path, &self.generics); let opt_final_as_ref_impls = self.as_ref_impls( &opt_final_name, @@ -885,14 +902,14 @@ impl TraitGroup { #[doc = #opt_final_doc2] #[repr(C)] #derive_layouts - pub struct #opt_final_name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare> + pub struct #opt_final_name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds_base { #mandatory_vtbl_defs #opt_vtbl_defs - container: #cont_name, + container: #cont_name, } #get_container_impl_final @@ -908,39 +925,39 @@ impl TraitGroup { #[doc = #opt_doc2] #[repr(C)] #derive_layouts - pub struct #opt_name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare> + pub struct #opt_name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds_base { #mandatory_vtbl_defs #opt_mixed_vtbl_defs - container: #cont_name, + container: #cont_name, } - unsafe impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> - #trg_path::Opaquable for #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + unsafe impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> + #trg_path::Opaquable for #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - type OpaqueTarget = #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; + type OpaqueTarget = #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>; } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> - From<#opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> + From<#opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - fn from(input: #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> Self { + fn from(input: #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> Self { #trg_path::Opaquable::into_opaque(input) } } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where Self: #trg_path::Opaquable, - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { /// Cast back into the original group @@ -990,7 +1007,7 @@ impl TraitGroup { /// #[doc = #func_check_doc2] pub fn #func_name_check(&self) -> bool - where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>: 'cglue_a + #impl_traits + where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>: 'cglue_a + #impl_traits { self.#func_name_ref().is_some() } @@ -999,7 +1016,7 @@ impl TraitGroup { /// #[doc = #func_final_doc2] pub fn #func_name_final(self) -> ::core::option::Option - where #opt_final_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>: 'cglue_a + #impl_traits + where #opt_final_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>: 'cglue_a + #impl_traits { let #name { container, @@ -1018,8 +1035,8 @@ impl TraitGroup { #[doc = #func_doc1] /// #[doc = #func_doc2] - pub fn #func_name(self) -> ::core::option::Option<#opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>> - where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>: 'cglue_a + #impl_traits + pub fn #func_name(self) -> ::core::option::Option<#opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>> + where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>: 'cglue_a + #impl_traits { let #name { container, @@ -1036,7 +1053,7 @@ impl TraitGroup { #[doc = #func_mut_doc1] pub fn #func_name_mut<'b>(&'b mut self) -> ::core::option::Option<&'b mut (impl 'cglue_a + #impl_traits)> - where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>: 'cglue_a + #impl_traits + where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>: 'cglue_a + #impl_traits { let #name { container, @@ -1053,13 +1070,13 @@ impl TraitGroup { // optional reference validity was checked beforehand unsafe { - (self as *mut Self as *mut #opt_name).as_mut() + (self as *mut Self as *mut #opt_name).as_mut() } } #[doc = #func_ref_doc1] pub fn #func_name_ref<'b>(&'b self) -> ::core::option::Option<&'b (impl 'cglue_a + #impl_traits)> - where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>: 'cglue_a + #impl_traits + where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>: 'cglue_a + #impl_traits { let #name { #mand_vtbl_list @@ -1075,7 +1092,7 @@ impl TraitGroup { // optional reference validity was checked beforehand unsafe { - (self as *const Self as *const #opt_name).as_ref() + (self as *const Self as *const #opt_name).as_ref() } } }); @@ -1084,23 +1101,23 @@ impl TraitGroup { #[cfg(not(feature = "unstable"))] let (extra_filler_traits, filler_trait_imports) = if self.extra_filler_traits { let traits = quote! { - pub trait #fwd_filler_trait<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare>: 'cglue_a + Sized + pub trait #fwd_filler_trait<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>>: 'cglue_a + Sized where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - fn fill_fwd_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; + fn fill_fwd_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>; } - impl<'cglue_a, CGlueInst: ::core::ops::Deref>, CGlueT, CGlueCtx: #ctx_bound, #gen_declare> - #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueInst: ::core::ops::Deref>, CGlueT, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> + #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> for #crate_path::forward::Fwd<&'cglue_a mut CGlueT> where - #cont_name: #trg_path::CGlueObjBase, - CGlueT: #fwd_filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use>, + #cont_name: #trg_path::CGlueObjBase, + CGlueT: #fwd_filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>, #gen_where_bounds { - fn fill_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use> { + fn fill_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> { CGlueT::fill_fwd_table(table) } } @@ -1126,8 +1143,7 @@ impl TraitGroup { #[cfg(feature = "unstable")] let cglue_inst_filler_trait_bound = quote!(); #[cfg(not(feature = "unstable"))] - let cglue_inst_filler_trait_bound = - quote!(CGlueInst::Target: #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use>,); + let cglue_inst_filler_trait_bound = quote!(CGlueInst::Target: #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>,); #[cfg(feature = "unstable")] let create_vtbl = quote!(Default::default()); #[cfg(not(feature = "unstable"))] @@ -1137,12 +1153,12 @@ impl TraitGroup { let filler_trait_impl = quote!(); #[cfg(not(feature = "unstable"))] let filler_trait_impl = quote! { - pub trait #filler_trait<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare>: Sized + pub trait #filler_trait<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>>: Sized where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - fn fill_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; + fn fill_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>; } #extra_filler_traits @@ -1159,7 +1175,11 @@ impl TraitGroup { pub use cglue_internal::{ #name, #vtable_type, + #assocs_trait, + #assocs_base_type, #filler_trait_imports + #base_name, + #base_baseassocs_name, #base_name_ref, #base_name_ctx_ref, #base_name_arc_ref, @@ -1203,21 +1223,32 @@ impl TraitGroup { /// perform any memory transformations either. They are the safest to use, because /// there is no risk of accidentally consuming the whole object. #derive_layouts - pub struct #name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare> + pub struct #name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds_base { #mandatory_vtbl_defs #optional_vtbl_defs - container: #cont_name, + container: #cont_name, + } + + /// Describes associated types of a trait group. + pub trait #assocs_trait<#gen_use> { + #assoc_decls + } + + pub type #assocs_base_type = (#assocs_num_void); + + impl<#gen_use #assoc_gen_defs> #assocs_trait<#gen_use> for (#assoc_gen_use) { + #assoc_defs } #get_container_impl #[repr(C)] #derive_layouts - pub struct #cont_name + pub struct #cont_name> { instance: CGlueInst, context: CGlueCtx, @@ -1226,27 +1257,27 @@ impl TraitGroup { #cglue_obj_impl - unsafe impl - #trg_path::Opaquable for #cont_name + unsafe impl> + #trg_path::Opaquable for #cont_name { - type OpaqueTarget = #cont_name; + type OpaqueTarget = #cont_name; } #[repr(C)] #derive_layouts - pub struct #vtable_type<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare> + pub struct #vtable_type<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds_base { #mandatory_vtbl_defs #optional_vtbl_defs } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> Default - for #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> Default + for #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #vtbl_where_bounds #gen_where_bounds { fn default() -> Self { @@ -1257,17 +1288,17 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { #enable_funcs } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { #enable_funcs_vtbl @@ -1275,63 +1306,69 @@ impl TraitGroup { #filler_trait_impl - pub type #base_name_boxed<'cglue_a, CGlueT, #gen_use> - = #base_name_ctx_box<'cglue_a, CGlueT, #crate_path::trait_group::NoContext, #gen_use>; + pub type #base_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>; + + pub type #base_baseassocs_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + = #base_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; + + pub type #base_name_boxed<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_ctx_box<'cglue_a, CGlueT, #crate_path::trait_group::NoContext, #gen_use CGlueAssocs>; - pub type #base_name_ctx_box<'cglue_a, CGlueT, CGlueCtx, #gen_use> - = #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use>; + pub type #base_name_ctx_box<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use CGlueAssocs>; - pub type #base_name_arc_box<'cglue_a, CGlueT, CGlueArcTy, #gen_use> - = #base_name_ctx_box<'cglue_a, CGlueT, #crate_path::arc::CArc, #gen_use>; + pub type #base_name_arc_box<'cglue_a, CGlueT, CGlueArcTy, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_ctx_box<'cglue_a, CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; - pub type #base_name_ref<'cglue_a, CGlueT, #gen_use> - = #name<'cglue_a, &'cglue_a CGlueT, #crate_path::trait_group::NoContext, #gen_use>; + pub type #base_name_ref<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> + = #name<'cglue_a, &'cglue_a CGlueT, #crate_path::trait_group::NoContext, #gen_use CGlueAssocs>; - pub type #base_name_ctx_ref<'cglue_a, CGlueT, CGlueCtx, #gen_use> - = #name<'cglue_a, &'cglue_a CGlueT, CGlueCtx, #gen_use>; + pub type #base_name_ctx_ref<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #name<'cglue_a, &'cglue_a CGlueT, CGlueCtx, #gen_use CGlueAssocs>; - pub type #base_name_arc_ref<'cglue_a, CGlueT, CGlueArcTy, #gen_use> - = #name<'cglue_a, &'cglue_a CGlueT, #crate_path::arc::CArc, #gen_use>; + pub type #base_name_arc_ref<'cglue_a, CGlueT, CGlueArcTy, #gen_use CGlueAssocs = #assocs_base_type> + = #name<'cglue_a, &'cglue_a CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; - pub type #base_name_mut<'cglue_a, CGlueT, #gen_use> - = #name<'cglue_a, &'cglue_a mut CGlueT, #crate_path::trait_group::NoContext, #gen_use>; + pub type #base_name_mut<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> + = #name<'cglue_a, &'cglue_a mut CGlueT, #crate_path::trait_group::NoContext, #gen_use CGlueAssocs>; - pub type #base_name_ctx_mut<'cglue_a, CGlueT, CGlueCtx, #gen_use> - = #name<'cglue_a, &'cglue_a mut CGlueT, CGlueCtx, #gen_use>; + pub type #base_name_ctx_mut<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #name<'cglue_a, &'cglue_a mut CGlueT, CGlueCtx, #gen_use CGlueAssocs>; - pub type #base_name_arc_mut<'cglue_a, CGlueT, CGlueArcTy, #gen_use> - = #name<'cglue_a, &'cglue_a mut CGlueT, #crate_path::arc::CArc, #gen_use>; + pub type #base_name_arc_mut<'cglue_a, CGlueT, CGlueArcTy, #gen_use CGlueAssocs = #assocs_base_type> + = #name<'cglue_a, &'cglue_a mut CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; - pub type #opaque_name_boxed<'cglue_a, #gen_use> - = #base_name_boxed<'cglue_a, #c_void, #gen_use>; + pub type #opaque_name_boxed<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_boxed<'cglue_a, #c_void, #gen_use CGlueAssocs>; - pub type #opaque_name_ref<'cglue_a, #gen_use> - = #base_name_ref<'cglue_a, #c_void, #gen_use>; + pub type #opaque_name_ref<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_ref<'cglue_a, #c_void, #gen_use CGlueAssocs>; - pub type #opaque_name_ctx_ref<'cglue_a, CGlueCtx, #gen_use> - = #base_name_ctx_ref<'cglue_a, #c_void, CGlueCtx, #gen_use>; + pub type #opaque_name_ctx_ref<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_ctx_ref<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; - pub type #opaque_name_arc_ref<'cglue_a, #gen_use> - = #base_name_arc_ref<'cglue_a, #c_void, #c_void, #gen_use>; + pub type #opaque_name_arc_ref<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_arc_ref<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; - pub type #opaque_name_mut<'cglue_a, #gen_use> - = #base_name_mut<'cglue_a, #c_void, #gen_use>; + pub type #opaque_name_mut<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_mut<'cglue_a, #c_void, #gen_use CGlueAssocs>; - pub type #opaque_name_ctx_mut<'cglue_a, CGlueCtx, #gen_use> - = #base_name_ctx_mut<'cglue_a, #c_void, CGlueCtx, #gen_use>; + pub type #opaque_name_ctx_mut<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_ctx_mut<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; - pub type #opaque_name_arc_mut<'cglue_a, #gen_use> - = #base_name_arc_mut<'cglue_a, #c_void, #c_void, #gen_use>; + pub type #opaque_name_arc_mut<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_arc_mut<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; - pub type #opaque_name_ctx_box<'cglue_a, CGlueCtx, #gen_use> - = #base_name_ctx_box<'cglue_a, #c_void, CGlueCtx, #gen_use>; + pub type #opaque_name_ctx_box<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_ctx_box<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; - pub type #opaque_name_arc_box<'cglue_a, #gen_use> - = #base_name_arc_box<'cglue_a, #c_void, #c_void, #gen_use>; + pub type #opaque_name_arc_box<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_name_arc_box<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> - From<(CGlueInst, CGlueCtx)> for #cont_name + impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> + From<(CGlueInst, CGlueCtx)> for #cont_name where Self: #trg_path::CGlueObjBase { @@ -1345,8 +1382,8 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, CGlueCtx: #ctx_bound, #gen_declare> - From<(CGlueT, CGlueCtx)> for #cont_name<#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueT, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> + From<(CGlueT, CGlueCtx)> for #cont_name<#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use CGlueAssocs> where Self: #trg_path::CGlueObjBase { @@ -1355,14 +1392,14 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> - From<#cont_name> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> + From<#cont_name> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #cglue_inst_filler_trait_bound #vtbl_where_bounds #gen_where_bounds { - fn from(container: #cont_name) -> Self { + fn from(container: #cont_name) -> Self { let vtbl = #create_vtbl; let #vtable_type { @@ -1378,11 +1415,11 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> - From<(CGlueInst, CGlueCtx)> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> + From<(CGlueInst, CGlueCtx)> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - Self: From<#cont_name>, - #cont_name: #trg_path::CGlueObjBase, + Self: From<#cont_name>, + #cont_name: #trg_path::CGlueObjBase, #vtbl_where_bounds #gen_where_bounds { fn from((instance, context): (CGlueInst, CGlueCtx)) -> Self { @@ -1390,8 +1427,8 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, #gen_declare> - From for #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use> + impl<'cglue_a, CGlueT, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> + From for #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use CGlueAssocs> where Self: From<(#crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext)>, #vtbl_where_bounds_boxed #gen_where_bounds @@ -1401,11 +1438,11 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: core::ops::Deref, #gen_declare> From - for #name<'cglue_a, CGlueInst, #trg_path::NoContext, #gen_use> + impl<'cglue_a, CGlueInst: core::ops::Deref, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> From + for #name<'cglue_a, CGlueInst, #trg_path::NoContext, #gen_use CGlueAssocs> where Self: From<(CGlueInst, #crate_path::trait_group::NoContext)>, - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #vtbl_where_bounds_noctx #gen_where_bounds { fn from(instance: CGlueInst) -> Self { @@ -1413,11 +1450,11 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, CGlueCtx: #ctx_bound, #gen_declare> From<(CGlueT, CGlueCtx)> - for #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueT, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> From<(CGlueT, CGlueCtx)> + for #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use CGlueAssocs> where Self: From<(#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx)>, - #cont_name<#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use>: #trg_path::CGlueObjBase, + #cont_name<#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use CGlueAssocs>: #trg_path::CGlueObjBase, #vtbl_where_bounds_ctxboxed #gen_where_bounds { fn from((this, context): (CGlueT, CGlueCtx)) -> Self { @@ -1425,10 +1462,10 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> - #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> + #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #vtbl_where_bounds #gen_where_bounds { #[doc = #new_doc] @@ -1448,7 +1485,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, #gen_declare> #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use> + impl<'cglue_a, CGlueT, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use CGlueAssocs> where #gen_where_bounds { #[doc = #new_doc] @@ -1464,25 +1501,26 @@ impl TraitGroup { /// Convert into opaque object. /// /// This is the prerequisite for using underlying trait implementations. - unsafe impl<'cglue_a, CGlueInst: #trg_path::Opaquable, CGlueCtx: #ctx_bound, #gen_declare> - #trg_path::Opaquable for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + unsafe impl<'cglue_a, CGlueInst: #trg_path::Opaquable, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> + #trg_path::Opaquable for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #trg_path::CGlueObjBase, - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - type OpaqueTarget = #name<'cglue_a, CGlueInst::OpaqueTarget, CGlueCtx, #gen_use>; + type OpaqueTarget = #name<'cglue_a, CGlueInst::OpaqueTarget, CGlueCtx, #gen_use CGlueAssocs>; } impl< 'cglue_a, CGlueInst, //: ::core::ops::Deref CGlueCtx: #ctx_bound, + CGlueAssocs: #assocs_trait<#gen_use>, #gen_declare > - #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { #trait_funcs @@ -1508,6 +1546,7 @@ impl TraitGroup { let mut ret = TokenStream::new(); let cont_name = &self.cont_name; + let assocs_trait = &self.assocs_trait; let ctx_bound = super::traits::ctx_bound(); @@ -1542,10 +1581,10 @@ impl TraitGroup { } let gen = quote! { - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_use> - #path #raw_ident <#tr_life_use #tr_gen_use> for #self_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_use CGlueAssocs: #assocs_trait<#gen_use>> + #path #raw_ident <#tr_life_use #tr_gen_use> for #self_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #crate_path::trait_group::CGlueObjBase, + #cont_name: #crate_path::trait_group::CGlueObjBase, Self: #ext_path #ext_name<#tr_life_use #tr_gen_use> { #impls @@ -1578,12 +1617,13 @@ impl TraitGroup { vtbl_name, path, vtbl_typename, + name_ident, generics: ParsedGenerics { gen_use, .. }, .. } in iter { ret.extend( - quote!(#vtbl_name: &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use>, ), + quote!(#vtbl_name: &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>, ), ); } @@ -1627,6 +1667,51 @@ impl TraitGroup { ret } + /// Get tokens for declaring and using associated types + /// + /// # Arguments + /// + /// * `traits` - traits to generate for. + fn trait_assocs<'a>( + &'a self, + traits: impl Iterator, + ) -> ( + TokenStream, + TokenStream, + TokenStream, + TokenStream, + TokenStream, + ) { + let mut assoc_gen_defs = TokenStream::new(); + let mut assoc_gen_use = TokenStream::new(); + let mut assoc_decls = TokenStream::new(); + let mut assoc_defs = TokenStream::new(); + let mut assocs_num_void = TokenStream::new(); + + for TraitInfo { + path, + assocs_typename, + name_ident, + generics: ParsedGenerics { gen_use, .. }, + .. + } in traits + { + assoc_gen_defs.extend(quote!(#name_ident: #path #assocs_typename<#gen_use>,)); + assoc_gen_use.extend(quote!(#name_ident,)); + assoc_decls.extend(quote!(type #name_ident: #path #assocs_typename<#gen_use>;)); + assoc_defs.extend(quote!(type #name_ident = #name_ident;)); + assocs_num_void.extend(quote!((),)); + } + + ( + assoc_gen_defs, + assoc_gen_use, + assoc_decls, + assoc_defs, + assocs_num_void, + ) + } + /// Optional and vtable definitions. /// /// Optional means they are of type `Option<&'cglue_a VTable>`. @@ -1641,12 +1726,13 @@ impl TraitGroup { vtbl_name, path, vtbl_typename, + name_ident, generics: ParsedGenerics { gen_use, .. }, .. } in &self.optional_vtbl { ret.extend( - quote!(#vtbl_name: ::core::option::Option<&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name<#inst_ident, #ctx_ident, #gen_all_use>, #gen_use>>, ), + quote!(#vtbl_name: ::core::option::Option<&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name<#inst_ident, #ctx_ident, #gen_all_use CGlueAssocs>, #gen_use CGlueAssocs::#name_ident>>, ), ); } @@ -1660,11 +1746,12 @@ impl TraitGroup { ret_tmp_name, path, ret_tmp_typename, + name_ident, generics: ParsedGenerics { gen_use, .. }, .. } in self.mandatory_vtbl.iter().chain(iter) { - ret.extend(quote!(#ret_tmp_name: #path #ret_tmp_typename, )); + ret.extend(quote!(#ret_tmp_name: #path #ret_tmp_typename, )); } ret @@ -1692,6 +1779,7 @@ impl TraitGroup { TraitInfo { vtbl_name, path, + name_ident, vtbl_typename, generics: ParsedGenerics { gen_use, .. }, .. @@ -1707,10 +1795,10 @@ impl TraitGroup { }) { let def = match mandatory { true => { - quote!(#vtbl_name: &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use>, ) + quote!(#vtbl_name: &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>, ) } false => { - quote!(#vtbl_name: ::core::option::Option<&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use>>, ) + quote!(#vtbl_name: ::core::option::Option<&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>>, ) } }; ret.extend(def); @@ -1723,6 +1811,7 @@ impl TraitGroup { fn get_container_impl( &self, name: &Ident, + assocs_trait: &Ident, trg_path: &TokenStream, all_generics: &ParsedGenerics, ) -> TokenStream { @@ -1738,13 +1827,13 @@ impl TraitGroup { let ctx_bound = super::traits::ctx_bound(); quote! { - impl - #trg_path::GetContainer for #name<'_, CGlueInst, CGlueCtx, #gen_use> + impl> + #trg_path::GetContainer for #name<'_, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - type ContType = #cont_name; + type ContType = #cont_name; fn ccont_ref(&self) -> &Self::ContType { &self.container @@ -1770,6 +1859,7 @@ impl TraitGroup { fn cglue_obj_impl(&self, trg_path: &TokenStream, all_generics: &ParsedGenerics) -> TokenStream { let cont_name = &self.cont_name; + let assocs_trait = &self.assocs_trait; let ParsedGenerics { gen_declare: all_gen_declare, @@ -1781,8 +1871,8 @@ impl TraitGroup { let ctx_bound = super::traits::ctx_bound(); let mut ret = quote! { - impl #trg_path::CGlueObjBase - for #cont_name + impl, #all_gen_declare> #trg_path::CGlueObjBase + for #cont_name where CGlueInst::Target: Sized, #all_gen_where_bounds @@ -1805,19 +1895,20 @@ impl TraitGroup { path, ret_tmp_typename, ret_tmp_name, + name_ident, generics: ParsedGenerics { gen_use, .. }, .. } in self.mandatory_vtbl.iter().chain(self.optional_vtbl.iter()) { ret.extend(quote!{ - impl - #trg_path::CGlueObjRef<#path #ret_tmp_typename> - for #cont_name + impl, #all_gen_declare> + #trg_path::CGlueObjRef<#path #ret_tmp_typename> + for #cont_name where CGlueInst::Target: Sized, #all_gen_where_bounds { - fn cobj_ref(&self) -> (&Self::ObjType, &#path #ret_tmp_typename, &Self::Context) { + fn cobj_ref(&self) -> (&Self::ObjType, &#path #ret_tmp_typename, &Self::Context) { (self.instance.deref(), &self.#ret_tmp_name, &self.context) } } @@ -1825,14 +1916,15 @@ impl TraitGroup { impl< CGlueInst: ::core::ops::DerefMut, CGlueCtx: #ctx_bound, + CGlueAssocs: #assocs_trait<#all_gen_use>, #all_gen_declare - > #trg_path::CGlueObjMut<#path #ret_tmp_typename> - for #cont_name + > #trg_path::CGlueObjMut<#path #ret_tmp_typename> + for #cont_name where CGlueInst::Target: Sized, #all_gen_where_bounds { - fn cobj_mut(&mut self) -> (&mut Self::ObjType, &mut #path #ret_tmp_typename, &Self::Context) { + fn cobj_mut(&mut self) -> (&mut Self::ObjType, &mut #path #ret_tmp_typename, &Self::Context) { ( self.instance.deref_mut(), &mut self.#ret_tmp_name, @@ -1872,6 +1964,7 @@ impl TraitGroup { let mut ret = TokenStream::new(); let cont_name = &self.cont_name; + let assocs_trait = &self.assocs_trait; let all_gen_declare = &all_generics.gen_declare; let all_gen_use = &all_generics.gen_use; @@ -1883,7 +1976,8 @@ impl TraitGroup { vtbl_name, path, vtbl_typename, - vtbl_info_typename, + vtbl_get_ident, + name_ident, generics: ParsedGenerics { gen_use, .. }, .. } in traits @@ -1892,14 +1986,27 @@ impl TraitGroup { // TODO: bring back CGlueObjBuild - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #all_gen_declare> #trg_path::GetVtbl<'cglue_a, (#gen_use), #path #vtbl_info_typename> - for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #all_gen_declare CGlueAssocs: #assocs_trait<#all_gen_use>> #trg_path::GetVtblBase<#path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>> + for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use CGlueAssocs> + where + #cont_name: #trg_path::CGlueObjBase, + #all_gen_where_bounds + { + fn get_vtbl_base(&self) -> &#path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident> { + &self.#vtbl_name + } + } + + impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #all_gen_declare CGlueAssocs: #assocs_trait<#all_gen_use>> #path #vtbl_get_ident<'cglue_a, #gen_use> + for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use CGlueAssocs> where ::Target: Sized, - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #all_gen_where_bounds { - fn get_vtbl(&self) -> &#path #vtbl_typename<'cglue_a, #cont_name, #gen_use> { + type Assocs = CGlueAssocs::#name_ident; + + fn get_vtbl(&self) -> &#path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident> { &self.#vtbl_name } } @@ -1950,13 +2057,15 @@ impl TraitGroup { vtbl_name, path, vtbl_typename, + #[cfg(feature = "unstable")] + name_ident, generics: ParsedGenerics { gen_use, .. }, .. } in &self.optional_vtbl { #[cfg(feature = "unstable")] { - let vtbl_ty = quote!(&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use>); + let vtbl_ty = quote!(&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>); ret.extend(quote!(#vtbl_name: <#vtbl_ty as #crate_path::TryDefault<#vtbl_ty>>::try_default(),)); } #[cfg(not(feature = "unstable"))] @@ -2061,6 +2170,7 @@ impl TraitGroup { for TraitInfo { path, raw_ident, + name_ident, vtbl_typename, generics: ParsedGenerics { gen_use, life_use, .. @@ -2081,7 +2191,7 @@ impl TraitGroup { ret.extend(quote!(#trait_bound: #path #raw_ident<#life_use #gen_use>,)); } - ret.extend(quote!(&#vtbl_lifetime #path #vtbl_typename<#vtbl_lifetime, #cont_name<#container_ident, #ctx_ident, #all_gen_use>, #gen_use>: #vtbl_lifetime + Default,)); + ret.extend(quote!(&#vtbl_lifetime #path #vtbl_typename<#vtbl_lifetime, #cont_name<#container_ident, #ctx_ident, #all_gen_use CGlueAssocs>, #gen_use CGlueAssocs::#name_ident>: #vtbl_lifetime + Default,)); } ret diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index fceb6ef..52c2334 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -155,8 +155,17 @@ pub fn process_item( .parse_args::() .expect("Invalid type in wrap_with."); + let target_ty = new_ty.clone(); let target = new_ty.target.clone(); + //if target.to_string() == "G" + + let mut new_ty_assocs = new_ty.clone(); + new_ty_assocs.target = + format_ident!("{}BaseAssocs", target.to_string()).to_token_stream(); + core::mem::take(&mut new_ty_assocs.generic_types); + core::mem::take(&mut new_ty_assocs.generic_lifetimes); + if ["wrap_with_obj", "wrap_with_obj_ref", "wrap_with_obj_mut"].contains(&x) { new_ty.target = format_ident!("{}Base", target.to_string()).to_token_stream(); } @@ -251,69 +260,72 @@ pub fn process_item( quote!(#crate_path::boxed::CBox<#lifetime, #c_void>, ::Context, ), ); new_ty_hrtb.push_types_start( - quote!(#crate_path::boxed::CBox<#from_lifetime, #c_void>, CGlueC::Context,), + quote!(#crate_path::boxed::CBox<#from_lifetime, #c_void>, CGlueC::Context, ), ); new_ty_simple.push_types_start( - quote!(#crate_path::boxed::CBox<#from_lifetime_simple, #c_void>, CGlueC::Context,), + quote!(#crate_path::boxed::CBox<#from_lifetime_simple, #c_void>, CGlueC::Context, ), ); new_ty_static.push_types_start( - quote!(#crate_path::boxed::CBox<'static, #c_void>, CGlueCtx,), + quote!(#crate_path::boxed::CBox<'static, #c_void>, CGlueCtx, ), ); + if let Some((cglue_f_ty_def, cglue_f_ty_simple_ident)) = &cglue_f_tys { from_new_ty.push_types_start( quote!(#crate_path::boxed::CBox<#from_lifetime, #cglue_f_ty_def>, CGlueC::Context, ), ); from_new_ty_simple.push_types_start( - quote!(#crate_path::boxed::CBox<#from_lifetime_simple, #cglue_f_ty_simple_ident>, CGlueC::Context,), + quote!(#crate_path::boxed::CBox<#from_lifetime_simple, #cglue_f_ty_simple_ident>, CGlueC::Context, ), ); } } else if x == "wrap_with_group_ref" || x == "wrap_with_obj_ref" { let no_context = quote!(CGlueC::Context); - new_ty.push_types_start(quote!(&#lifetime #c_void, CGlueC::Context,)); - new_ty_ret_tmp.push_types_start(quote!(&#lifetime #c_void, CGlueCtx,)); + new_ty.push_types_start(quote!(&#lifetime #c_void, CGlueC::Context, )); + new_ty_ret_tmp.push_types_start(quote!(&#lifetime #c_void, CGlueCtx, )); new_ty_trait_impl.push_types_start( - quote!(&#lifetime #c_void, ::Context,), + quote!(&#lifetime #c_void, ::Context, ), ); new_ty_hrtb.push_types_start( - quote!(&#from_lifetime #c_void, CGlueC::Context,), + quote!(&#from_lifetime #c_void, CGlueC::Context, ), ); new_ty_simple.push_types_start( - quote!(&#from_lifetime_simple #c_void, CGlueC::Context,), + quote!(&#from_lifetime_simple #c_void, CGlueC::Context, ), ); - new_ty_static.push_types_start(quote!(&'static #c_void, CGlueCtx,)); + new_ty_static.push_types_start(quote!(&'static #c_void, CGlueCtx, )); if let Some((cglue_f_ty_def, cglue_f_ty_simple_ident)) = &cglue_f_tys { from_new_ty.push_types_start( - quote!(&#from_lifetime #cglue_f_ty_def, #no_context,), + quote!(&#from_lifetime #cglue_f_ty_def, #no_context, ), ); from_new_ty_ref.extend(quote!(&#from_lifetime)); from_new_ty_simple.push_types_start( - quote!(&#from_lifetime_simple #cglue_f_ty_simple_ident, #no_context,), + quote!(&#from_lifetime_simple #cglue_f_ty_simple_ident, #no_context, ), ); from_new_ty_simple_ref.extend(quote!(&#from_lifetime_simple)); } } else if x == "wrap_with_group_mut" || x == "wrap_with_obj_mut" { let no_context = quote!(CGlueC::Context); - new_ty - .push_types_start(quote!(&#lifetime mut #c_void, CGlueC::Context,)); + new_ty.push_types_start( + quote!(&#lifetime mut #c_void, CGlueC::Context, ), + ); new_ty_ret_tmp - .push_types_start(quote!(&#lifetime mut #c_void, CGlueCtx,)); + .push_types_start(quote!(&#lifetime mut #c_void, CGlueCtx, )); new_ty_trait_impl.push_types_start( - quote!(&#lifetime mut #c_void, ::Context,), + quote!(&#lifetime mut #c_void, ::Context, ), ); new_ty_hrtb.push_types_start( - quote!(&#from_lifetime mut #c_void, CGlueC::Context,), + quote!(&#from_lifetime mut #c_void, CGlueC::Context, ), ); new_ty_simple.push_types_start( - quote!(&#from_lifetime_simple mut #c_void, CGlueC::Context,), + quote!(&#from_lifetime_simple mut #c_void, CGlueC::Context, ), ); - new_ty_static.push_types_start(quote!(&'static mut #c_void, CGlueCtx,)); + new_ty_static + .push_types_start(quote!(&'static mut #c_void, CGlueCtx, )); if let Some((cglue_f_ty_def, cglue_f_ty_simple_ident)) = &cglue_f_tys { from_new_ty.push_types_start( - quote!(&#from_lifetime mut #cglue_f_ty_def, #no_context,), + quote!(&#from_lifetime mut #cglue_f_ty_def, #no_context, ), ); from_new_ty_ref.extend(quote!(&#from_lifetime mut)); from_new_ty_simple.push_types_start( - quote!(&#from_lifetime_simple mut #cglue_f_ty_simple_ident, #no_context,), + quote!(&#from_lifetime_simple mut #cglue_f_ty_simple_ident, #no_context, ), ); from_new_ty_simple_ref.extend(quote!(&#from_lifetime_simple mut)); } @@ -321,7 +333,24 @@ pub fn process_item( unreachable!() } + for v in [ + &mut new_ty, + &mut new_ty_ret_tmp, + &mut new_ty_trait_impl, + &mut new_ty_hrtb, + &mut new_ty_simple, + &mut new_ty_static, + ] + .iter_mut() + { + v.push_types_end(quote!(#new_ty_assocs, )); + } + if let Some((cglue_f_ty_def, cglue_f_ty_simple_ident)) = cglue_f_tys { + for v in [&mut from_new_ty, &mut from_new_ty_simple].iter_mut() { + v.push_types_end(quote!(#new_ty_assocs, )); + } + let (ty_ref, ty_ref_simple) = { ( quote!((#from_new_ty_ref #cglue_f_ty_def, CGlueC::Context)), @@ -384,6 +413,8 @@ pub fn process_item( (ret_write_unsafe.clone(), quote!('cglue_a)) }; + let target = target_ty; + let (return_conv, inject_ret_tmp) = match x { "wrap_with_obj" => ( parse2(quote!(|ret| trait_obj!((ret, cglue_ctx) as #target))) @@ -683,11 +714,14 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { // Additional identifiers let vtbl_ident = format_ident!("{}Vtbl", trait_name); - let vtbl_info_ident = format_ident!("{}VtblInfo", trait_name); + let vtbl_get_ident = format_ident!("{}VtblGet", trait_name); + let trait_assocs_ident = format_ident!("{}TraitAssocs", trait_name); + let vtbl_assocs_ident = format_ident!("{}VtblAssocs", trait_name); let ret_tmp_ident = format_ident!("{}RetTmp", trait_name); let ret_tmp_ident_phantom = format_ident!("{}RetTmpPhantom", trait_name); let accessor_trait_ident = format_ident!("{}OpaqueObj", trait_name); + let assocs_base_type = format_ident!("{}BaseAssocs", trait_name); let base_box_trait_obj_ident = format_ident!("{}BaseBox", trait_name); let base_ctx_trait_obj_ident = format_ident!("{}BaseCtxBox", trait_name); let base_arc_trait_obj_ident = format_ident!("{}BaseArcBox", trait_name); @@ -698,6 +732,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { let base_ctx_ref_trait_obj_ident = format_ident!("{}BaseCtxRef", trait_name); let base_arc_ref_trait_obj_ident = format_ident!("{}BaseArcRef", trait_name); let base_trait_obj_ident = format_ident!("{}Base", trait_name); + let base_baseassocs_trait_obj_ident = format_ident!("{}BaseBaseAssocs", trait_name); let opaque_box_trait_obj_ident = format_ident!("{}Box", trait_name); let opaque_ctx_trait_obj_ident = format_ident!("{}CtxBox", trait_name); @@ -755,10 +790,22 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { }; #[cfg(feature = "layout_checks")] - let derive_layouts = quote!(#[derive(::abi_stable::StableAbi)]); + let derive_layouts = + quote!(#[derive(::abi_stable::StableAbi)] #[sabi(unsafe_unconstrained(CGlueAssocs))]); #[cfg(not(feature = "layout_checks"))] let derive_layouts = quote!(); + #[cfg(feature = "layout_checks")] + let cglue_assocs_phantom_decl = + quote!(::abi_stable::marker_type::UnsafeIgnoredType); + #[cfg(not(feature = "layout_checks"))] + let cglue_assocs_phantom_decl = quote!(::core::marker::PhantomData); + #[cfg(feature = "layout_checks")] + let cglue_assocs_phantom_new = + quote!(::abi_stable::marker_type::UnsafeIgnoredType::::NEW); + #[cfg(not(feature = "layout_checks"))] + let cglue_assocs_phantom_new = quote!(::core::marker::PhantomData); + // Function definitions in the vtable let mut vtbl_func_defintions = TokenStream::new(); @@ -783,10 +830,16 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { // Define wrapped functions for the vtable let mut cfuncs = TokenStream::new(); - let ret_tmp_ty = quote!(#ret_tmp_ident); + let ret_tmp_ty = quote!(#ret_tmp_ident); for func in funcs.iter() { - let extra_bounds = func.cfunc_def(&mut cfuncs, &trg_path, &ret_tmp_ty); + let extra_bounds = func.cfunc_def( + &mut cfuncs, + &trg_path, + &ret_tmp_ty, + &vtbl_assocs_ident, + &trait_assocs_ident, + ); trait_type_bounds.extend(extra_bounds.to_token_stream()); } @@ -938,6 +991,8 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { ); let submod_name = format_ident!("cglue_{}", trait_name.to_string().to_lowercase()); + let assoc_bound = quote!(#vtbl_assocs_ident<#gen_use>); + let ret_tmp = if !ret_tmp_type_defs.is_empty() { quote! { /// Temporary return value structure, for returning wrapped references. @@ -947,25 +1002,27 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /// directly. Use the trait functions. #[repr(C)] #derive_layouts - pub struct #ret_tmp_ident + pub struct #ret_tmp_ident { #ret_tmp_type_defs #phantom_data_definitions + _ty_cglue_assocs: #cglue_assocs_phantom_decl, _ty_cglue_ctx: ::core::marker::PhantomData, } - impl #ret_tmp_ident + impl #ret_tmp_ident { #ret_tmp_getter_defs } - impl Default for #ret_tmp_ident + impl Default for #ret_tmp_ident { fn default() -> Self { Self { #ret_tmp_default_defs #phantom_data_init - _ty_cglue_ctx: ::core::marker::PhantomData{}, + _ty_cglue_assocs: Default::default(), + _ty_cglue_ctx: ::core::marker::PhantomData, } } } @@ -975,9 +1032,10 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /// Technically unused phantom data definition structure. #[repr(C)] #derive_layouts - pub struct #ret_tmp_ident_phantom + pub struct #ret_tmp_ident_phantom { #phantom_data_definitions + _ty_cglue_assocs: #cglue_assocs_phantom_decl, _ty_cglue_ctx: ::core::marker::PhantomData, } @@ -991,14 +1049,14 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /// groups/objects. If C++11 templates are generated, it is important to define a /// custom type for CGlueTraitObj that does not have `ret_tmp` defined, and change all /// type aliases of this trait to use that particular structure. - pub type #ret_tmp_ident = ::core::marker::PhantomData<#ret_tmp_ident_phantom>; + pub type #ret_tmp_ident = ::core::marker::PhantomData<#ret_tmp_ident_phantom>; } }; #[cfg(feature = "layout_checks")] let (opaque_vtbl_bounds, container_vtbl_bounds) = ( - quote!(#vtbl_ident<'cglue_a, CGlueC::OpaqueTarget, #gen_use>: ::abi_stable::StableAbi,), - quote!(#vtbl_ident<'cglue_a, ::ContType, #gen_use>: ::abi_stable::StableAbi,), + quote!(#vtbl_ident<'cglue_a, CGlueC::OpaqueTarget, #gen_use CGlueAssocs>: ::abi_stable::StableAbi,), + quote!(#vtbl_ident<'cglue_a, ::ContType, #gen_use >::Assocs>: ::abi_stable::StableAbi,), ); #[cfg(not(feature = "layout_checks"))] let (opaque_vtbl_bounds, container_vtbl_bounds) = (quote!(), quote!()); @@ -1024,10 +1082,14 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { #vis use cglue_internal::{ #vtbl_ident, - #vtbl_info_ident, + #vtbl_get_ident, #ret_tmp_ident, #accessor_trait_ident, + #vtbl_assocs_ident, + #trait_assocs_ident, + #assocs_base_type, + #base_box_trait_obj_ident, #base_ctx_trait_obj_ident, #base_arc_trait_obj_ident, @@ -1038,6 +1100,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { #base_ctx_ref_trait_obj_ident, #base_arc_ref_trait_obj_ident, #base_trait_obj_ident, + #base_baseassocs_trait_obj_ident, #opaque_box_trait_obj_ident, #opaque_ctx_trait_obj_ident, @@ -1056,14 +1119,28 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /* Primary vtable definition. */ - pub struct #vtbl_info_ident; + /// Associated types, extracted from the trait + /// + /// Associated types are encoded as a tuple of all associated types, sorted alphabetically. + pub trait #vtbl_assocs_ident<#gen_use>: 'static { + //type ReturnType; + } - impl<#gen_declare_stripped> #trg_path::TraitInfo<(#gen_use)> for #vtbl_info_ident - where - #gen_where_bounds_base_nolt + impl<#gen_use> #vtbl_assocs_ident<#gen_use> for () { + } + + /// Helper for getting associated types from a `T` that implements the trait. + pub trait #trait_assocs_ident<#gen_use> { + type Assocs: #vtbl_assocs_ident<#gen_use>; + } + + pub type #assocs_base_type = (); + + impl #trait_name<#life_use #gen_use>, #gen_declare_stripped> #trait_assocs_ident<#gen_use> for CGlueInst + where + #gen_where_bounds_base_nolt { type Assocs = (); - type Vtbl<'cglue_a, CGlueC: #trg_path::CGlueObjBase> = #vtbl_ident<'cglue_a, CGlueC, #gen_use> where CGlueC: 'cglue_a; } #[doc = #vtbl_doc] @@ -1071,15 +1148,26 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /// This virtual function table contains ABI-safe interface for the given trait. #[repr(C)] #derive_layouts - pub struct #vtbl_ident<'cglue_a, CGlueC: 'cglue_a + #trg_path::CGlueObjBase, #gen_declare_stripped> + pub struct #vtbl_ident< + 'cglue_a, + CGlueC: 'cglue_a + #trg_path::CGlueObjBase, + #gen_declare_stripped + CGlueAssocs: 'cglue_a + #assoc_bound, + > where #gen_where_bounds_base_nolt { #vtbl_func_defintions _lt_cglue_a: ::core::marker::PhantomData<&'cglue_a CGlueC>, + _assocs: #cglue_assocs_phantom_decl, } - impl<'cglue_a, CGlueC: #trg_path::CGlueObjBase, #gen_declare_stripped> #vtbl_ident<'cglue_a, CGlueC, #gen_use> + impl< + 'cglue_a, + CGlueC: #trg_path::CGlueObjBase, + #gen_declare_stripped + CGlueAssocs: #assoc_bound, + > #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs> where #gen_where_bounds { @@ -1091,138 +1179,153 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /* Default implementation. */ /// Default vtable reference creation. - impl<'cglue_a, CGlueC #cglue_c_bounds, CGlueCtx: #ctx_bound, #gen_declare_stripped> Default - for &'cglue_a #vtbl_ident<'cglue_a, CGlueC, #gen_use> + impl<'cglue_a, CGlueC #cglue_c_bounds, CGlueCtx: #ctx_bound, #gen_declare_stripped CGlueAssocs: 'cglue_a + #assoc_bound> Default + for &'cglue_a #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs> where #gen_where_bounds #trait_type_bounds #cglue_c_into_inner - CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use>, + CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use> + #trait_assocs_ident<#gen_use Assocs = CGlueAssocs>, CGlueC: #trg_path::Opaquable, CGlueC::OpaqueTarget: #trg_path::GenericTypeBounds, - #vtbl_ident<'cglue_a, CGlueC, #gen_use>: #trg_path::CGlueBaseVtbl, + #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs>: #trg_path::CGlueBaseVtbl, { /// Create a static vtable for the given type. fn default() -> Self { &#vtbl_ident { #vtbl_default_funcs _lt_cglue_a: ::core::marker::PhantomData, + _assocs: #cglue_assocs_phantom_new, } } } /* Vtable trait implementations. */ - impl<'cglue_a, CGlueC: #trg_path::CGlueObjBase, #gen_declare_stripped> - #trg_path::CGlueVtblCont for #vtbl_ident<'cglue_a, CGlueC, #gen_use> + impl< + 'cglue_a, + CGlueC: #trg_path::CGlueObjBase, + #gen_declare_stripped + CGlueAssocs: #assoc_bound, + > + #trg_path::CGlueVtblCont for #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs> where #gen_where_bounds { type ContType = CGlueC; } - unsafe impl<'cglue_a, CGlueC: #trg_path::Opaquable + #trg_path::CGlueObjBase + 'cglue_a, #gen_declare_stripped> #trg_path::CGlueBaseVtbl - for #vtbl_ident<'cglue_a, CGlueC, #gen_use> + unsafe impl< + 'cglue_a, + CGlueC: #trg_path::Opaquable + #trg_path::CGlueObjBase + 'cglue_a, + #gen_declare_stripped + CGlueAssocs: #assoc_bound, + > #trg_path::CGlueBaseVtbl + for #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs> where #gen_where_bounds #cglue_c_opaque_bound - CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use>, + CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use> + #trait_assocs_ident<#gen_use Assocs = CGlueAssocs>, CGlueC::OpaqueTarget: #trg_path::GenericTypeBounds, #opaque_vtbl_bounds { - type OpaqueVtbl = #vtbl_ident<'cglue_a, CGlueC::OpaqueTarget, #gen_use>; + type OpaqueVtbl = #vtbl_ident<'cglue_a, CGlueC::OpaqueTarget, #gen_use CGlueAssocs>; type Context = CGlueC::Context; - type RetTmp = #ret_tmp_ident; + type RetTmp = #ret_tmp_ident; } - impl<'cglue_a, CGlueC #cglue_c_bounds, CGlueCtx: #ctx_bound, #gen_declare_stripped> #trg_path::CGlueVtbl - for #vtbl_ident<'cglue_a, CGlueC, #gen_use> + impl<'cglue_a, CGlueC #cglue_c_bounds, CGlueCtx: #ctx_bound, #gen_declare_stripped CGlueAssocs: 'cglue_a + #assoc_bound> #trg_path::CGlueVtbl + for #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs> where #gen_where_bounds #cglue_c_opaque_bound CGlueC: #trg_path::Opaquable, CGlueC::OpaqueTarget: #trg_path::GenericTypeBounds, - CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use> {} + CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use> + #trait_assocs_ident<#gen_use Assocs = CGlueAssocs> {} #[doc = #base_box_trait_obj_doc] - pub type #base_box_trait_obj_ident<'cglue_a, CGlueT, #gen_use> - = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #trg_path::NoContext, #gen_use>; + pub type #base_box_trait_obj_ident<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> + = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #trg_path::NoContext, #gen_use CGlueAssocs>; #[doc = #base_ctx_trait_obj_doc] - pub type #base_ctx_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use> - = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use>; + pub type #base_ctx_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use CGlueAssocs>; #[doc = #base_arc_trait_obj_doc] - pub type #base_arc_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use> - = #base_ctx_trait_obj_ident<'cglue_a, CGlueT, #crate_path::arc::CArc, #gen_use>; + pub type #base_arc_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use CGlueAssocs = #assocs_base_type> + = #base_ctx_trait_obj_ident<'cglue_a, CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; #[doc = #base_mut_trait_obj_doc] - pub type #base_mut_trait_obj_ident<'cglue_a, CGlueT, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #trg_path::NoContext, #gen_use>; + pub type #base_mut_trait_obj_ident<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> + = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #trg_path::NoContext, #gen_use CGlueAssocs>; #[doc = #base_ctx_mut_trait_obj_doc] - pub type #base_ctx_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, CGlueCtx, #gen_use>; + pub type #base_ctx_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, CGlueCtx, #gen_use CGlueAssocs>; #[doc = #base_arc_mut_trait_obj_doc] - pub type #base_arc_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #crate_path::arc::CArc, #gen_use>; + pub type #base_arc_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use CGlueAssocs = #assocs_base_type> + = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; #[doc = #base_ref_trait_obj_doc] - pub type #base_ref_trait_obj_ident<'cglue_a, CGlueT, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #trg_path::NoContext, #gen_use>; + pub type #base_ref_trait_obj_ident<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> + = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #trg_path::NoContext, #gen_use CGlueAssocs>; #[doc = #base_ctx_ref_trait_obj_doc] - pub type #base_ctx_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, CGlueCtx, #gen_use>; + pub type #base_ctx_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, CGlueCtx, #gen_use CGlueAssocs>; #[doc = #base_arc_ref_trait_obj_doc] - pub type #base_arc_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #crate_path::arc::CArc, #gen_use>; + pub type #base_arc_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use CGlueAssocs = #assocs_base_type> + = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; #[doc = #base_trait_obj_doc] - pub type #base_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + pub type #base_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> = #trg_path::CGlueTraitObj::< 'cglue_a, CGlueInst, #vtbl_ident< 'cglue_a, - #trg_path::CGlueObjContainer>, + #trg_path::CGlueObjContainer>, #gen_use + CGlueAssocs, >, CGlueCtx, - #ret_tmp_ident + #ret_tmp_ident >; + pub type #base_baseassocs_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + = #base_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; + #[doc = #opaque_box_trait_obj_doc] - pub type #opaque_box_trait_obj_ident<'cglue_a, #gen_use> - = #base_box_trait_obj_ident<'cglue_a, #c_void, #gen_use>; + pub type #opaque_box_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_box_trait_obj_ident<'cglue_a, #c_void, #gen_use CGlueAssocs>; #[doc = #opaque_ctx_trait_obj_doc] - pub type #opaque_ctx_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use> - = #base_ctx_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use>; + pub type #opaque_ctx_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #base_ctx_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; #[doc = #opaque_arc_trait_obj_doc] - pub type #opaque_arc_trait_obj_ident<'cglue_a, #gen_use> - = #base_arc_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use>; + pub type #opaque_arc_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_arc_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; #[doc = #opaque_mut_trait_obj_doc] - pub type #opaque_mut_trait_obj_ident<'cglue_a, #gen_use> - = #base_mut_trait_obj_ident<'cglue_a, #c_void, #gen_use>; + pub type #opaque_mut_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_mut_trait_obj_ident<'cglue_a, #c_void, #gen_use CGlueAssocs>; #[doc = #opaque_ctx_mut_trait_obj_doc] - pub type #opaque_ctx_mut_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use> - = #base_ctx_mut_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use>; + pub type #opaque_ctx_mut_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #base_ctx_mut_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; #[doc = #opaque_arc_mut_trait_obj_doc] - pub type #opaque_arc_mut_trait_obj_ident<'cglue_a, #gen_use> - = #base_arc_mut_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use>; + pub type #opaque_arc_mut_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_arc_mut_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; #[doc = #opaque_ref_trait_obj_doc] - pub type #opaque_ref_trait_obj_ident<'cglue_a, #gen_use> - = #base_ref_trait_obj_ident<'cglue_a, #c_void, #gen_use>; + pub type #opaque_ref_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_ref_trait_obj_ident<'cglue_a, #c_void, #gen_use CGlueAssocs>; #[doc = #opaque_ctx_ref_trait_obj_doc] - pub type #opaque_ctx_ref_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use> - = #base_ctx_ref_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use>; + pub type #opaque_ctx_ref_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + = #base_ctx_ref_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; #[doc = #opaque_arc_ref_trait_obj_doc] - pub type #opaque_arc_ref_trait_obj_ident<'cglue_a, #gen_use> - = #base_arc_ref_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use>; + pub type #opaque_arc_ref_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> + = #base_arc_ref_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; /* Internal wrapper functions. */ @@ -1231,7 +1334,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /* Define trait for simpler type accesses */ pub trait #accessor_trait_ident<'cglue_a #cglue_a_outlives, #life_declare #gen_declare> - : 'cglue_a + #trg_path::GetContainer + #trg_path::GetVtbl<'cglue_a, (#gen_use), #vtbl_info_ident> #supertrait_bounds + : 'cglue_a + #trg_path::GetContainer + #vtbl_get_ident<'cglue_a, #gen_use> #supertrait_bounds where #gen_where_bounds { @@ -1239,23 +1342,61 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { } impl<'cglue_a #cglue_a_outlives, #life_declare - CGlueO: 'cglue_a + #trg_path::GetContainer + #trg_path::GetVtbl<'cglue_a, (#gen_use), #vtbl_info_ident> #supertrait_bounds, #gen_declare> + CGlueO: 'cglue_a + #trg_path::GetContainer + #vtbl_get_ident<'cglue_a, #gen_use> #supertrait_bounds, #gen_declare> #accessor_trait_ident<'cglue_a, #life_use #gen_use> for CGlueO where #objcont_accessor_bound #gen_where_bounds { - type #vtbl_ident = #vtbl_ident<'cglue_a, ::ContType, #gen_use>; + type #vtbl_ident = #vtbl_ident<'cglue_a, ::ContType, #gen_use >::Assocs>; + } + + /* Getters for vtables. Automatically implemented for CGlueTraitObj */ + + pub trait #vtbl_get_ident<'cglue_a, #gen_declare_stripped>: + #trg_path::GetContainer + where + #gen_where_bounds_base + { + // List unspecified associated types here: + type Assocs: #assoc_bound; + + fn get_vtbl(&self) -> &#vtbl_ident<'cglue_a, ::ContType, #gen_use Self::Assocs>; + } + + impl< + 'cglue_a, + CGlueT: ::core::ops::Deref, + CGlueF, + CGlueCtx: #ctx_bound, + CGlueAssocs: #assoc_bound, + CGlueRetTmp, + #gen_declare_stripped + > + #vtbl_get_ident<'cglue_a, #gen_use> + for #trg_path::CGlueTraitObj<'cglue_a, CGlueT, #vtbl_ident<'cglue_a, #trg_path::CGlueObjContainer, #gen_use CGlueAssocs>, CGlueCtx, CGlueRetTmp> + where + #gen_where_bounds_base + { + type Assocs = CGlueAssocs; + + fn get_vtbl(&self) -> &#vtbl_ident<'cglue_a, ::ContType, #gen_use CGlueAssocs> { + #trg_path::GetVtblBase::get_vtbl_base(self) + } } /* Trait implementation. */ #unsafety impl<'cglue_a #cglue_a_outlives, #life_declare - CGlueO: 'cglue_a + /*#trg_path::GetContainer + */#trg_path::GetVtbl<'cglue_a, (#gen_use), #vtbl_info_ident> #supertrait_bounds + CGlueO: 'cglue_a + #vtbl_get_ident<'cglue_a, #gen_use> #supertrait_bounds // We essentially need only this bound, but we repeat the previous ones because // otherwise we get conflicting impl errors. // TODO: Is this a bug? Typically Rust typesystem doesn't complain in such cases. - + #accessor_trait_ident<'cglue_a, #life_use #gen_use>, + + #accessor_trait_ident<'cglue_a, #life_use #gen_use> + // We also need to specify this one, for some reason. If not for conflicting + // impl errors, `GetVtblBase` would be a relatively redundant trait with no + // purpose. + + #trg_path::GetVtblBase<#vtbl_ident<'cglue_a, ::ContType, #gen_use >::Assocs>>, #gen_declare> #trait_impl_name<#life_use #gen_use> for CGlueO where diff --git a/cglue-macro/src/lib.rs b/cglue-macro/src/lib.rs index 1f7a01a..a68d896 100644 --- a/cglue-macro/src/lib.rs +++ b/cglue-macro/src/lib.rs @@ -4,10 +4,9 @@ extern crate proc_macro; use cglue_gen::ext::{ext_abs_remap, prelude_remap_with_ident}; use cglue_gen::forward::gen_forward; -use cglue_gen::generics::GenericCastType; +use cglue_gen::generics::{GenericCastType, GroupCastType}; use cglue_gen::trait_groups::*; use proc_macro::TokenStream; -use quote::ToTokens; use quote::{format_ident, quote}; use syn::*; @@ -54,20 +53,21 @@ pub fn cglue_trait_ext(_args: TokenStream, input: TokenStream) -> TokenStream { pub fn trait_obj(args: TokenStream) -> TokenStream { let crate_path = cglue_gen::util::crate_path(); - let GenericCastType { ident, mut target } = parse_macro_input!(args as GenericCastType); + let GenericCastType { + mut target, + expr, + ident, + } = parse_macro_input!(args as GenericCastType); - if let Ok(ident) = parse2::(target.target.clone()) { + if let Ok(ident) = parse2::(ident) { target.path = ext_abs_remap(prelude_remap_with_ident(target.path, &ident)) } - target.target = - format_ident!("{}Base", target.target.to_token_stream().to_string()).to_token_stream(); - let gen = quote! { #crate_path::trait_group::Opaquable::into_opaque({ // We need rust to infer lifetimes and generics, thus we use a wrapper trait use #crate_path::from2::From2; - #target ::from2(#ident) + #target ::from2(#expr) }) }; @@ -133,17 +133,21 @@ pub fn cglue_impl_group(args: TokenStream) -> TokenStream { pub fn group_obj(args: TokenStream) -> TokenStream { let crate_path = cglue_gen::util::crate_path(); - let GenericCastType { ident, mut target } = parse_macro_input!(args as GenericCastType); + let GroupCastType { + mut target, + expr, + ident, + } = parse_macro_input!(args as GroupCastType); - if let Ok(ident) = parse2::(target.target.clone()) { - target.path = ext_abs_remap(prelude_remap_with_ident(target.path, &ident)) + if let Ok(ident) = parse2::(ident) { + target.path = ext_abs_remap(prelude_remap_with_ident(target.path, &ident)); } let gen = quote! { #crate_path::trait_group::Opaquable::into_opaque({ // We need rust to infer lifetimes and generics, thus we use a wrapper trait use #crate_path::from2::From2; - #target ::from2(#ident) + #target ::from2(#expr) }) }; diff --git a/cglue/src/lib.rs b/cglue/src/lib.rs index 4fb781e..fc10102 100644 --- a/cglue/src/lib.rs +++ b/cglue/src/lib.rs @@ -511,16 +511,18 @@ //! CGlueInst: ::core::ops::Deref>, //! CGlueCtx: cglue::trait_group::ContextBounds, //! T: Eq, -//! > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, T> for GA +//! CGlueAssocs: GenGroupVtblAssocs, +//! > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, T, CGlueAssocs> for GA //! where //! Self: TA, -//! &'cglue_a TAVtbl<'cglue_a, GenGroupContainer>: +//! &'cglue_a TAVtbl<'cglue_a, GenGroupContainer, +//! CGlueAssocs::TA>: //! 'cglue_a + Default, //! T: cglue::trait_group::GenericTypeBounds, //! { //! fn fill_table( -//! table: GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, T>, -//! ) -> GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, T> { +//! table: GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, T, CGlueAssocs>, +//! ) -> GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, T, CGlueAssocs> { //! table.enable_ta() //! } //! } @@ -529,11 +531,12 @@ //! 'cglue_a, //! CGlueInst: ::core::ops::Deref>, //! CGlueCtx: cglue::trait_group::ContextBounds, -//! > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, u64> for GA +//! CGlueAssocs: GenGroupVtblAssocs, +//! > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, u64, CGlueAssocs> for GA //! { //! fn fill_table( -//! table: GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, u64>, -//! ) -> GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, u64> { +//! table: GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, u64, CGlueAssocs>, +//! ) -> GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, u64, CGlueAssocs> { //! table //! } //! } diff --git a/cglue/src/tests/generics/associated.rs b/cglue/src/tests/generics/associated.rs index a5ab78b..8469605 100644 --- a/cglue/src/tests/generics/associated.rs +++ b/cglue/src/tests/generics/associated.rs @@ -47,10 +47,6 @@ pub trait ObjResultReturn { #[allow(clippy::result_unit_err)] fn orr_1(&self) -> Result; - // NOTE: cbindgen breaks here whenever there is an explicit () type in params. - // - // You can workaround it by defining a `type Void = ()`, and use `Void` instead of `()`. This - // should be reported to cbindgen folks with MRE. #[no_int_result] #[allow(clippy::result_unit_err)] fn orr_2(&self) -> Result { @@ -132,6 +128,22 @@ impl GenericConsumedGroupReturn for SA { } } +//#[cglue_trait] +// FIXME: cglue currently does not support unwrapped associated types. +pub trait UnwrappedAssociatedReturn { + type ReturnType; + + fn uar_1(self) -> Self::ReturnType; +} + +impl UnwrappedAssociatedReturn for SA { + type ReturnType = SA; + + fn uar_1(self) -> SA { + self + } +} + #[test] fn use_assoc_return() { let sa = SA {}; diff --git a/cglue/src/tests/simple/hrtb.rs b/cglue/src/tests/simple/hrtb.rs index d9cc017..8900520 100644 --- a/cglue/src/tests/simple/hrtb.rs +++ b/cglue/src/tests/simple/hrtb.rs @@ -138,7 +138,7 @@ fn use_plugin_group() { fn use_plugin_group_mut() { let mut sa = SA {}; - let base = PluginInstance::from(&mut sa); + let base = PluginInstance::<_, _, PluginInstanceBaseAssocs>::from(&mut sa); let mut obj = crate::trait_group::Opaquable::into_opaque(base); diff --git a/cglue/src/tests/simple/trait_groups.rs b/cglue/src/tests/simple/trait_groups.rs index d63c211..c6ccb74 100644 --- a/cglue/src/tests/simple/trait_groups.rs +++ b/cglue/src/tests/simple/trait_groups.rs @@ -5,6 +5,7 @@ use cglue_macro::*; cglue_trait_group!(TestGroup, TA, { TB, TC }); cglue_impl_group!(SA, TestGroup, { TC }); + cglue_impl_group!(&'a SA, TestGroup, {}); cglue_impl_group!(SB, super::trait_groups::TestGroup, { TB }); diff --git a/cglue/src/tests/simple/traits.rs b/cglue/src/tests/simple/traits.rs index eb6f988..b62b7f1 100644 --- a/cglue/src/tests/simple/traits.rs +++ b/cglue/src/tests/simple/traits.rs @@ -64,15 +64,15 @@ type ICont = crate::trait_group::CGlueObjContainer = ICont<&'static Implementor, C>; type IMutCont = ICont<&'static mut Implementor, C>; -type WSCont = IMutCont>; -type WOCont = IMutCont>; -type WIRCont = IRefCont>; -type WAIRCont = IRefCont>; -type WINTOCont = IRefCont>; +type WSCont = IMutCont>; +type WOCont = IMutCont>; +type WIRCont = IRefCont>; +type WAIRCont = IRefCont>; +type WINTOCont = IRefCont>; #[test] fn slices_wrapped() { - let vtbl = <&WithSliceVtbl>::default(); + let vtbl = <&WithSliceVtbl>::default(); let _: unsafe extern "C" fn(&mut WSCont, CSliceRef) = vtbl.wslice_1(); let _: unsafe extern "C" fn(&mut WSCont, CSliceRef) = vtbl.wslice_2(); let _: unsafe extern "C" fn(&mut WSCont) -> CSliceRef = vtbl.wslice_3(); @@ -82,53 +82,53 @@ fn slices_wrapped() { #[test] fn npo_option_forwarded() { - let vtbl = <&WithOptionsVtbl>::default(); + let vtbl = <&WithOptionsVtbl>::default(); let _: unsafe extern "C" fn(&WOCont, Option<&usize>) = vtbl.wopt_1(); } #[test] fn non_npo_option_wrapped() { - let vtbl = <&WithOptionsVtbl>::default(); + let vtbl = <&WithOptionsVtbl>::default(); let _: unsafe extern "C" fn(&WOCont, crate::option::COption) = vtbl.wopt_2(); } #[test] fn mixed_options() { - let vtbl = <&WithOptionsVtbl>::default(); + let vtbl = <&WithOptionsVtbl>::default(); let _: unsafe extern "C" fn(&mut WOCont, Option<&u64>, crate::option::COption) = vtbl.wopt_3(); } #[test] fn int_result() { - let vtbl = <&WithIntResultVtbl>::default(); + let vtbl = <&WithIntResultVtbl>::default(); let _: unsafe extern "C" fn(&WIRCont, usize, &mut core::mem::MaybeUninit) -> i32 = vtbl.wint_1(); } #[test] fn no_int_result() { - let vtbl = <&WithIntResultVtbl>::default(); + let vtbl = <&WithIntResultVtbl>::default(); let _: unsafe extern "C" fn(&WIRCont, usize) -> crate::result::CResult = vtbl.wint_2(); } #[test] fn alias_int_result() { - let vtbl = <&WithAliasIntResultVtbl>::default(); + let vtbl = <&WithAliasIntResultVtbl>::default(); let _: unsafe extern "C" fn(&WAIRCont, usize, &mut core::mem::MaybeUninit) -> i32 = vtbl.waint_1(); } #[test] fn alias_no_int_result() { - let vtbl = <&WithAliasIntResultVtbl>::default(); + let vtbl = <&WithAliasIntResultVtbl>::default(); let _: unsafe extern "C" fn(&WAIRCont, usize) -> crate::result::CResult = vtbl.waint_2(); } #[test] fn into_t_wrapped() { - let vtbl = <&WithIntoVtbl>::default(); + let vtbl = <&WithIntoVtbl>::default(); let _: unsafe extern "C" fn(&WINTOCont, usize) = vtbl.winto_1(); } diff --git a/cglue/src/trait_group.rs b/cglue/src/trait_group.rs index 9f7a67b..6f32ff8 100644 --- a/cglue/src/trait_group.rs +++ b/cglue/src/trait_group.rs @@ -1,6 +1,7 @@ //! These are essentially the internals of CGlue. // TODO: split everything up +pub mod specify; use crate::boxed::CBox; #[cfg(feature = "layout_checks")] @@ -142,23 +143,13 @@ unsafe impl<'a, T: Opaquable, F: CGlueBaseVtbl, C: Cont type OpaqueTarget = CGlueTraitObj<'a, T::OpaqueTarget, F::OpaqueVtbl, C, R>; } -pub trait TraitInfo { - type Vtbl<'cglue_a, CGlueC: CGlueObjBase> - where - CGlueC: 'cglue_a; - type Assocs; +pub trait GetVtblBase { + fn get_vtbl_base(&self) -> &V; } -pub trait GetVtbl<'a, Generics, T: TraitInfo>: GetContainer { - fn get_vtbl(&self) -> &T::Vtbl<'a, ::ContType>; -} - -impl<'a, T: Deref, F, Tr: TraitInfo, Generics, C: ContextBounds, R> - GetVtbl<'a, Generics, Tr> - for CGlueTraitObj<'a, T, Tr::Vtbl<'a, CGlueObjContainer>, C, R> -{ - fn get_vtbl(&self) -> &Tr::Vtbl<'a, ::ContType> { - self.vtbl +impl GetVtblBase for CGlueTraitObj<'_, T, V, C, R> { + fn get_vtbl_base(&self) -> &V { + &self.vtbl } } diff --git a/cglue/src/trait_group/specify.rs b/cglue/src/trait_group/specify.rs new file mode 100644 index 0000000..2478855 --- /dev/null +++ b/cglue/src/trait_group/specify.rs @@ -0,0 +1,74 @@ +/// Allows specifying type tuple type parameters. +/// +/// Only allows specifying tuple elements that have void at the given position. +/// +/// This trait is used in trait groups in order to aid specification of associated types. +/// +/// # Example +/// +/// ``` +/// use cglue::trait_group::specify::*; +/// +/// // Create a mixed type +/// type Mixed = ((), u8, String, (), &'static str); +/// type Specified = <>::Type as Specify>::Type; +/// +/// fn take_specified(v: Option<(u64, u8, String, f32, &'static str)>) {} +/// +/// let v: Option = None; +/// take_specified(v); +/// ``` +pub trait Specify { + type Type; +} + +/// Actually implements `Specify` trait. +macro_rules! impl_specify0 { + ($(($pre:ident, $pre_num:ident),)* | ($cur:ident, $cur_num:ident) | $(($next0:ident, $next_num0:ident),)* | ) => { + impl<$($pre,)* $cur, $($next0),*> Specify<$cur_num, $cur> for ($($pre,)* (), $($next0),*) { + type Type = ($($pre,)* $cur, $($next0),*); + } + }; + ($(($pre:ident, $pre_num:ident),)* | ($cur:ident, $cur_num:ident) | $(($next0:ident, $next_num0:ident),)* | ($next1:ident, $next_num1:ident), $(($next2:ident, $next_num2:ident),)*) => { + impl<$($pre,)* $cur, $($next0),*> Specify<$cur_num, $cur> for ($($pre,)* (), $($next0),*) { + type Type = ($($pre,)* $cur, $($next0),*); + } + + impl_specify0!($(($pre, $pre_num),)* | ($cur, $cur_num) | $(($next0, $next_num0),)* ($next1, $next_num1), | $(($next2, $next_num2),)*); + } +} + +/// Dispatches `Specify` trait implementation. +macro_rules! impl_specify { + ($(($pre:ident, $pre_num:ident),)* | ($cur:ident, $cur_num:ident) | $(($next:ident, $next_num:ident),)*) => { + pub struct $cur_num(()); + + impl_specify0!($(($pre, $pre_num),)* | ($cur, $cur_num) | | $(($next, $next_num),)*); + impl_specify!($(($pre, $pre_num),)* ($cur, $cur_num), | | $(($next, $next_num),)*); + }; + ($(($pre:ident, $pre_num:ident),)* | | ) => { }; + ($(($pre:ident, $pre_num:ident),)* | | ($cur:ident, $cur_num:ident), $(($next:ident, $next_num:ident),)*) => { + impl_specify!($(($pre, $pre_num),)* | ($cur, $cur_num) | $(($next, $next_num),)*); + }; +} + +impl_specify! { + | | + (T0, U0), + (T1, U1), + (T2, U2), + (T3, U3), + (T4, U4), + (T5, U5), + (T6, U6), + (T7, U7), + (T8, U8), + (T9, U9), + (T10, U10), + (T11, U11), + (T12, U12), + (T13, U13), + (T14, U14), + (T15, U15), + (T16, U16), +} From b6a95b5d4653bbae64529caa6a873b96738f7d02 Mon Sep 17 00:00:00 2001 From: ko1N Date: Thu, 4 Apr 2024 21:14:03 +0000 Subject: [PATCH 21/41] Changed clone and drop implementations to generate inline static variants --- cglue-bindgen/src/codegen/c.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cglue-bindgen/src/codegen/c.rs b/cglue-bindgen/src/codegen/c.rs index 663dc34..83a33c0 100644 --- a/cglue-bindgen/src/codegen/c.rs +++ b/cglue-bindgen/src/codegen/c.rs @@ -186,13 +186,13 @@ pub fn parse_header(header: &str, config: &Config) -> Result { }, ) { all_wrappers += &format!( - r"static {ty} ctx_{prefix}_clone({ty} *self) {{ + r"static inline {ty} ctx_{prefix}_clone({ty} *self) {{ {ty} ret = *self; {impl_clone} return ret; }} -void ctx_{prefix}_drop({ty} *self) {{ +static inline void ctx_{prefix}_drop({ty} *self) {{ {impl_drop} }} ", @@ -214,7 +214,7 @@ void ctx_{prefix}_drop({ty} *self) {{ )| drop_impl.map(|impl_drop| (ty, ty_prefix.to_lowercase(), impl_drop)), ) { all_wrappers += &format!( - r"void cont_{prefix}_drop({ty} *self) {{ + r"static inline void cont_{prefix}_drop({ty} *self) {{ {impl_drop} }} ", From e4dd02e6b0f52aa6e945054523a18db794d484f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Sat, 13 Apr 2024 13:50:37 +0100 Subject: [PATCH 22/41] Fix compilation on older rustc --- Cargo.lock | 45 +++++++++++++++++++++++++++++++++++------ Cargo.toml | 4 +++- cglue/Cargo.toml | 9 --------- cglue/build.rs | 6 +++++- cglue/src/task/mod.rs | 18 ++++++++++++++--- version-hack/Cargo.toml | 16 +++++++++++++++ version-hack/src/lib.rs | 14 +++++++++++++ 7 files changed, 92 insertions(+), 20 deletions(-) create mode 100644 version-hack/Cargo.toml create mode 100644 version-hack/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index b391858..ef09b89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "abi_stable" version = "0.10.4" @@ -152,18 +150,22 @@ checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6" [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ + "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] [[package]] name = "either" @@ -180,6 +182,22 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "instant" version = "0.1.12" @@ -548,6 +566,21 @@ dependencies = [ "plugin-api", ] +[[package]] +name = "version-hack" +version = "0.1.0" +dependencies = [ + "crossbeam-utils", + "indexmap", + "log", + "memchr", + "once_cell", + "proc-macro2", + "serde", + "thiserror", + "thiserror-impl", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 0a9de25..f38407b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,8 @@ members = [ "cglue-bindgen", "examples/plugin-api", "examples/plugin-lib", - "examples/user-bin" + "examples/user-bin", + "version-hack" ] default-members = [ @@ -15,5 +16,6 @@ default-members = [ "cglue-gen", "cglue-macro", "cglue-bindgen", + "version-hack", ] diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 39039c9..e57b1a8 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -22,15 +22,6 @@ tarc = { version = "0.1", default-features = false } [build-dependencies] rustc_version = "0.4" -# Need to uncomment these before cargo update to keep hashbrown on rust 2018 edition -# indexmap = "~1.8" -# once_cell = "~1.14" -# thiserror = "=1.0.24" -# thiserror-impl = "=1.0.24" -# serde = "=1.0.127" -# proc-macro2 = "=1.0.65" -# memchr = "=2.4.1" -# log = "=0.4.18" [features] default = ["std"] diff --git a/cglue/build.rs b/cglue/build.rs index f9f441b..3294c6a 100644 --- a/cglue/build.rs +++ b/cglue/build.rs @@ -1,7 +1,11 @@ use rustc_version::{version, Version}; fn main() { - if version().unwrap() >= Version::parse("1.65.0").unwrap() { + let version = version().unwrap(); + if version >= Version::parse("1.57.0").unwrap() { + println!("cargo:rustc-cfg=const_panic_on_stable"); + } + if version >= Version::parse("1.65.0").unwrap() { println!("cargo:rustc-cfg=gats_on_stable"); } } diff --git a/cglue/src/task/mod.rs b/cglue/src/task/mod.rs index 4f4dae1..a3cdabe 100644 --- a/cglue/src/task/mod.rs +++ b/cglue/src/task/mod.rs @@ -74,15 +74,24 @@ const _: () = { use core::mem::{size_of, transmute}; if size_of::() != size_of::() { - panic!("Raw waker size mismatch") + #[cfg(not(const_panic_on_stable))] + let _ = "Raw waker size mismatch".as_bytes()[!0]; + #[cfg(const_panic_on_stable)] + panic!("Raw waker size mismatch"); } if size_of::() != size_of::() { - panic!("Raw waker size mismatch") + #[cfg(not(const_panic_on_stable))] + let _ = "Raw waker size mismatch".as_bytes()[!0]; + #[cfg(const_panic_on_stable)] + panic!("Raw waker size mismatch"); } if size_of::() != size_of::() { - panic!("Raw waker vtbl size mismatch") + #[cfg(not(const_panic_on_stable))] + let _ = "Raw waker vtbl size mismatch".as_bytes()[!0]; + #[cfg(const_panic_on_stable)] + panic!("Raw waker vtbl size mismatch"); } macro_rules! expand { @@ -134,6 +143,9 @@ const _: () = { let mut cnt = 0; while cnt < $a.len() { if $a[cnt] != $b[cnt] { + #[cfg(not(const_panic_on_stable))] + let _buffers_not_equal: () = [][cnt]; + #[cfg(const_panic_on_stable)] panic!("{}", BUF[cnt]); } cnt += 1; diff --git a/version-hack/Cargo.toml b/version-hack/Cargo.toml new file mode 100644 index 0000000..410e87d --- /dev/null +++ b/version-hack/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "version-hack" +version = "0.1.0" +edition = "2018" + +# Need to uncomment these before cargo update to keep hashbrown on rust 2018 edition +[dependencies] +indexmap = "~1.7" +once_cell = "~1.14" +thiserror = "=1.0.24" +thiserror-impl = "=1.0.24" +serde = "=1.0.127" +proc-macro2 = "=1.0.65" +memchr = "=2.4.1" +log = "=0.4.18" +crossbeam-utils = "=0.8.16" diff --git a/version-hack/src/lib.rs b/version-hack/src/lib.rs new file mode 100644 index 0000000..7d12d9a --- /dev/null +++ b/version-hack/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} From d5e4c146667fba35b8c6d48aa9771af286d95612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Sat, 13 Apr 2024 14:25:36 +0100 Subject: [PATCH 23/41] Further fixes for assoc type codegen --- cglue-gen/src/trait_groups.rs | 2 +- cglue-gen/src/traits.rs | 86 +++++++++++++++++------------------ 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index 1a0d193..143b9d3 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -480,7 +480,7 @@ impl TraitGroupImpl { #cont_name: #crate_path::trait_group::CGlueObjBase, #gen_where_bounds #vtbl_where_bounds { - fn fill_fwd_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use> { + fn fill_fwd_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs> { table #implemented_tables } } diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index 52c2334..e6a0bdf 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -796,15 +796,11 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { let derive_layouts = quote!(); #[cfg(feature = "layout_checks")] - let cglue_assocs_phantom_decl = - quote!(::abi_stable::marker_type::UnsafeIgnoredType); + let cglue_assocs_phantom_decl = quote!( + ::core::marker::PhantomData<::abi_stable::marker_type::UnsafeIgnoredType> + ); #[cfg(not(feature = "layout_checks"))] let cglue_assocs_phantom_decl = quote!(::core::marker::PhantomData); - #[cfg(feature = "layout_checks")] - let cglue_assocs_phantom_new = - quote!(::abi_stable::marker_type::UnsafeIgnoredType::::NEW); - #[cfg(not(feature = "layout_checks"))] - let cglue_assocs_phantom_new = quote!(::core::marker::PhantomData); // Function definitions in the vtable let mut vtbl_func_defintions = TokenStream::new(); @@ -1192,7 +1188,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { &#vtbl_ident { #vtbl_default_funcs _lt_cglue_a: ::core::marker::PhantomData, - _assocs: #cglue_assocs_phantom_new, + _assocs: ::core::marker::PhantomData, } } } @@ -1238,40 +1234,40 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use> + #trait_assocs_ident<#gen_use Assocs = CGlueAssocs> {} #[doc = #base_box_trait_obj_doc] - pub type #base_box_trait_obj_ident<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> - = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #trg_path::NoContext, #gen_use CGlueAssocs>; + pub type #base_box_trait_obj_ident<'cglue_a, CGlueT, #gen_use> + = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #trg_path::NoContext, #gen_use>; #[doc = #base_ctx_trait_obj_doc] - pub type #base_ctx_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use CGlueAssocs>; + pub type #base_ctx_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use> + = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use>; #[doc = #base_arc_trait_obj_doc] - pub type #base_arc_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use CGlueAssocs = #assocs_base_type> - = #base_ctx_trait_obj_ident<'cglue_a, CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; + pub type #base_arc_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use> + = #base_ctx_trait_obj_ident<'cglue_a, CGlueT, #crate_path::arc::CArc, #gen_use>; #[doc = #base_mut_trait_obj_doc] - pub type #base_mut_trait_obj_ident<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> - = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #trg_path::NoContext, #gen_use CGlueAssocs>; + pub type #base_mut_trait_obj_ident<'cglue_a, CGlueT, #gen_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #trg_path::NoContext, #gen_use>; #[doc = #base_ctx_mut_trait_obj_doc] - pub type #base_ctx_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, CGlueCtx, #gen_use CGlueAssocs>; + pub type #base_ctx_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, CGlueCtx, #gen_use>; #[doc = #base_arc_mut_trait_obj_doc] - pub type #base_arc_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use CGlueAssocs = #assocs_base_type> - = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; + pub type #base_arc_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #crate_path::arc::CArc, #gen_use>; #[doc = #base_ref_trait_obj_doc] - pub type #base_ref_trait_obj_ident<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> - = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #trg_path::NoContext, #gen_use CGlueAssocs>; + pub type #base_ref_trait_obj_ident<'cglue_a, CGlueT, #gen_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #trg_path::NoContext, #gen_use>; #[doc = #base_ctx_ref_trait_obj_doc] - pub type #base_ctx_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, CGlueCtx, #gen_use CGlueAssocs>; + pub type #base_ctx_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, CGlueCtx, #gen_use>; #[doc = #base_arc_ref_trait_obj_doc] - pub type #base_arc_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use CGlueAssocs = #assocs_base_type> - = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; + pub type #base_arc_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #crate_path::arc::CArc, #gen_use>; #[doc = #base_trait_obj_doc] pub type #base_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> @@ -1289,43 +1285,43 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { >; pub type #base_baseassocs_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use> - = #base_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; + = #base_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use #assocs_base_type>; #[doc = #opaque_box_trait_obj_doc] - pub type #opaque_box_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_box_trait_obj_ident<'cglue_a, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_box_trait_obj_ident<'cglue_a, #gen_use> + = #base_box_trait_obj_ident<'cglue_a, #c_void, #gen_use>; #[doc = #opaque_ctx_trait_obj_doc] - pub type #opaque_ctx_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #base_ctx_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; + pub type #opaque_ctx_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use> + = #base_ctx_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use>; #[doc = #opaque_arc_trait_obj_doc] - pub type #opaque_arc_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_arc_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_arc_trait_obj_ident<'cglue_a, #gen_use> + = #base_arc_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use>; #[doc = #opaque_mut_trait_obj_doc] - pub type #opaque_mut_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_mut_trait_obj_ident<'cglue_a, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_mut_trait_obj_ident<'cglue_a, #gen_use> + = #base_mut_trait_obj_ident<'cglue_a, #c_void, #gen_use>; #[doc = #opaque_ctx_mut_trait_obj_doc] - pub type #opaque_ctx_mut_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #base_ctx_mut_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; + pub type #opaque_ctx_mut_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use> + = #base_ctx_mut_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use>; #[doc = #opaque_arc_mut_trait_obj_doc] - pub type #opaque_arc_mut_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_arc_mut_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_arc_mut_trait_obj_ident<'cglue_a, #gen_use> + = #base_arc_mut_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use>; #[doc = #opaque_ref_trait_obj_doc] - pub type #opaque_ref_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_ref_trait_obj_ident<'cglue_a, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_ref_trait_obj_ident<'cglue_a, #gen_use> + = #base_ref_trait_obj_ident<'cglue_a, #c_void, #gen_use>; #[doc = #opaque_ctx_ref_trait_obj_doc] - pub type #opaque_ctx_ref_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #base_ctx_ref_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; + pub type #opaque_ctx_ref_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use> + = #base_ctx_ref_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use>; #[doc = #opaque_arc_ref_trait_obj_doc] - pub type #opaque_arc_ref_trait_obj_ident<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_arc_ref_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_arc_ref_trait_obj_ident<'cglue_a, #gen_use> + = #base_arc_ref_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use>; /* Internal wrapper functions. */ From 5d26c373bd49e935dc65b4434bb6593e2109b8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Thu, 20 Jun 2024 23:09:26 +0100 Subject: [PATCH 24/41] Assoc type codegen rework --- cglue-gen/src/forward.rs | 4 +- cglue-gen/src/func.rs | 8 +- cglue-gen/src/generics.rs | 8 +- cglue-gen/src/trait_groups.rs | 494 ++++++++++++------------- cglue-gen/src/traits.rs | 363 +++++++++--------- cglue/src/lib.rs | 18 +- cglue/src/tests/generics/associated.rs | 33 +- cglue/src/tests/simple/hrtb.rs | 2 +- cglue/src/tests/simple/traits.rs | 28 +- 9 files changed, 493 insertions(+), 465 deletions(-) diff --git a/cglue-gen/src/forward.rs b/cglue-gen/src/forward.rs index 93cf27a..cefe31a 100644 --- a/cglue-gen/src/forward.rs +++ b/cglue-gen/src/forward.rs @@ -32,11 +32,11 @@ pub fn gen_forward(tr: ItemTrait, ext_path: Option) -> TokenStream let mut wrapped_types = TokenStream::new(); - let (funcs, generics, _) = super::traits::parse_trait( + let (funcs, generics, _, _) = super::traits::parse_trait( &tr, &crate_path, false, - |(ty_ident, _, ty_where_clause, _), _, _, _, _, _| { + |(ty_ident, _, ty_where_clause, _), _, _, _, _, _, _| { if let Some(ident) = ty_ident { wrapped_types.extend(quote!(type #ident = CGlueT::#ident #ty_where_clause;)); } diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index 65a0f8c..9c0faad 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -918,8 +918,8 @@ impl ParsedFunc { tokens: &mut TokenStream, trg_path: &TokenStream, ret_tmp: &TokenStream, - vtbl_assocs_ident: &Ident, - trait_assocs_ident: &Ident, + assocs: &ParsedGenerics, + assoc_equality: &TokenStream, ) -> Option<&TokenStream> { if !self.is_wrapped() { return None; @@ -956,6 +956,8 @@ impl ParsedFunc { .. } = &self.generics; + let assoc_declare = &assocs.gen_declare; + let ParsedGenerics { life_declare: sig_life_declare, .. @@ -1035,7 +1037,7 @@ impl ParsedFunc { let ctx_bound = super::traits::ctx_bound(); let gen = quote! { - #safety extern "C" fn #fnname<#sig_life_declare CGlueC: #container_bound, CGlueCtx: #ctx_bound, CGlueAssocs: #vtbl_assocs_ident<#gen_use>, #gen_declare>(#args #c_ret_params) #c_out where #gen_where_bounds #c_where_bounds #cglue_c_into_inner CGlueC::ObjType: for<'cglue_b> #trname<#tmp_lifetime #gen_use> + #trait_assocs_ident<#gen_use Assocs = CGlueAssocs>, { + #safety extern "C" fn #fnname<#sig_life_declare CGlueC: #container_bound, CGlueCtx: #ctx_bound, #gen_declare #assoc_declare>(#args #c_ret_params) #c_out where #gen_where_bounds #c_where_bounds #cglue_c_into_inner CGlueC::ObjType: for<'cglue_b> #trname<#tmp_lifetime #gen_use #assoc_equality>, { #c_pre_call let ret = #inner_impl; #c_ret diff --git a/cglue-gen/src/generics.rs b/cglue-gen/src/generics.rs index 4b8d33a..2456bb6 100644 --- a/cglue-gen/src/generics.rs +++ b/cglue-gen/src/generics.rs @@ -692,16 +692,12 @@ impl GenericType { generic_types.insert(0, infer.clone()); generic_types.insert(0, infer); - let base_assocs_ident = format_ident!("{}BaseAssocs", target.to_string()); - generic_types.push(parse_quote!(#path #base_assocs_ident)); - if !generic_types.trailing_punct() { generic_types.push_punct(Default::default()); } - target = format_ident!("{}Base", target.to_string()).to_token_stream(); - } else { - target = format_ident!("{}BaseBaseAssocs", target.to_string()).to_token_stream(); } + target = format_ident!("{}Base", target.to_string()).to_token_stream(); + quote!(::) } else { quote!() diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index 143b9d3..5333438 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -4,8 +4,9 @@ use crate::util::*; use itertools::*; use proc_macro2::TokenStream; use quote::*; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; use syn::*; pub struct AliasPath { @@ -49,14 +50,15 @@ pub struct TraitInfo { raw_ident: Ident, name_ident: Ident, generics: ParsedGenerics, + assocs: ParsedGenerics, vtbl_name: Ident, - assocs_typename: Ident, ret_tmp_typename: Ident, ret_tmp_name: Ident, enable_vtbl_name: Ident, lc_name: Ident, vtbl_typename: Ident, vtbl_get_ident: Ident, + assoc_bind_ident: Ident, } impl PartialEq for TraitInfo { @@ -81,7 +83,7 @@ impl PartialOrd for TraitInfo { impl From for TraitInfo { fn from(in_path: AliasPath) -> Self { - let (path, raw_ident, gens) = + let (path, raw_ident, mut gens) = split_path_ident(&in_path.path).expect("Failed to split path by idents"); let mut name_ident = raw_ident.clone(); @@ -93,12 +95,30 @@ impl From for TraitInfo { name_ident = alias; } + let mut assocs_map = BTreeMap::new(); + + if let Some(gens) = &mut gens { + while let Some(GenericArgument::Binding(_)) = gens.last() { + let v = gens.pop().unwrap().into_value(); + if let GenericArgument::Binding(v) = v { + assocs_map.insert(v.ident, v.ty); + } + } + } + + let mut assocs = Punctuated::new(); + + for (_, ty) in assocs_map { + assocs.push_value(GenericArgument::Type(ty.clone())); + assocs.push_punct(Default::default()); + } + Self { vtbl_name: format_ident!("vtbl_{}", lc_ident), lc_name: format_ident!("{}", lc_ident), vtbl_typename: format_ident!("{}Vtbl", raw_ident), vtbl_get_ident: format_ident!("{}VtblGet", raw_ident), - assocs_typename: format_ident!("{}VtblAssocs", raw_ident), + assoc_bind_ident: format_ident!("{}AssocBind", raw_ident), ret_tmp_typename: format_ident!("{}RetTmp", raw_ident), ret_tmp_name: format_ident!("ret_tmp_{}", lc_ident), enable_vtbl_name: format_ident!("enable_{}", lc_ident), @@ -106,6 +126,7 @@ impl From for TraitInfo { raw_ident, name_ident, generics: ParsedGenerics::from(gens.as_ref()), + assocs: ParsedGenerics::from(&assocs), } } } @@ -115,7 +136,6 @@ impl From for TraitInfo { pub struct TraitGroup { name: Ident, cont_name: Ident, - assocs_trait: Ident, generics: ParsedGenerics, mandatory_vtbl: Vec, optional_vtbl: Vec, @@ -250,12 +270,10 @@ impl Parse for TraitGroup { }; let cont_name = format_ident!("{}Container", name); - let assocs_trait = format_ident!("{}VtblAssocs", name); Ok(Self { name, cont_name, - assocs_trait, generics, mandatory_vtbl, optional_vtbl, @@ -432,7 +450,6 @@ impl TraitGroupImpl { let filler_trait = format_ident!("{}VtableFiller", group); let vtable_type = format_ident!("{}Vtables", group); let cont_name = format_ident!("{}Container", group); - let assocs_trait = format_ident!("{}VtblAssocs", group); let implemented_tables = TraitGroup::enable_opt_vtbls(self.implemented_vtbl.iter()); let vtbl_where_bounds = TraitGroup::vtbl_where_bounds( @@ -446,10 +463,10 @@ impl TraitGroupImpl { ); let gen = quote! { - impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #group_path #assocs_trait<#gen_use>> - #group_path #filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs> for #ty + impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + #group_path #filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use> for #ty where #gen_where_bounds #vtbl_where_bounds { - fn fill_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs> { + fn fill_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use> { table #implemented_tables } } @@ -474,13 +491,13 @@ impl TraitGroupImpl { quote! { #gen - impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #group_path #assocs_trait<#gen_use>> - #group_path #fwd_filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs> for #ty + impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + #group_path #fwd_filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use> for #ty where - #cont_name: #crate_path::trait_group::CGlueObjBase, + #cont_name: #crate_path::trait_group::CGlueObjBase, #gen_where_bounds #vtbl_where_bounds { - fn fill_fwd_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use CGlueAssocs> { + fn fill_fwd_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use> { table #implemented_tables } } @@ -632,7 +649,6 @@ impl TraitGroup { let name = &self.name; let cont_name = &self.cont_name; - let assocs_trait = &self.assocs_trait; let ParsedGenerics { gen_declare, @@ -676,8 +692,7 @@ impl TraitGroup { let full_opt_vtbl_list = self.vtbl_list(self.optional_vtbl.iter()); let mandatory_as_ref_impls = self.mandatory_as_ref_impls(&trg_path); - let get_container_impl = - self.get_container_impl(name, &assocs_trait, &trg_path, &self.generics); + let get_container_impl = self.get_container_impl(name, &trg_path, &self.generics); let mandatory_internal_trait_impls = self.internal_trait_impls( name, @@ -727,8 +742,7 @@ impl TraitGroup { let mut enable_funcs_vtbl = TokenStream::new(); #[cfg(feature = "layout_checks")] - let derive_layouts = - quote!(#[derive(::abi_stable::StableAbi)] #[sabi(unsafe_unconstrained(CGlueAssocs))]); + let derive_layouts = quote!(#[derive(::abi_stable::StableAbi)]); #[cfg(not(feature = "layout_checks"))] let derive_layouts = quote!(); @@ -745,9 +759,11 @@ impl TraitGroup { enable_vtbl_name, vtbl_typename, vtbl_name, - name_ident, path, generics: ParsedGenerics { gen_use, .. }, + assocs: ParsedGenerics { + gen_use: assoc_use, .. + }, .. } in &self.optional_vtbl { @@ -757,7 +773,7 @@ impl TraitGroup { ] { funcs.extend(quote! { pub fn #enable_vtbl_name (self) -> Self - where &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>: Default { + where &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use #assoc_use>: Default { Self { #vtbl_name: Some(Default::default()),#fill_rest } @@ -774,9 +790,6 @@ impl TraitGroup { let impl_traits = self.impl_traits(self.mandatory_vtbl.iter().chain(self.optional_vtbl.iter())); - let (assoc_gen_defs, assoc_gen_use, assoc_decls, assoc_defs, assocs_num_void) = - self.trait_assocs(self.mandatory_vtbl.iter().chain(self.optional_vtbl.iter())); - let base_doc = format!( " Trait group potentially implementing `{}` traits.", impl_traits @@ -784,9 +797,7 @@ impl TraitGroup { let trback_doc = format!("be transformed back into `{}` without losing data.", name); let new_doc = format!(" Create new instance of {}.", name); - let assocs_base_type = format_ident!("{}BaseAssocs", name); let base_name = format_ident!("{}Base", name); - let base_baseassocs_name = format_ident!("{}BaseBaseAssocs", name); let base_name_ref = format_ident!("{}BaseRef", name); let base_name_ctx_ref = format_ident!("{}BaseCtxRef", name); let base_name_arc_ref = format_ident!("{}BaseArcRef", name); @@ -834,8 +845,7 @@ impl TraitGroup { let mixed_opt_vtbl_unwrap = self.mixed_opt_vtbl_unwrap_list(traits.iter().copied()); - let get_container_impl = - self.get_container_impl(&opt_name, &assocs_trait, &trg_path, &self.generics); + let get_container_impl = self.get_container_impl(&opt_name, &trg_path, &self.generics); let opt_as_ref_impls = self.as_ref_impls( &opt_name, @@ -852,7 +862,7 @@ impl TraitGroup { ); let get_container_impl_final = - self.get_container_impl(&opt_final_name, &assocs_trait, &trg_path, &self.generics); + self.get_container_impl(&opt_final_name, &trg_path, &self.generics); let opt_final_as_ref_impls = self.as_ref_impls( &opt_final_name, @@ -902,14 +912,14 @@ impl TraitGroup { #[doc = #opt_final_doc2] #[repr(C)] #derive_layouts - pub struct #opt_final_name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> + pub struct #opt_final_name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds_base { #mandatory_vtbl_defs #opt_vtbl_defs - container: #cont_name, + container: #cont_name, } #get_container_impl_final @@ -925,39 +935,39 @@ impl TraitGroup { #[doc = #opt_doc2] #[repr(C)] #derive_layouts - pub struct #opt_name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> + pub struct #opt_name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds_base { #mandatory_vtbl_defs #opt_mixed_vtbl_defs - container: #cont_name, + container: #cont_name, } - unsafe impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> - #trg_path::Opaquable for #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + unsafe impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> + #trg_path::Opaquable for #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - type OpaqueTarget = #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>; + type OpaqueTarget = #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> - From<#opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> + From<#opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - fn from(input: #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> Self { + fn from(input: #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> Self { #trg_path::Opaquable::into_opaque(input) } } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where Self: #trg_path::Opaquable, - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { /// Cast back into the original group @@ -1007,7 +1017,7 @@ impl TraitGroup { /// #[doc = #func_check_doc2] pub fn #func_name_check(&self) -> bool - where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>: 'cglue_a + #impl_traits + where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>: 'cglue_a + #impl_traits { self.#func_name_ref().is_some() } @@ -1016,7 +1026,7 @@ impl TraitGroup { /// #[doc = #func_final_doc2] pub fn #func_name_final(self) -> ::core::option::Option - where #opt_final_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>: 'cglue_a + #impl_traits + where #opt_final_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>: 'cglue_a + #impl_traits { let #name { container, @@ -1035,8 +1045,8 @@ impl TraitGroup { #[doc = #func_doc1] /// #[doc = #func_doc2] - pub fn #func_name(self) -> ::core::option::Option<#opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>> - where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>: 'cglue_a + #impl_traits + pub fn #func_name(self) -> ::core::option::Option<#opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>> + where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>: 'cglue_a + #impl_traits { let #name { container, @@ -1053,7 +1063,7 @@ impl TraitGroup { #[doc = #func_mut_doc1] pub fn #func_name_mut<'b>(&'b mut self) -> ::core::option::Option<&'b mut (impl 'cglue_a + #impl_traits)> - where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>: 'cglue_a + #impl_traits + where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>: 'cglue_a + #impl_traits { let #name { container, @@ -1070,13 +1080,13 @@ impl TraitGroup { // optional reference validity was checked beforehand unsafe { - (self as *mut Self as *mut #opt_name).as_mut() + (self as *mut Self as *mut #opt_name).as_mut() } } #[doc = #func_ref_doc1] pub fn #func_name_ref<'b>(&'b self) -> ::core::option::Option<&'b (impl 'cglue_a + #impl_traits)> - where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>: 'cglue_a + #impl_traits + where #opt_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>: 'cglue_a + #impl_traits { let #name { #mand_vtbl_list @@ -1092,7 +1102,7 @@ impl TraitGroup { // optional reference validity was checked beforehand unsafe { - (self as *const Self as *const #opt_name).as_ref() + (self as *const Self as *const #opt_name).as_ref() } } }); @@ -1101,23 +1111,23 @@ impl TraitGroup { #[cfg(not(feature = "unstable"))] let (extra_filler_traits, filler_trait_imports) = if self.extra_filler_traits { let traits = quote! { - pub trait #fwd_filler_trait<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>>: 'cglue_a + Sized + pub trait #fwd_filler_trait<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare>: 'cglue_a + Sized where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - fn fill_fwd_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>; + fn fill_fwd_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; } - impl<'cglue_a, CGlueInst: ::core::ops::Deref>, CGlueT, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> - #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst: ::core::ops::Deref>, CGlueT, CGlueCtx: #ctx_bound, #gen_declare> + #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use> for #crate_path::forward::Fwd<&'cglue_a mut CGlueT> where - #cont_name: #trg_path::CGlueObjBase, - CGlueT: #fwd_filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>, + #cont_name: #trg_path::CGlueObjBase, + CGlueT: #fwd_filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use>, #gen_where_bounds { - fn fill_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> { + fn fill_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use> { CGlueT::fill_fwd_table(table) } } @@ -1143,7 +1153,8 @@ impl TraitGroup { #[cfg(feature = "unstable")] let cglue_inst_filler_trait_bound = quote!(); #[cfg(not(feature = "unstable"))] - let cglue_inst_filler_trait_bound = quote!(CGlueInst::Target: #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>,); + let cglue_inst_filler_trait_bound = + quote!(CGlueInst::Target: #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use>,); #[cfg(feature = "unstable")] let create_vtbl = quote!(Default::default()); #[cfg(not(feature = "unstable"))] @@ -1153,12 +1164,12 @@ impl TraitGroup { let filler_trait_impl = quote!(); #[cfg(not(feature = "unstable"))] let filler_trait_impl = quote! { - pub trait #filler_trait<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>>: Sized + pub trait #filler_trait<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare>: Sized where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - fn fill_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>; + fn fill_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; } #extra_filler_traits @@ -1175,11 +1186,8 @@ impl TraitGroup { pub use cglue_internal::{ #name, #vtable_type, - #assocs_trait, - #assocs_base_type, #filler_trait_imports #base_name, - #base_baseassocs_name, #base_name_ref, #base_name_ctx_ref, #base_name_arc_ref, @@ -1223,32 +1231,21 @@ impl TraitGroup { /// perform any memory transformations either. They are the safest to use, because /// there is no risk of accidentally consuming the whole object. #derive_layouts - pub struct #name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> + pub struct #name<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds_base { #mandatory_vtbl_defs #optional_vtbl_defs - container: #cont_name, - } - - /// Describes associated types of a trait group. - pub trait #assocs_trait<#gen_use> { - #assoc_decls - } - - pub type #assocs_base_type = (#assocs_num_void); - - impl<#gen_use #assoc_gen_defs> #assocs_trait<#gen_use> for (#assoc_gen_use) { - #assoc_defs + container: #cont_name, } #get_container_impl #[repr(C)] #derive_layouts - pub struct #cont_name> + pub struct #cont_name { instance: CGlueInst, context: CGlueCtx, @@ -1257,27 +1254,27 @@ impl TraitGroup { #cglue_obj_impl - unsafe impl> - #trg_path::Opaquable for #cont_name + unsafe impl + #trg_path::Opaquable for #cont_name { - type OpaqueTarget = #cont_name; + type OpaqueTarget = #cont_name; } #[repr(C)] #derive_layouts - pub struct #vtable_type<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> + pub struct #vtable_type<'cglue_a, CGlueInst: 'cglue_a, CGlueCtx: #ctx_bound, #gen_declare> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds_base { #mandatory_vtbl_defs #optional_vtbl_defs } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> Default - for #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> Default + for #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #vtbl_where_bounds #gen_where_bounds { fn default() -> Self { @@ -1288,17 +1285,17 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { #enable_funcs } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use> + 'cglue_a> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { #enable_funcs_vtbl @@ -1306,69 +1303,66 @@ impl TraitGroup { #filler_trait_impl - pub type #base_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs>; + pub type #base_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> + = #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; - pub type #base_baseassocs_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> - = #base_name<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; + pub type #base_name_boxed<'cglue_a, CGlueT, #gen_use> + = #base_name_ctx_box<'cglue_a, CGlueT, #crate_path::trait_group::NoContext, #gen_use>; - pub type #base_name_boxed<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_ctx_box<'cglue_a, CGlueT, #crate_path::trait_group::NoContext, #gen_use CGlueAssocs>; + pub type #base_name_ctx_box<'cglue_a, CGlueT, CGlueCtx, #gen_use> + = #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use>; - pub type #base_name_ctx_box<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use CGlueAssocs>; + pub type #base_name_arc_box<'cglue_a, CGlueT, CGlueArcTy, #gen_use> + = #base_name_ctx_box<'cglue_a, CGlueT, #crate_path::arc::CArc, #gen_use>; - pub type #base_name_arc_box<'cglue_a, CGlueT, CGlueArcTy, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_ctx_box<'cglue_a, CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; + pub type #base_name_ref<'cglue_a, CGlueT, #gen_use> + = #name<'cglue_a, &'cglue_a CGlueT, #crate_path::trait_group::NoContext, #gen_use>; - pub type #base_name_ref<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> - = #name<'cglue_a, &'cglue_a CGlueT, #crate_path::trait_group::NoContext, #gen_use CGlueAssocs>; + pub type #base_name_ctx_ref<'cglue_a, CGlueT, CGlueCtx, #gen_use> + = #name<'cglue_a, &'cglue_a CGlueT, CGlueCtx, #gen_use>; - pub type #base_name_ctx_ref<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #name<'cglue_a, &'cglue_a CGlueT, CGlueCtx, #gen_use CGlueAssocs>; + pub type #base_name_arc_ref<'cglue_a, CGlueT, CGlueArcTy, #gen_use> + = #name<'cglue_a, &'cglue_a CGlueT, #crate_path::arc::CArc, #gen_use>; - pub type #base_name_arc_ref<'cglue_a, CGlueT, CGlueArcTy, #gen_use CGlueAssocs = #assocs_base_type> - = #name<'cglue_a, &'cglue_a CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; + pub type #base_name_mut<'cglue_a, CGlueT, #gen_use> + = #name<'cglue_a, &'cglue_a mut CGlueT, #crate_path::trait_group::NoContext, #gen_use>; - pub type #base_name_mut<'cglue_a, CGlueT, #gen_use CGlueAssocs = #assocs_base_type> - = #name<'cglue_a, &'cglue_a mut CGlueT, #crate_path::trait_group::NoContext, #gen_use CGlueAssocs>; + pub type #base_name_ctx_mut<'cglue_a, CGlueT, CGlueCtx, #gen_use> + = #name<'cglue_a, &'cglue_a mut CGlueT, CGlueCtx, #gen_use>; - pub type #base_name_ctx_mut<'cglue_a, CGlueT, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #name<'cglue_a, &'cglue_a mut CGlueT, CGlueCtx, #gen_use CGlueAssocs>; + pub type #base_name_arc_mut<'cglue_a, CGlueT, CGlueArcTy, #gen_use> + = #name<'cglue_a, &'cglue_a mut CGlueT, #crate_path::arc::CArc, #gen_use>; - pub type #base_name_arc_mut<'cglue_a, CGlueT, CGlueArcTy, #gen_use CGlueAssocs = #assocs_base_type> - = #name<'cglue_a, &'cglue_a mut CGlueT, #crate_path::arc::CArc, #gen_use CGlueAssocs>; + pub type #opaque_name_boxed<'cglue_a, #gen_use> + = #base_name_boxed<'cglue_a, #c_void, #gen_use>; - pub type #opaque_name_boxed<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_boxed<'cglue_a, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_name_ref<'cglue_a, #gen_use> + = #base_name_ref<'cglue_a, #c_void, #gen_use>; - pub type #opaque_name_ref<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_ref<'cglue_a, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_name_ctx_ref<'cglue_a, CGlueCtx, #gen_use> + = #base_name_ctx_ref<'cglue_a, #c_void, CGlueCtx, #gen_use>; - pub type #opaque_name_ctx_ref<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_ctx_ref<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; + pub type #opaque_name_arc_ref<'cglue_a, #gen_use> + = #base_name_arc_ref<'cglue_a, #c_void, #c_void, #gen_use>; - pub type #opaque_name_arc_ref<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_arc_ref<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_name_mut<'cglue_a, #gen_use> + = #base_name_mut<'cglue_a, #c_void, #gen_use>; - pub type #opaque_name_mut<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_mut<'cglue_a, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_name_ctx_mut<'cglue_a, CGlueCtx, #gen_use> + = #base_name_ctx_mut<'cglue_a, #c_void, CGlueCtx, #gen_use>; - pub type #opaque_name_ctx_mut<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_ctx_mut<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; + pub type #opaque_name_arc_mut<'cglue_a, #gen_use> + = #base_name_arc_mut<'cglue_a, #c_void, #c_void, #gen_use>; - pub type #opaque_name_arc_mut<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_arc_mut<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; + pub type #opaque_name_ctx_box<'cglue_a, CGlueCtx, #gen_use> + = #base_name_ctx_box<'cglue_a, #c_void, CGlueCtx, #gen_use>; - pub type #opaque_name_ctx_box<'cglue_a, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_ctx_box<'cglue_a, #c_void, CGlueCtx, #gen_use CGlueAssocs>; + pub type #opaque_name_arc_box<'cglue_a, #gen_use> + = #base_name_arc_box<'cglue_a, #c_void, #c_void, #gen_use>; - pub type #opaque_name_arc_box<'cglue_a, #gen_use CGlueAssocs = #assocs_base_type> - = #base_name_arc_box<'cglue_a, #c_void, #c_void, #gen_use CGlueAssocs>; - - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> - From<(CGlueInst, CGlueCtx)> for #cont_name + impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + From<(CGlueInst, CGlueCtx)> for #cont_name where Self: #trg_path::CGlueObjBase { @@ -1382,8 +1376,8 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> - From<(CGlueT, CGlueCtx)> for #cont_name<#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueT, CGlueCtx: #ctx_bound, #gen_declare> + From<(CGlueT, CGlueCtx)> for #cont_name<#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use> where Self: #trg_path::CGlueObjBase { @@ -1392,14 +1386,14 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> - From<#cont_name> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + From<#cont_name> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #cglue_inst_filler_trait_bound #vtbl_where_bounds #gen_where_bounds { - fn from(container: #cont_name) -> Self { + fn from(container: #cont_name) -> Self { let vtbl = #create_vtbl; let #vtable_type { @@ -1415,11 +1409,11 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> - From<(CGlueInst, CGlueCtx)> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + From<(CGlueInst, CGlueCtx)> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - Self: From<#cont_name>, - #cont_name: #trg_path::CGlueObjBase, + Self: From<#cont_name>, + #cont_name: #trg_path::CGlueObjBase, #vtbl_where_bounds #gen_where_bounds { fn from((instance, context): (CGlueInst, CGlueCtx)) -> Self { @@ -1427,8 +1421,8 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> - From for #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueT, #gen_declare> + From for #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use> where Self: From<(#crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext)>, #vtbl_where_bounds_boxed #gen_where_bounds @@ -1438,11 +1432,11 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: core::ops::Deref, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> From - for #name<'cglue_a, CGlueInst, #trg_path::NoContext, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst: core::ops::Deref, #gen_declare> From + for #name<'cglue_a, CGlueInst, #trg_path::NoContext, #gen_use> where Self: From<(CGlueInst, #crate_path::trait_group::NoContext)>, - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #vtbl_where_bounds_noctx #gen_where_bounds { fn from(instance: CGlueInst) -> Self { @@ -1450,11 +1444,11 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> From<(CGlueT, CGlueCtx)> - for #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueT, CGlueCtx: #ctx_bound, #gen_declare> From<(CGlueT, CGlueCtx)> + for #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use> where Self: From<(#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx)>, - #cont_name<#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use CGlueAssocs>: #trg_path::CGlueObjBase, + #cont_name<#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use>: #trg_path::CGlueObjBase, #vtbl_where_bounds_ctxboxed #gen_where_bounds { fn from((this, context): (CGlueT, CGlueCtx)) -> Self { @@ -1462,10 +1456,10 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> - #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_declare> + #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #vtbl_where_bounds #gen_where_bounds { #[doc = #new_doc] @@ -1485,7 +1479,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueT, #gen_declare> #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use> where #gen_where_bounds { #[doc = #new_doc] @@ -1501,26 +1495,25 @@ impl TraitGroup { /// Convert into opaque object. /// /// This is the prerequisite for using underlying trait implementations. - unsafe impl<'cglue_a, CGlueInst: #trg_path::Opaquable, CGlueCtx: #ctx_bound, #gen_declare CGlueAssocs: #assocs_trait<#gen_use>> - #trg_path::Opaquable for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + unsafe impl<'cglue_a, CGlueInst: #trg_path::Opaquable, CGlueCtx: #ctx_bound, #gen_declare> + #trg_path::Opaquable for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #trg_path::CGlueObjBase, - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - type OpaqueTarget = #name<'cglue_a, CGlueInst::OpaqueTarget, CGlueCtx, #gen_use CGlueAssocs>; + type OpaqueTarget = #name<'cglue_a, CGlueInst::OpaqueTarget, CGlueCtx, #gen_use>; } impl< 'cglue_a, CGlueInst, //: ::core::ops::Deref CGlueCtx: #ctx_bound, - CGlueAssocs: #assocs_trait<#gen_use>, #gen_declare > - #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { #trait_funcs @@ -1546,7 +1539,6 @@ impl TraitGroup { let mut ret = TokenStream::new(); let cont_name = &self.cont_name; - let assocs_trait = &self.assocs_trait; let ctx_bound = super::traits::ctx_bound(); @@ -1569,7 +1561,7 @@ impl TraitGroup { let ext_name = format_ident!("{}Ext", raw_ident); - let (funcs, _, _) = super::traits::parse_trait( + let (funcs, _, _, _) = super::traits::parse_trait( tr_info, crate_path, false, @@ -1581,10 +1573,10 @@ impl TraitGroup { } let gen = quote! { - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_use CGlueAssocs: #assocs_trait<#gen_use>> - #path #raw_ident <#tr_life_use #tr_gen_use> for #self_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #gen_use> + #path #raw_ident <#tr_life_use #tr_gen_use> for #self_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #crate_path::trait_group::CGlueObjBase, + #cont_name: #crate_path::trait_group::CGlueObjBase, Self: #ext_path #ext_name<#tr_life_use #tr_gen_use> { #impls @@ -1617,13 +1609,15 @@ impl TraitGroup { vtbl_name, path, vtbl_typename, - name_ident, generics: ParsedGenerics { gen_use, .. }, + assocs: ParsedGenerics { + gen_use: assoc_use, .. + }, .. } in iter { ret.extend( - quote!(#vtbl_name: &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>, ), + quote!(#vtbl_name: &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use #assoc_use>, ), ); } @@ -1667,51 +1661,6 @@ impl TraitGroup { ret } - /// Get tokens for declaring and using associated types - /// - /// # Arguments - /// - /// * `traits` - traits to generate for. - fn trait_assocs<'a>( - &'a self, - traits: impl Iterator, - ) -> ( - TokenStream, - TokenStream, - TokenStream, - TokenStream, - TokenStream, - ) { - let mut assoc_gen_defs = TokenStream::new(); - let mut assoc_gen_use = TokenStream::new(); - let mut assoc_decls = TokenStream::new(); - let mut assoc_defs = TokenStream::new(); - let mut assocs_num_void = TokenStream::new(); - - for TraitInfo { - path, - assocs_typename, - name_ident, - generics: ParsedGenerics { gen_use, .. }, - .. - } in traits - { - assoc_gen_defs.extend(quote!(#name_ident: #path #assocs_typename<#gen_use>,)); - assoc_gen_use.extend(quote!(#name_ident,)); - assoc_decls.extend(quote!(type #name_ident: #path #assocs_typename<#gen_use>;)); - assoc_defs.extend(quote!(type #name_ident = #name_ident;)); - assocs_num_void.extend(quote!((),)); - } - - ( - assoc_gen_defs, - assoc_gen_use, - assoc_decls, - assoc_defs, - assocs_num_void, - ) - } - /// Optional and vtable definitions. /// /// Optional means they are of type `Option<&'cglue_a VTable>`. @@ -1726,13 +1675,15 @@ impl TraitGroup { vtbl_name, path, vtbl_typename, - name_ident, generics: ParsedGenerics { gen_use, .. }, + assocs: ParsedGenerics { + gen_use: assoc_use, .. + }, .. } in &self.optional_vtbl { ret.extend( - quote!(#vtbl_name: ::core::option::Option<&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name<#inst_ident, #ctx_ident, #gen_all_use CGlueAssocs>, #gen_use CGlueAssocs::#name_ident>>, ), + quote!(#vtbl_name: ::core::option::Option<&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name<#inst_ident, #ctx_ident, #gen_all_use>, #gen_use #assoc_use>>, ), ); } @@ -1746,12 +1697,16 @@ impl TraitGroup { ret_tmp_name, path, ret_tmp_typename, - name_ident, generics: ParsedGenerics { gen_use, .. }, + assocs: ParsedGenerics { + gen_use: assoc_use, .. + }, .. } in self.mandatory_vtbl.iter().chain(iter) { - ret.extend(quote!(#ret_tmp_name: #path #ret_tmp_typename, )); + ret.extend( + quote!(#ret_tmp_name: #path #ret_tmp_typename, ), + ); } ret @@ -1779,9 +1734,12 @@ impl TraitGroup { TraitInfo { vtbl_name, path, - name_ident, vtbl_typename, generics: ParsedGenerics { gen_use, .. }, + assocs: + ParsedGenerics { + gen_use: assoc_use, .. + }, .. }, mandatory, @@ -1795,10 +1753,10 @@ impl TraitGroup { }) { let def = match mandatory { true => { - quote!(#vtbl_name: &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>, ) + quote!(#vtbl_name: &'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use #assoc_use>, ) } false => { - quote!(#vtbl_name: ::core::option::Option<&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>>, ) + quote!(#vtbl_name: ::core::option::Option<&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use #assoc_use>>, ) } }; ret.extend(def); @@ -1811,7 +1769,6 @@ impl TraitGroup { fn get_container_impl( &self, name: &Ident, - assocs_trait: &Ident, trg_path: &TokenStream, all_generics: &ParsedGenerics, ) -> TokenStream { @@ -1827,13 +1784,13 @@ impl TraitGroup { let ctx_bound = super::traits::ctx_bound(); quote! { - impl> - #trg_path::GetContainer for #name<'_, CGlueInst, CGlueCtx, #gen_use CGlueAssocs> + impl + #trg_path::GetContainer for #name<'_, CGlueInst, CGlueCtx, #gen_use> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds { - type ContType = #cont_name; + type ContType = #cont_name; fn ccont_ref(&self) -> &Self::ContType { &self.container @@ -1859,7 +1816,6 @@ impl TraitGroup { fn cglue_obj_impl(&self, trg_path: &TokenStream, all_generics: &ParsedGenerics) -> TokenStream { let cont_name = &self.cont_name; - let assocs_trait = &self.assocs_trait; let ParsedGenerics { gen_declare: all_gen_declare, @@ -1871,8 +1827,8 @@ impl TraitGroup { let ctx_bound = super::traits::ctx_bound(); let mut ret = quote! { - impl, #all_gen_declare> #trg_path::CGlueObjBase - for #cont_name + impl #trg_path::CGlueObjBase + for #cont_name where CGlueInst::Target: Sized, #all_gen_where_bounds @@ -1895,20 +1851,22 @@ impl TraitGroup { path, ret_tmp_typename, ret_tmp_name, - name_ident, generics: ParsedGenerics { gen_use, .. }, + assocs: ParsedGenerics { + gen_use: assoc_use, .. + }, .. } in self.mandatory_vtbl.iter().chain(self.optional_vtbl.iter()) { ret.extend(quote!{ - impl, #all_gen_declare> - #trg_path::CGlueObjRef<#path #ret_tmp_typename> - for #cont_name + impl + #trg_path::CGlueObjRef<#path #ret_tmp_typename> + for #cont_name where CGlueInst::Target: Sized, #all_gen_where_bounds { - fn cobj_ref(&self) -> (&Self::ObjType, &#path #ret_tmp_typename, &Self::Context) { + fn cobj_ref(&self) -> (&Self::ObjType, &#path #ret_tmp_typename, &Self::Context) { (self.instance.deref(), &self.#ret_tmp_name, &self.context) } } @@ -1916,15 +1874,14 @@ impl TraitGroup { impl< CGlueInst: ::core::ops::DerefMut, CGlueCtx: #ctx_bound, - CGlueAssocs: #assocs_trait<#all_gen_use>, #all_gen_declare - > #trg_path::CGlueObjMut<#path #ret_tmp_typename> - for #cont_name + > #trg_path::CGlueObjMut<#path #ret_tmp_typename> + for #cont_name where CGlueInst::Target: Sized, #all_gen_where_bounds { - fn cobj_mut(&mut self) -> (&mut Self::ObjType, &mut #path #ret_tmp_typename, &Self::Context) { + fn cobj_mut(&mut self) -> (&mut Self::ObjType, &mut #path #ret_tmp_typename, &Self::Context) { ( self.instance.deref_mut(), &mut self.#ret_tmp_name, @@ -1964,7 +1921,6 @@ impl TraitGroup { let mut ret = TokenStream::new(); let cont_name = &self.cont_name; - let assocs_trait = &self.assocs_trait; let all_gen_declare = &all_generics.gen_declare; let all_gen_use = &all_generics.gen_use; @@ -1977,8 +1933,11 @@ impl TraitGroup { path, vtbl_typename, vtbl_get_ident, - name_ident, + assoc_bind_ident, generics: ParsedGenerics { gen_use, .. }, + assocs: ParsedGenerics { + gen_use: assoc_use, .. + }, .. } in traits { @@ -1986,30 +1945,38 @@ impl TraitGroup { // TODO: bring back CGlueObjBuild - impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #all_gen_declare CGlueAssocs: #assocs_trait<#all_gen_use>> #trg_path::GetVtblBase<#path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>> - for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst, CGlueCtx: #ctx_bound, #all_gen_declare> #trg_path::GetVtblBase<#path #vtbl_typename<'cglue_a, #cont_name, #gen_use #assoc_use>> + for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use> where - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #all_gen_where_bounds { - fn get_vtbl_base(&self) -> &#path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident> { + fn get_vtbl_base(&self) -> &#path #vtbl_typename<'cglue_a, #cont_name, #gen_use #assoc_use> { &self.#vtbl_name } } - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #all_gen_declare CGlueAssocs: #assocs_trait<#all_gen_use>> #path #vtbl_get_ident<'cglue_a, #gen_use> - for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use CGlueAssocs> + impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #all_gen_declare> #path #vtbl_get_ident<'cglue_a, #gen_use #assoc_use> + for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use> where ::Target: Sized, - #cont_name: #trg_path::CGlueObjBase, + #cont_name: #trg_path::CGlueObjBase, #all_gen_where_bounds { - type Assocs = CGlueAssocs::#name_ident; - - fn get_vtbl(&self) -> &#path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident> { + fn get_vtbl(&self) -> &#path #vtbl_typename<'cglue_a, #cont_name, #gen_use #assoc_use> { &self.#vtbl_name } } + + impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #all_gen_declare> #path #assoc_bind_ident<#gen_use> + for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use> + where + ::Target: Sized, + #cont_name: #trg_path::CGlueObjBase, + #all_gen_where_bounds + { + type Assocs = (#assoc_use); + } }); } @@ -2057,15 +2024,16 @@ impl TraitGroup { vtbl_name, path, vtbl_typename, - #[cfg(feature = "unstable")] - name_ident, generics: ParsedGenerics { gen_use, .. }, + assocs: ParsedGenerics { + gen_use: assoc_use, .. + }, .. } in &self.optional_vtbl { #[cfg(feature = "unstable")] { - let vtbl_ty = quote!(&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use CGlueAssocs::#name_ident>); + let vtbl_ty = quote!(&'cglue_a #path #vtbl_typename<'cglue_a, #cont_name, #gen_use #assoc_use>); ret.extend(quote!(#vtbl_name: <#vtbl_ty as #crate_path::TryDefault<#vtbl_ty>>::try_default(),)); } #[cfg(not(feature = "unstable"))] @@ -2170,11 +2138,13 @@ impl TraitGroup { for TraitInfo { path, raw_ident, - name_ident, vtbl_typename, generics: ParsedGenerics { gen_use, life_use, .. }, + assocs: ParsedGenerics { + gen_use: assoc_use, .. + }, .. } in iter { @@ -2191,7 +2161,7 @@ impl TraitGroup { ret.extend(quote!(#trait_bound: #path #raw_ident<#life_use #gen_use>,)); } - ret.extend(quote!(&#vtbl_lifetime #path #vtbl_typename<#vtbl_lifetime, #cont_name<#container_ident, #ctx_ident, #all_gen_use CGlueAssocs>, #gen_use CGlueAssocs::#name_ident>: #vtbl_lifetime + Default,)); + ret.extend(quote!(&#vtbl_lifetime #path #vtbl_typename<#vtbl_lifetime, #cont_name<#container_ident, #ctx_ident, #all_gen_use>, #gen_use #assoc_use>: #vtbl_lifetime + Default,)); } ret diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index e6a0bdf..8134ddc 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -61,6 +61,7 @@ pub fn process_item( generics: &ParsedGenerics, trait_type_defs: &mut TokenStream, types: &mut BTreeMap, WrappedType>, + assoc_types: &mut BTreeMap>, crate_path: &TokenStream, ) { let c_void = crate::util::void_type(); @@ -103,6 +104,8 @@ pub fn process_item( panic!("Traits with multiple lifetime bounds are not supported!"); } + let mut wrapped = false; + for attr in ty_attrs { let s = attr.path.to_token_stream().to_string(); @@ -110,6 +113,7 @@ pub fn process_item( match x { "wrap_with" => { + wrapped = true; let new_ty = attr .parse_args::() .expect("Invalid type in wrap_with."); @@ -136,6 +140,7 @@ pub fn process_item( ); } "return_wrap" => { + wrapped = true; let closure = attr .parse_args::() .expect("A valid closure must be supplied accepting the wrapped type!"); @@ -151,6 +156,7 @@ pub fn process_item( | "wrap_with_group" | "wrap_with_group_ref" | "wrap_with_group_mut" => { + wrapped = true; let mut new_ty = attr .parse_args::() .expect("Invalid type in wrap_with."); @@ -160,12 +166,6 @@ pub fn process_item( //if target.to_string() == "G" - let mut new_ty_assocs = new_ty.clone(); - new_ty_assocs.target = - format_ident!("{}BaseAssocs", target.to_string()).to_token_stream(); - core::mem::take(&mut new_ty_assocs.generic_types); - core::mem::take(&mut new_ty_assocs.generic_lifetimes); - if ["wrap_with_obj", "wrap_with_obj_ref", "wrap_with_obj_mut"].contains(&x) { new_ty.target = format_ident!("{}Base", target.to_string()).to_token_stream(); } @@ -333,24 +333,7 @@ pub fn process_item( unreachable!() } - for v in [ - &mut new_ty, - &mut new_ty_ret_tmp, - &mut new_ty_trait_impl, - &mut new_ty_hrtb, - &mut new_ty_simple, - &mut new_ty_static, - ] - .iter_mut() - { - v.push_types_end(quote!(#new_ty_assocs, )); - } - if let Some((cglue_f_ty_def, cglue_f_ty_simple_ident)) = cglue_f_tys { - for v in [&mut from_new_ty, &mut from_new_ty_simple].iter_mut() { - v.push_types_end(quote!(#new_ty_assocs, )); - } - let (ty_ref, ty_ref_simple) = { ( quote!((#from_new_ty_ref #cglue_f_ty_def, CGlueC::Context)), @@ -503,6 +486,32 @@ pub fn process_item( _ => {} } } + + if let (Some(ty_def), false) = (ty_def, wrapped) { + let new_ty = parse2(format_ident!("CGlueA{}", ty_def.ident).to_token_stream()) + .expect("Invalid type in unwrapped assoc"); + + trait_type_defs.extend(quote!(type #ty_def = #new_ty #ty_where_clause;)); + + types.insert( + Some(ty_def.clone()), + WrappedType { + ty: new_ty, + ty_ret_tmp: None, + ty_static: None, + return_conv: None, + impl_return_conv: None, + lifetime_bound: None, + lifetime_type_bound: None, + other_bounds: None, + other_bounds_simple: None, + inject_ret_tmp: false, + unbounded_hrtb: false, + }, + ); + + assoc_types.insert(ty_def.clone(), ty_bounds.clone()); + } } pub fn parse_trait( @@ -520,15 +529,23 @@ pub fn parse_trait( &ParsedGenerics, &mut TokenStream, &mut BTreeMap, WrappedType>, + &mut BTreeMap>, &TokenStream, ), -) -> (Vec, ParsedGenerics, TokenStream) { +) -> ( + Vec, + ParsedGenerics, + (ParsedGenerics, TokenStream), + TokenStream, +) { let mut funcs = vec![]; let generics = ParsedGenerics::from(&tr.generics); let mut trait_type_defs = TokenStream::new(); let mut types = BTreeMap::new(); let mut types_c_side_vtbl = BTreeMap::new(); + let mut assocs = BTreeMap::new(); + let trait_name = &tr.ident; types.insert( @@ -580,6 +597,7 @@ pub fn parse_trait( &generics, &mut trait_type_defs, &mut types, + &mut assocs, crate_path, ), TraitItem::Method(m) => { @@ -646,6 +664,7 @@ pub fn parse_trait( &generics, &mut trait_type_defs, &mut types_c_side_vtbl, + &mut Default::default(), crate_path, ); } @@ -693,7 +712,31 @@ pub fn parse_trait( } } - (funcs, generics, trait_type_defs) + let assoc_types = { + // CGlueA: bounds, CGlueA: bounds, ... + let mut tokens = TokenStream::new(); + // = CGlueA, = CGlueA, ... + let mut equality = TokenStream::new(); + + // TODO: please, make this cleaner without reparsing tokens. + for (t, mut b) in assocs { + let t = t.ident; + let ident = format_ident!("CGlueA{}", t); + equality.extend(quote!(#t = #ident,)); + if b.is_empty() { + tokens.extend(quote!(#ident,)); + } else { + if !b.trailing_punct() { + b.push_punct(Default::default()); + } + tokens.extend(quote!(#ident: #b)) + } + } + + (parse2(quote!(<#tokens>)).unwrap(), equality) + }; + + (funcs, generics, assoc_types, trait_type_defs) } pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { @@ -715,13 +758,11 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { // Additional identifiers let vtbl_ident = format_ident!("{}Vtbl", trait_name); let vtbl_get_ident = format_ident!("{}VtblGet", trait_name); - let trait_assocs_ident = format_ident!("{}TraitAssocs", trait_name); - let vtbl_assocs_ident = format_ident!("{}VtblAssocs", trait_name); let ret_tmp_ident = format_ident!("{}RetTmp", trait_name); let ret_tmp_ident_phantom = format_ident!("{}RetTmpPhantom", trait_name); let accessor_trait_ident = format_ident!("{}OpaqueObj", trait_name); + let assoc_bind_ident = format_ident!("{}AssocBind", trait_name); - let assocs_base_type = format_ident!("{}BaseAssocs", trait_name); let base_box_trait_obj_ident = format_ident!("{}BaseBox", trait_name); let base_ctx_trait_obj_ident = format_ident!("{}BaseCtxBox", trait_name); let base_arc_trait_obj_ident = format_ident!("{}BaseArcBox", trait_name); @@ -732,7 +773,6 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { let base_ctx_ref_trait_obj_ident = format_ident!("{}BaseCtxRef", trait_name); let base_arc_ref_trait_obj_ident = format_ident!("{}BaseArcRef", trait_name); let base_trait_obj_ident = format_ident!("{}Base", trait_name); - let base_baseassocs_trait_obj_ident = format_ident!("{}BaseBaseAssocs", trait_name); let opaque_box_trait_obj_ident = format_ident!("{}Box", trait_name); let opaque_ctx_trait_obj_ident = format_ident!("{}CtxBox", trait_name); @@ -744,7 +784,8 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { let opaque_ctx_ref_trait_obj_ident = format_ident!("{}CtxRef", trait_name); let opaque_arc_ref_trait_obj_ident = format_ident!("{}ArcRef", trait_name); - let (funcs, generics, trait_type_defs) = parse_trait(&tr, &crate_path, true, process_item); + let (funcs, generics, (assocs, assoc_equality), trait_type_defs) = + parse_trait(&tr, &crate_path, true, process_item); let cglue_c_opaque_bound = cglue_c_opaque_bound(); let ctx_bound = ctx_bound(); @@ -762,6 +803,14 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { .. } = &generics; + let ParsedGenerics { + gen_use: assoc_use, + gen_declare: assoc_declare, + .. + } = &assocs; + + let assoc_declare_stripped = assocs.declare_without_nonstatic_bounds(); + // TODO: Is there a better solution? let cglue_a_outlives = if life_use.is_empty() { None @@ -776,6 +825,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { let gen_declare_stripped = generics.declare_without_nonstatic_bounds(); let gen_lt_bounds = generics.declare_lt_for_all("e!('cglue_a)); let gen_sabi_bounds = generics.declare_sabi_for_all(&crate_path); + let assoc_sabi_bounds = assocs.declare_sabi_for_all(&crate_path); let gen_where_bounds_base_nolt = gen_where_bounds.clone(); @@ -787,21 +837,14 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { let gen_where_bounds = quote! { #gen_where_bounds_base #gen_sabi_bounds + #assoc_sabi_bounds }; #[cfg(feature = "layout_checks")] - let derive_layouts = - quote!(#[derive(::abi_stable::StableAbi)] #[sabi(unsafe_unconstrained(CGlueAssocs))]); + let derive_layouts = quote!(#[derive(::abi_stable::StableAbi)]); #[cfg(not(feature = "layout_checks"))] let derive_layouts = quote!(); - #[cfg(feature = "layout_checks")] - let cglue_assocs_phantom_decl = quote!( - ::core::marker::PhantomData<::abi_stable::marker_type::UnsafeIgnoredType> - ); - #[cfg(not(feature = "layout_checks"))] - let cglue_assocs_phantom_decl = quote!(::core::marker::PhantomData); - // Function definitions in the vtable let mut vtbl_func_defintions = TokenStream::new(); @@ -826,15 +869,15 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { // Define wrapped functions for the vtable let mut cfuncs = TokenStream::new(); - let ret_tmp_ty = quote!(#ret_tmp_ident); + let ret_tmp_ty = quote!(#ret_tmp_ident); for func in funcs.iter() { let extra_bounds = func.cfunc_def( &mut cfuncs, &trg_path, &ret_tmp_ty, - &vtbl_assocs_ident, - &trait_assocs_ident, + &assocs, + &assoc_equality, ); trait_type_bounds.extend(extra_bounds.to_token_stream()); } @@ -865,6 +908,8 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { // I mean we could cross filter it but it's a little bit much work. let phantom_data_definitions = generics.phantom_data_definitions(); let phantom_data_init = generics.phantom_data_init(); + let assoc_phantom_data_definitions = assocs.phantom_data_definitions(); + let assoc_phantom_data_init = assocs.phantom_data_init(); // Implement the trait for a type that has CGlueObj let mut trait_impl_fns = TokenStream::new(); @@ -987,8 +1032,6 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { ); let submod_name = format_ident!("cglue_{}", trait_name.to_string().to_lowercase()); - let assoc_bound = quote!(#vtbl_assocs_ident<#gen_use>); - let ret_tmp = if !ret_tmp_type_defs.is_empty() { quote! { /// Temporary return value structure, for returning wrapped references. @@ -998,26 +1041,26 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /// directly. Use the trait functions. #[repr(C)] #derive_layouts - pub struct #ret_tmp_ident + pub struct #ret_tmp_ident { #ret_tmp_type_defs #phantom_data_definitions - _ty_cglue_assocs: #cglue_assocs_phantom_decl, + #assoc_phantom_data_definitions _ty_cglue_ctx: ::core::marker::PhantomData, } - impl #ret_tmp_ident + impl #ret_tmp_ident { #ret_tmp_getter_defs } - impl Default for #ret_tmp_ident + impl Default for #ret_tmp_ident { fn default() -> Self { Self { #ret_tmp_default_defs #phantom_data_init - _ty_cglue_assocs: Default::default(), + #assoc_phantom_data_init _ty_cglue_ctx: ::core::marker::PhantomData, } } @@ -1028,10 +1071,10 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /// Technically unused phantom data definition structure. #[repr(C)] #derive_layouts - pub struct #ret_tmp_ident_phantom + pub struct #ret_tmp_ident_phantom { #phantom_data_definitions - _ty_cglue_assocs: #cglue_assocs_phantom_decl, + #assoc_phantom_data_definitions _ty_cglue_ctx: ::core::marker::PhantomData, } @@ -1045,14 +1088,14 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /// groups/objects. If C++11 templates are generated, it is important to define a /// custom type for CGlueTraitObj that does not have `ret_tmp` defined, and change all /// type aliases of this trait to use that particular structure. - pub type #ret_tmp_ident = ::core::marker::PhantomData<#ret_tmp_ident_phantom>; + pub type #ret_tmp_ident = ::core::marker::PhantomData<#ret_tmp_ident_phantom>; } }; #[cfg(feature = "layout_checks")] let (opaque_vtbl_bounds, container_vtbl_bounds) = ( - quote!(#vtbl_ident<'cglue_a, CGlueC::OpaqueTarget, #gen_use CGlueAssocs>: ::abi_stable::StableAbi,), - quote!(#vtbl_ident<'cglue_a, ::ContType, #gen_use >::Assocs>: ::abi_stable::StableAbi,), + quote!(#vtbl_ident<'cglue_a, CGlueC::OpaqueTarget, #gen_use #assoc_use>: ::abi_stable::StableAbi,), + quote!(#vtbl_ident<'cglue_a, ::ContType, #gen_use #assoc_use>: ::abi_stable::StableAbi,), ); #[cfg(not(feature = "layout_checks"))] let (opaque_vtbl_bounds, container_vtbl_bounds) = (quote!(), quote!()); @@ -1081,10 +1124,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { #vtbl_get_ident, #ret_tmp_ident, #accessor_trait_ident, - - #vtbl_assocs_ident, - #trait_assocs_ident, - #assocs_base_type, + #assoc_bind_ident, #base_box_trait_obj_ident, #base_ctx_trait_obj_ident, @@ -1096,7 +1136,6 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { #base_ctx_ref_trait_obj_ident, #base_arc_ref_trait_obj_ident, #base_trait_obj_ident, - #base_baseassocs_trait_obj_ident, #opaque_box_trait_obj_ident, #opaque_ctx_trait_obj_ident, @@ -1115,30 +1154,6 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /* Primary vtable definition. */ - /// Associated types, extracted from the trait - /// - /// Associated types are encoded as a tuple of all associated types, sorted alphabetically. - pub trait #vtbl_assocs_ident<#gen_use>: 'static { - //type ReturnType; - } - - impl<#gen_use> #vtbl_assocs_ident<#gen_use> for () { - } - - /// Helper for getting associated types from a `T` that implements the trait. - pub trait #trait_assocs_ident<#gen_use> { - type Assocs: #vtbl_assocs_ident<#gen_use>; - } - - pub type #assocs_base_type = (); - - impl #trait_name<#life_use #gen_use>, #gen_declare_stripped> #trait_assocs_ident<#gen_use> for CGlueInst - where - #gen_where_bounds_base_nolt - { - type Assocs = (); - } - #[doc = #vtbl_doc] /// /// This virtual function table contains ABI-safe interface for the given trait. @@ -1148,22 +1163,22 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { 'cglue_a, CGlueC: 'cglue_a + #trg_path::CGlueObjBase, #gen_declare_stripped - CGlueAssocs: 'cglue_a + #assoc_bound, + #assoc_declare_stripped > where #gen_where_bounds_base_nolt { #vtbl_func_defintions + #assoc_phantom_data_definitions _lt_cglue_a: ::core::marker::PhantomData<&'cglue_a CGlueC>, - _assocs: #cglue_assocs_phantom_decl, } impl< 'cglue_a, CGlueC: #trg_path::CGlueObjBase, #gen_declare_stripped - CGlueAssocs: #assoc_bound, - > #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs> + #assoc_declare_stripped + > #vtbl_ident<'cglue_a, CGlueC, #gen_use #assoc_use> where #gen_where_bounds { @@ -1175,20 +1190,20 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /* Default implementation. */ /// Default vtable reference creation. - impl<'cglue_a, CGlueC #cglue_c_bounds, CGlueCtx: #ctx_bound, #gen_declare_stripped CGlueAssocs: 'cglue_a + #assoc_bound> Default - for &'cglue_a #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueC #cglue_c_bounds, CGlueCtx: #ctx_bound, #gen_declare_stripped #assoc_declare_stripped> Default + for &'cglue_a #vtbl_ident<'cglue_a, CGlueC, #gen_use #assoc_use> where #gen_where_bounds #trait_type_bounds #cglue_c_into_inner - CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use> + #trait_assocs_ident<#gen_use Assocs = CGlueAssocs>, + CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use #assoc_equality>, CGlueC: #trg_path::Opaquable, CGlueC::OpaqueTarget: #trg_path::GenericTypeBounds, - #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs>: #trg_path::CGlueBaseVtbl, + #vtbl_ident<'cglue_a, CGlueC, #gen_use #assoc_use>: #trg_path::CGlueBaseVtbl, { /// Create a static vtable for the given type. fn default() -> Self { &#vtbl_ident { #vtbl_default_funcs + #assoc_phantom_data_init _lt_cglue_a: ::core::marker::PhantomData, - _assocs: ::core::marker::PhantomData, } } } @@ -1199,9 +1214,9 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { 'cglue_a, CGlueC: #trg_path::CGlueObjBase, #gen_declare_stripped - CGlueAssocs: #assoc_bound, + #assoc_declare_stripped > - #trg_path::CGlueVtblCont for #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs> + #trg_path::CGlueVtblCont for #vtbl_ident<'cglue_a, CGlueC, #gen_use #assoc_use> where #gen_where_bounds { @@ -1212,116 +1227,113 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { 'cglue_a, CGlueC: #trg_path::Opaquable + #trg_path::CGlueObjBase + 'cglue_a, #gen_declare_stripped - CGlueAssocs: #assoc_bound, + #assoc_declare_stripped > #trg_path::CGlueBaseVtbl - for #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs> + for #vtbl_ident<'cglue_a, CGlueC, #gen_use #assoc_use> where #gen_where_bounds #cglue_c_opaque_bound - CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use> + #trait_assocs_ident<#gen_use Assocs = CGlueAssocs>, + CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use #assoc_equality>, CGlueC::OpaqueTarget: #trg_path::GenericTypeBounds, #opaque_vtbl_bounds { - type OpaqueVtbl = #vtbl_ident<'cglue_a, CGlueC::OpaqueTarget, #gen_use CGlueAssocs>; + type OpaqueVtbl = #vtbl_ident<'cglue_a, CGlueC::OpaqueTarget, #gen_use #assoc_use>; type Context = CGlueC::Context; - type RetTmp = #ret_tmp_ident; + type RetTmp = #ret_tmp_ident; } - impl<'cglue_a, CGlueC #cglue_c_bounds, CGlueCtx: #ctx_bound, #gen_declare_stripped CGlueAssocs: 'cglue_a + #assoc_bound> #trg_path::CGlueVtbl - for #vtbl_ident<'cglue_a, CGlueC, #gen_use CGlueAssocs> + impl<'cglue_a, CGlueC #cglue_c_bounds, CGlueCtx: #ctx_bound, #gen_declare_stripped #assoc_declare_stripped> #trg_path::CGlueVtbl + for #vtbl_ident<'cglue_a, CGlueC, #gen_use #assoc_use> where #gen_where_bounds #cglue_c_opaque_bound CGlueC: #trg_path::Opaquable, CGlueC::OpaqueTarget: #trg_path::GenericTypeBounds, - CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use> + #trait_assocs_ident<#gen_use Assocs = CGlueAssocs> {} + CGlueC::ObjType: for<#life_declare> #trait_name<#life_use #gen_use #assoc_equality> {} #[doc = #base_box_trait_obj_doc] - pub type #base_box_trait_obj_ident<'cglue_a, CGlueT, #gen_use> - = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #trg_path::NoContext, #gen_use>; + pub type #base_box_trait_obj_ident<'cglue_a, CGlueT, #gen_use #assoc_use> + = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #trg_path::NoContext, #gen_use #assoc_use>; #[doc = #base_ctx_trait_obj_doc] - pub type #base_ctx_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use> - = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use>; + pub type #base_ctx_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use #assoc_use> + = #base_trait_obj_ident<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use #assoc_use>; #[doc = #base_arc_trait_obj_doc] - pub type #base_arc_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use> - = #base_ctx_trait_obj_ident<'cglue_a, CGlueT, #crate_path::arc::CArc, #gen_use>; + pub type #base_arc_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use #assoc_use> + = #base_ctx_trait_obj_ident<'cglue_a, CGlueT, #crate_path::arc::CArc, #gen_use #assoc_use>; #[doc = #base_mut_trait_obj_doc] - pub type #base_mut_trait_obj_ident<'cglue_a, CGlueT, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #trg_path::NoContext, #gen_use>; + pub type #base_mut_trait_obj_ident<'cglue_a, CGlueT, #gen_use #assoc_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #trg_path::NoContext, #gen_use #assoc_use>; #[doc = #base_ctx_mut_trait_obj_doc] - pub type #base_ctx_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, CGlueCtx, #gen_use>; + pub type #base_ctx_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use #assoc_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, CGlueCtx, #gen_use #assoc_use>; #[doc = #base_arc_mut_trait_obj_doc] - pub type #base_arc_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #crate_path::arc::CArc, #gen_use>; + pub type #base_arc_mut_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use #assoc_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a mut CGlueT, #crate_path::arc::CArc, #gen_use #assoc_use>; #[doc = #base_ref_trait_obj_doc] - pub type #base_ref_trait_obj_ident<'cglue_a, CGlueT, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #trg_path::NoContext, #gen_use>; + pub type #base_ref_trait_obj_ident<'cglue_a, CGlueT, #gen_use #assoc_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #trg_path::NoContext, #gen_use #assoc_use>; #[doc = #base_ctx_ref_trait_obj_doc] - pub type #base_ctx_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, CGlueCtx, #gen_use>; + pub type #base_ctx_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueCtx, #gen_use #assoc_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, CGlueCtx, #gen_use #assoc_use>; #[doc = #base_arc_ref_trait_obj_doc] - pub type #base_arc_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use> - = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #crate_path::arc::CArc, #gen_use>; + pub type #base_arc_ref_trait_obj_ident<'cglue_a, CGlueT, CGlueC, #gen_use #assoc_use> + = #base_trait_obj_ident<'cglue_a, &'cglue_a CGlueT, #crate_path::arc::CArc, #gen_use #assoc_use>; #[doc = #base_trait_obj_doc] - pub type #base_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use CGlueAssocs = #assocs_base_type> + pub type #base_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use #assoc_use> = #trg_path::CGlueTraitObj::< 'cglue_a, CGlueInst, #vtbl_ident< 'cglue_a, - #trg_path::CGlueObjContainer>, + #trg_path::CGlueObjContainer>, #gen_use - CGlueAssocs, + #assoc_use >, CGlueCtx, - #ret_tmp_ident + #ret_tmp_ident >; - pub type #base_baseassocs_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use> - = #base_trait_obj_ident<'cglue_a, CGlueInst, CGlueCtx, #gen_use #assocs_base_type>; - #[doc = #opaque_box_trait_obj_doc] - pub type #opaque_box_trait_obj_ident<'cglue_a, #gen_use> - = #base_box_trait_obj_ident<'cglue_a, #c_void, #gen_use>; + pub type #opaque_box_trait_obj_ident<'cglue_a, #gen_use #assoc_use> + = #base_box_trait_obj_ident<'cglue_a, #c_void, #gen_use #assoc_use>; #[doc = #opaque_ctx_trait_obj_doc] - pub type #opaque_ctx_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use> - = #base_ctx_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use>; + pub type #opaque_ctx_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use #assoc_use> + = #base_ctx_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use #assoc_use>; #[doc = #opaque_arc_trait_obj_doc] - pub type #opaque_arc_trait_obj_ident<'cglue_a, #gen_use> - = #base_arc_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use>; + pub type #opaque_arc_trait_obj_ident<'cglue_a, #gen_use #assoc_use> + = #base_arc_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use #assoc_use>; #[doc = #opaque_mut_trait_obj_doc] - pub type #opaque_mut_trait_obj_ident<'cglue_a, #gen_use> - = #base_mut_trait_obj_ident<'cglue_a, #c_void, #gen_use>; + pub type #opaque_mut_trait_obj_ident<'cglue_a, #gen_use #assoc_use> + = #base_mut_trait_obj_ident<'cglue_a, #c_void, #gen_use #assoc_use>; #[doc = #opaque_ctx_mut_trait_obj_doc] - pub type #opaque_ctx_mut_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use> - = #base_ctx_mut_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use>; + pub type #opaque_ctx_mut_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use #assoc_use> + = #base_ctx_mut_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use #assoc_use>; #[doc = #opaque_arc_mut_trait_obj_doc] - pub type #opaque_arc_mut_trait_obj_ident<'cglue_a, #gen_use> - = #base_arc_mut_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use>; + pub type #opaque_arc_mut_trait_obj_ident<'cglue_a, #gen_use #assoc_use> + = #base_arc_mut_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use #assoc_use>; #[doc = #opaque_ref_trait_obj_doc] - pub type #opaque_ref_trait_obj_ident<'cglue_a, #gen_use> - = #base_ref_trait_obj_ident<'cglue_a, #c_void, #gen_use>; + pub type #opaque_ref_trait_obj_ident<'cglue_a, #gen_use #assoc_use> + = #base_ref_trait_obj_ident<'cglue_a, #c_void, #gen_use #assoc_use>; #[doc = #opaque_ctx_ref_trait_obj_doc] - pub type #opaque_ctx_ref_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use> - = #base_ctx_ref_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use>; + pub type #opaque_ctx_ref_trait_obj_ident<'cglue_a, CGlueCtx, #gen_use #assoc_use> + = #base_ctx_ref_trait_obj_ident<'cglue_a, #c_void, CGlueCtx, #gen_use #assoc_use>; #[doc = #opaque_arc_ref_trait_obj_doc] - pub type #opaque_arc_ref_trait_obj_ident<'cglue_a, #gen_use> - = #base_arc_ref_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use>; + pub type #opaque_arc_ref_trait_obj_ident<'cglue_a, #gen_use #assoc_use> + = #base_arc_ref_trait_obj_ident<'cglue_a, #c_void, #c_void, #gen_use #assoc_use>; /* Internal wrapper functions. */ @@ -1329,8 +1341,8 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /* Define trait for simpler type accesses */ - pub trait #accessor_trait_ident<'cglue_a #cglue_a_outlives, #life_declare #gen_declare> - : 'cglue_a + #trg_path::GetContainer + #vtbl_get_ident<'cglue_a, #gen_use> #supertrait_bounds + pub trait #accessor_trait_ident<'cglue_a #cglue_a_outlives, #life_declare #gen_declare #assoc_declare> + : 'cglue_a + #trg_path::GetContainer + #vtbl_get_ident<'cglue_a, #gen_use #assoc_use> #supertrait_bounds where #gen_where_bounds { @@ -1338,26 +1350,46 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { } impl<'cglue_a #cglue_a_outlives, #life_declare - CGlueO: 'cglue_a + #trg_path::GetContainer + #vtbl_get_ident<'cglue_a, #gen_use> #supertrait_bounds, #gen_declare> - #accessor_trait_ident<'cglue_a, #life_use #gen_use> for CGlueO + CGlueO: 'cglue_a + #trg_path::GetContainer + #vtbl_get_ident<'cglue_a, #gen_use #assoc_use> #supertrait_bounds, #gen_declare #assoc_declare> + #accessor_trait_ident<'cglue_a, #life_use #gen_use #assoc_use> for CGlueO where #objcont_accessor_bound #gen_where_bounds { - type #vtbl_ident = #vtbl_ident<'cglue_a, ::ContType, #gen_use >::Assocs>; + type #vtbl_ident = #vtbl_ident<'cglue_a, ::ContType, #gen_use #assoc_use>; + } + + /* Binds associated types for a given trait. */ + + pub trait #assoc_bind_ident<#gen_use> { + type Assocs; + } + + impl< + 'cglue_a, + CGlueT: ::core::ops::Deref, + CGlueF, + CGlueCtx: #ctx_bound, + CGlueRetTmp, + #gen_declare_stripped + #assoc_declare_stripped + > + #assoc_bind_ident<#gen_use> + for #trg_path::CGlueTraitObj<'cglue_a, CGlueT, #vtbl_ident<'cglue_a, #trg_path::CGlueObjContainer, #gen_use #assoc_use>, CGlueCtx, CGlueRetTmp> + where + #gen_where_bounds_base + { + type Assocs = (#assoc_use); } /* Getters for vtables. Automatically implemented for CGlueTraitObj */ - pub trait #vtbl_get_ident<'cglue_a, #gen_declare_stripped>: + pub trait #vtbl_get_ident<'cglue_a, #gen_declare_stripped #assoc_declare_stripped>: #trg_path::GetContainer where #gen_where_bounds_base { - // List unspecified associated types here: - type Assocs: #assoc_bound; - - fn get_vtbl(&self) -> &#vtbl_ident<'cglue_a, ::ContType, #gen_use Self::Assocs>; + fn get_vtbl(&self) -> &#vtbl_ident<'cglue_a, ::ContType, #gen_use #assoc_use>; } impl< @@ -1365,18 +1397,16 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { CGlueT: ::core::ops::Deref, CGlueF, CGlueCtx: #ctx_bound, - CGlueAssocs: #assoc_bound, CGlueRetTmp, #gen_declare_stripped + #assoc_declare_stripped > - #vtbl_get_ident<'cglue_a, #gen_use> - for #trg_path::CGlueTraitObj<'cglue_a, CGlueT, #vtbl_ident<'cglue_a, #trg_path::CGlueObjContainer, #gen_use CGlueAssocs>, CGlueCtx, CGlueRetTmp> + #vtbl_get_ident<'cglue_a, #gen_use #assoc_use> + for #trg_path::CGlueTraitObj<'cglue_a, CGlueT, #vtbl_ident<'cglue_a, #trg_path::CGlueObjContainer, #gen_use #assoc_use>, CGlueCtx, CGlueRetTmp> where #gen_where_bounds_base { - type Assocs = CGlueAssocs; - - fn get_vtbl(&self) -> &#vtbl_ident<'cglue_a, ::ContType, #gen_use CGlueAssocs> { + fn get_vtbl(&self) -> &#vtbl_ident<'cglue_a, ::ContType, #gen_use #assoc_use> { #trg_path::GetVtblBase::get_vtbl_base(self) } } @@ -1384,21 +1414,24 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { /* Trait implementation. */ #unsafety impl<'cglue_a #cglue_a_outlives, #life_declare - CGlueO: 'cglue_a + #vtbl_get_ident<'cglue_a, #gen_use> #supertrait_bounds + CGlueO: 'cglue_a + #vtbl_get_ident<'cglue_a, #gen_use #assoc_use> #supertrait_bounds // We essentially need only this bound, but we repeat the previous ones because // otherwise we get conflicting impl errors. // TODO: Is this a bug? Typically Rust typesystem doesn't complain in such cases. - + #accessor_trait_ident<'cglue_a, #life_use #gen_use> + + #accessor_trait_ident<'cglue_a, #life_use #gen_use #assoc_use> + // Same here. + + #assoc_bind_ident<#gen_use Assocs = (#assoc_use)> // We also need to specify this one, for some reason. If not for conflicting // impl errors, `GetVtblBase` would be a relatively redundant trait with no // purpose. - + #trg_path::GetVtblBase<#vtbl_ident<'cglue_a, ::ContType, #gen_use >::Assocs>>, - #gen_declare> + + #trg_path::GetVtblBase<#vtbl_ident<'cglue_a, ::ContType, #gen_use #assoc_use>>, + #gen_declare #assoc_declare> #trait_impl_name<#life_use #gen_use> for CGlueO where #gen_where_bounds #container_vtbl_bounds { + // TODO: #assoc_type_def #trait_type_defs #trait_impl_fns } diff --git a/cglue/src/lib.rs b/cglue/src/lib.rs index fc10102..91e4b15 100644 --- a/cglue/src/lib.rs +++ b/cglue/src/lib.rs @@ -511,18 +511,17 @@ //! CGlueInst: ::core::ops::Deref>, //! CGlueCtx: cglue::trait_group::ContextBounds, //! T: Eq, -//! CGlueAssocs: GenGroupVtblAssocs, -//! > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, T, CGlueAssocs> for GA +//! > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, T> for GA //! where //! Self: TA, -//! &'cglue_a TAVtbl<'cglue_a, GenGroupContainer, -//! CGlueAssocs::TA>: +//! &'cglue_a TAVtbl<'cglue_a, GenGroupContainer, +//! >: //! 'cglue_a + Default, //! T: cglue::trait_group::GenericTypeBounds, //! { //! fn fill_table( -//! table: GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, T, CGlueAssocs>, -//! ) -> GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, T, CGlueAssocs> { +//! table: GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, T>, +//! ) -> GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, T> { //! table.enable_ta() //! } //! } @@ -531,12 +530,11 @@ //! 'cglue_a, //! CGlueInst: ::core::ops::Deref>, //! CGlueCtx: cglue::trait_group::ContextBounds, -//! CGlueAssocs: GenGroupVtblAssocs, -//! > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, u64, CGlueAssocs> for GA +//! > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, u64> for GA //! { //! fn fill_table( -//! table: GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, u64, CGlueAssocs>, -//! ) -> GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, u64, CGlueAssocs> { +//! table: GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, u64>, +//! ) -> GenGroupVtables<'cglue_a, CGlueInst, CGlueCtx, u64> { //! table //! } //! } diff --git a/cglue/src/tests/generics/associated.rs b/cglue/src/tests/generics/associated.rs index 8469605..8ef807f 100644 --- a/cglue/src/tests/generics/associated.rs +++ b/cglue/src/tests/generics/associated.rs @@ -128,8 +128,12 @@ impl GenericConsumedGroupReturn for SA { } } -//#[cglue_trait] -// FIXME: cglue currently does not support unwrapped associated types. +#[cglue_trait] +pub trait UnwrappedAssociatedVar { + type AssocVar; +} + +#[cglue_trait] pub trait UnwrappedAssociatedReturn { type ReturnType; @@ -144,6 +148,13 @@ impl UnwrappedAssociatedReturn for SA { } } +cglue_trait_group!( + UnwrappedGroup, + UnwrappedAssociatedReturn, + {} +); +cglue_impl_group!(SA, UnwrappedGroup); + #[test] fn use_assoc_return() { let sa = SA {}; @@ -208,3 +219,21 @@ fn use_consumed_group_return() { assert!(cast.gwi_1(&cast.gt_1())); assert!(!cast.gwi_1(&(cast.gt_1() + 1))); } + +#[test] +fn use_unwrapped_associated_return() { + let sa = SA {}; + + let obj = trait_obj!(sa as UnwrappedAssociatedReturn); + + let _sa: SA = obj.uar_1(); +} + +#[test] +fn use_unwrapped_group() { + let sa = SA {}; + + let obj = group_obj!(sa as UnwrappedGroup); + + let _sa: SA = obj.uar_1(); +} diff --git a/cglue/src/tests/simple/hrtb.rs b/cglue/src/tests/simple/hrtb.rs index 8900520..4e411ea 100644 --- a/cglue/src/tests/simple/hrtb.rs +++ b/cglue/src/tests/simple/hrtb.rs @@ -138,7 +138,7 @@ fn use_plugin_group() { fn use_plugin_group_mut() { let mut sa = SA {}; - let base = PluginInstance::<_, _, PluginInstanceBaseAssocs>::from(&mut sa); + let base = PluginInstance::<_, _>::from(&mut sa); let mut obj = crate::trait_group::Opaquable::into_opaque(base); diff --git a/cglue/src/tests/simple/traits.rs b/cglue/src/tests/simple/traits.rs index b62b7f1..eb6f988 100644 --- a/cglue/src/tests/simple/traits.rs +++ b/cglue/src/tests/simple/traits.rs @@ -64,15 +64,15 @@ type ICont = crate::trait_group::CGlueObjContainer = ICont<&'static Implementor, C>; type IMutCont = ICont<&'static mut Implementor, C>; -type WSCont = IMutCont>; -type WOCont = IMutCont>; -type WIRCont = IRefCont>; -type WAIRCont = IRefCont>; -type WINTOCont = IRefCont>; +type WSCont = IMutCont>; +type WOCont = IMutCont>; +type WIRCont = IRefCont>; +type WAIRCont = IRefCont>; +type WINTOCont = IRefCont>; #[test] fn slices_wrapped() { - let vtbl = <&WithSliceVtbl>::default(); + let vtbl = <&WithSliceVtbl>::default(); let _: unsafe extern "C" fn(&mut WSCont, CSliceRef) = vtbl.wslice_1(); let _: unsafe extern "C" fn(&mut WSCont, CSliceRef) = vtbl.wslice_2(); let _: unsafe extern "C" fn(&mut WSCont) -> CSliceRef = vtbl.wslice_3(); @@ -82,53 +82,53 @@ fn slices_wrapped() { #[test] fn npo_option_forwarded() { - let vtbl = <&WithOptionsVtbl>::default(); + let vtbl = <&WithOptionsVtbl>::default(); let _: unsafe extern "C" fn(&WOCont, Option<&usize>) = vtbl.wopt_1(); } #[test] fn non_npo_option_wrapped() { - let vtbl = <&WithOptionsVtbl>::default(); + let vtbl = <&WithOptionsVtbl>::default(); let _: unsafe extern "C" fn(&WOCont, crate::option::COption) = vtbl.wopt_2(); } #[test] fn mixed_options() { - let vtbl = <&WithOptionsVtbl>::default(); + let vtbl = <&WithOptionsVtbl>::default(); let _: unsafe extern "C" fn(&mut WOCont, Option<&u64>, crate::option::COption) = vtbl.wopt_3(); } #[test] fn int_result() { - let vtbl = <&WithIntResultVtbl>::default(); + let vtbl = <&WithIntResultVtbl>::default(); let _: unsafe extern "C" fn(&WIRCont, usize, &mut core::mem::MaybeUninit) -> i32 = vtbl.wint_1(); } #[test] fn no_int_result() { - let vtbl = <&WithIntResultVtbl>::default(); + let vtbl = <&WithIntResultVtbl>::default(); let _: unsafe extern "C" fn(&WIRCont, usize) -> crate::result::CResult = vtbl.wint_2(); } #[test] fn alias_int_result() { - let vtbl = <&WithAliasIntResultVtbl>::default(); + let vtbl = <&WithAliasIntResultVtbl>::default(); let _: unsafe extern "C" fn(&WAIRCont, usize, &mut core::mem::MaybeUninit) -> i32 = vtbl.waint_1(); } #[test] fn alias_no_int_result() { - let vtbl = <&WithAliasIntResultVtbl>::default(); + let vtbl = <&WithAliasIntResultVtbl>::default(); let _: unsafe extern "C" fn(&WAIRCont, usize) -> crate::result::CResult = vtbl.waint_2(); } #[test] fn into_t_wrapped() { - let vtbl = <&WithIntoVtbl>::default(); + let vtbl = <&WithIntoVtbl>::default(); let _: unsafe extern "C" fn(&WINTOCont, usize) = vtbl.winto_1(); } From 783ccfa8e3d61c9c3f890caad2d8d04c48df551d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Fri, 21 Jun 2024 02:09:45 +0100 Subject: [PATCH 25/41] Fix unsafe trait functions --- cglue-gen/src/func.rs | 3 ++- cglue-gen/src/traits.rs | 6 +++--- cglue/src/tests/simple/trait_defs.rs | 5 +++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index 9c0faad..c13f520 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -794,6 +794,7 @@ impl ParsedFunc { /// Create a VTable definition for this function pub fn vtbl_def(&self, stream: &mut TokenStream) { let name = &self.name; + let unsafety = &self.get_safety(); let args = self.vtbl_args(); let ParsedReturnType { c_out, @@ -826,7 +827,7 @@ impl ParsedFunc { let sig_life_declare = merge_lifetime_declarations(&sig_life_declare, &parse_quote!(#hrtb)); let gen = quote! { - #name: for<#sig_life_declare> extern "C" fn(#args #c_ret_params) #c_out, + #name: for<#sig_life_declare> #unsafety extern "C" fn(#args #c_ret_params) #c_out, }; stream.extend(gen); diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index 8134ddc..b91849d 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -846,10 +846,10 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { let derive_layouts = quote!(); // Function definitions in the vtable - let mut vtbl_func_defintions = TokenStream::new(); + let mut vtbl_func_definitions = TokenStream::new(); for func in &funcs { - func.vtbl_def(&mut vtbl_func_defintions); + func.vtbl_def(&mut vtbl_func_definitions); } // Getters for vtable functions @@ -1168,7 +1168,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { where #gen_where_bounds_base_nolt { - #vtbl_func_defintions + #vtbl_func_definitions #assoc_phantom_data_definitions _lt_cglue_a: ::core::marker::PhantomData<&'cglue_a CGlueC>, } diff --git a/cglue/src/tests/simple/trait_defs.rs b/cglue/src/tests/simple/trait_defs.rs index 528b118..3b7e7b7 100644 --- a/cglue/src/tests/simple/trait_defs.rs +++ b/cglue/src/tests/simple/trait_defs.rs @@ -27,3 +27,8 @@ pub trait TE {} pub trait TT { fn tt_1(&self, v: T) -> T; } + +#[cglue_trait] +pub trait TF { + unsafe fn tf_1(&self); +} From 6c1662a6db80390690361804626d31b72834ea3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Fri, 21 Jun 2024 19:23:00 +0100 Subject: [PATCH 26/41] Add Future support --- .github/workflows/build.yml | 4 +- Cargo.lock | 9 ++ cglue-gen/Cargo.toml | 1 + cglue-gen/src/ext/core/future.rs | 63 ++++++++++ cglue-gen/src/ext/core/mod.rs | 5 + cglue-gen/src/func.rs | 168 +++++++++++++++++++++++---- cglue-gen/src/trait_groups.rs | 8 +- cglue-gen/src/traits.rs | 13 ++- cglue-macro/Cargo.toml | 1 + cglue/Cargo.toml | 7 +- cglue/src/lib.rs | 4 +- cglue/src/task/sound.rs | 3 +- cglue/src/tests/ext/future.rs | 17 +++ cglue/src/tests/ext/mod.rs | 2 + cglue/src/tests/simple/trait_defs.rs | 1 + cglue/src/trait_group.rs | 21 ++++ 16 files changed, 291 insertions(+), 36 deletions(-) create mode 100644 cglue-gen/src/ext/core/future.rs create mode 100644 cglue/src/tests/ext/future.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a7525f6..020e5eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: # panic in const is used to verify waker layouts toolchain: ["1.57.0", "stable"] features: [ - "--features task_unstable", + "--features task", "--features layout_checks" ] steps: @@ -148,7 +148,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - features: ["--all-features", "", "-p cglue --features task_unstable", "-p cglue --features task_unstable"] + features: ["--all-features", "", "-p cglue --features task", "-p cglue --features task"] steps: - uses: actions/checkout@v2 - run: rustup component add clippy diff --git a/Cargo.lock b/Cargo.lock index ef09b89..e347baf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "abi_stable" version = "0.10.4" @@ -94,6 +96,7 @@ dependencies = [ "cglue-macro", "log", "no-std-compat", + "pollster", "rustc_version 0.4.0", "serde", "tarc", @@ -327,6 +330,12 @@ dependencies = [ "plugin-api", ] +[[package]] +name = "pollster" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b647f02b0ae8f6d4f58e06639cf41316a154b5469dc7e833026645aa2807c8ef" + [[package]] name = "proc-macro-crate" version = "1.2.1" diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index 0a9d8be..ca0afac 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -24,3 +24,4 @@ default = [] rust_void = [] unstable = [] layout_checks = [] +task = [] diff --git a/cglue-gen/src/ext/core/future.rs b/cglue-gen/src/ext/core/future.rs new file mode 100644 index 0000000..a12485c --- /dev/null +++ b/cglue-gen/src/ext/core/future.rs @@ -0,0 +1,63 @@ +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use std::collections::HashMap; +use syn::{Ident, Path}; + +pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { + let cur_path = super::super::join_paths(parent_path, format_ident!("future")); + + let crate_path = crate::util::crate_path(); + + out.push(( + cur_path, + quote! { + pub trait Future { + type Output; + + #[custom_impl( + // Types within the C interface other than self and additional wrappers. + { + cx: &#crate_path::task::FastCWaker, + out: &mut ::core::mem::MaybeUninit, + }, + // Unwrapped return type + bool, + // Conversion in trait impl to C arguments (signature names are expected). + { + let mut out_v = ::core::mem::MaybeUninit::uninit(); + let out = &mut out_v; + let cx = #crate_path::task::FastCWaker::from(cx.waker()); + let cx = &cx; + }, + // This is the body of C impl minus the automatic wrapping. + { + cx.with_waker(|waker| { + let mut cx = ::core::task::Context::from_waker(waker); + match this.poll(&mut cx) { + ::core::task::Poll::Ready(v) => { + out.write(v); + true + } + _ => false + } + }) + }, + // This part is processed in the trait impl after the call returns (impl_func_ret). + { + if ret { + ::core::task::Poll::Ready(unsafe { out_v.assume_init() }) + } else { + ::core::task::Poll::Pending + } + }, + )] + fn poll(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context) -> ::core::task::Poll; + } + }, + )); +} + +pub fn get_exports(parent_path: &Path, exports: &mut HashMap) { + let cur_path = super::super::join_paths(parent_path, format_ident!("future")); + exports.insert(format_ident!("Future"), cur_path); +} diff --git a/cglue-gen/src/ext/core/mod.rs b/cglue-gen/src/ext/core/mod.rs index 241b2ad..4404d01 100644 --- a/cglue-gen/src/ext/core/mod.rs +++ b/cglue-gen/src/ext/core/mod.rs @@ -1,6 +1,7 @@ pub mod clone; pub mod convert; pub mod fmt; +pub mod future; use proc_macro2::TokenStream; use quote::format_ident; @@ -12,6 +13,8 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { clone::get_impl(&cur_path, out); fmt::get_impl(&cur_path, out); convert::get_impl(&cur_path, out); + #[cfg(feature = "task")] + future::get_impl(&cur_path, out); } pub fn get_exports(parent_path: &Path, exports: &mut HashMap) { @@ -19,4 +22,6 @@ pub fn get_exports(parent_path: &Path, exports: &mut HashMap) { clone::get_exports(&cur_path, exports); fmt::get_exports(&cur_path, exports); convert::get_exports(&cur_path, exports); + #[cfg(feature = "task")] + future::get_exports(&cur_path, exports); } diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index c13f520..468e367 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -302,6 +302,28 @@ impl TraitArgConv { ) } } + t if recv_pin(t) => { + let lifetime = inject_lifetime.or_else(|| recv_lifetime(t)); + let lifetime_cast = inject_lifetime_cast.or_else(|| recv_lifetime(t)); + + if recv_mutable(t) { + ( + quote!(let cont = self.ccont_pin_mut();), + quote!(cont,), + quote!(cont: ::core::pin::Pin<&#lifetime mut CGlueC>,), + quote!(cont: ::core::pin::Pin<&#lifetime_cast mut CGlueC>,), + quote!(), + ) + } else { + ( + quote!(let cont = self.ccont_pin_ref();), + quote!(cont,), + quote!(cont: ::core::pin::Pin<&#lifetime CGlueC>,), + quote!(cont: ::core::pin::Pin<&#lifetime_cast CGlueC>,), + quote!(), + ) + } + } FnArg::Typed(t) => { let mut t = t.clone(); let _old = do_wrap_type(&mut t.ty, targets); @@ -481,7 +503,7 @@ pub struct ParsedFunc { trait_name: Ident, safe: bool, abi: FuncAbi, - receiver: Receiver, + receiver: FnArg, orig_args: Vec, args: Vec, out: ParsedReturnType, @@ -491,6 +513,65 @@ pub struct ParsedFunc { only_c_side: bool, } +fn extract_pin(t: &Type) -> Option<&Type> { + if let Type::Path(v) = t { + if let Some(seg) = v.path.segments.last() { + if seg.ident != "Pin" { + return None; + } + if let PathArguments::AngleBracketed(a) = &seg.arguments { + if a.args.len() == 1 { + let a = a.args.first()?; + if let GenericArgument::Type(t) = a { + return Some(t); + } + } + } + } + } + None +} + +fn recv_pin(recv: &FnArg) -> bool { + match recv { + FnArg::Receiver(_) => false, + FnArg::Typed(t) => matches!(extract_pin(&t.ty), Some(Type::Reference(_))), + } +} + +fn recv_lifetime(recv: &FnArg) -> Option<&Lifetime> { + match recv { + FnArg::Receiver(r) => r.lifetime(), + FnArg::Typed(t) => { + if let Some(Type::Reference(r)) = extract_pin(&t.ty) { + r.lifetime.as_ref() + } else { + None + } + } + } +} + +fn recv_reference(recv: &FnArg) -> bool { + match recv { + FnArg::Receiver(r) => r.reference.is_some(), + FnArg::Typed(t) => matches!(extract_pin(&t.ty), Some(Type::Reference(_))), + } +} + +fn recv_mutable(recv: &FnArg) -> bool { + match recv { + FnArg::Receiver(r) => r.mutability.is_some(), + FnArg::Typed(t) => matches!( + extract_pin(&t.ty), + Some(Type::Reference(TypeReference { + mutability: Some(_), + .. + })) + ), + } +} + impl ParsedFunc { #[allow(clippy::too_many_arguments)] pub fn new( @@ -515,8 +596,17 @@ impl ParsedFunc { let unsafety = if safe { quote!(unsafe) } else { quote!() }; for input in sig.inputs.iter() { - if let FnArg::Receiver(r) = &input { - receiver = Some(r.clone()); + match &input { + FnArg::Receiver(_) => { + receiver = Some(input.clone()); + } + FnArg::Typed(v) => { + if let Pat::Ident(ref i) = *v.pat { + if i.ident == "self" { + receiver = Some(input.clone()); + } + } + } } } @@ -545,7 +635,17 @@ impl ParsedFunc { // But first, we need to process the receiver (self) type, as it is implicit. for arg in orig_args .iter() - .filter(|a| matches!(a, FnArg::Receiver(_))) + .filter(|a| match a { + FnArg::Receiver(_) => true, + FnArg::Typed(v) => { + if let Pat::Ident(ref i) = *v.pat { + if i.ident == "self" { + return true; + } + } + false + } + }) .take(1) .chain(tys.iter()) { @@ -612,7 +712,7 @@ impl ParsedFunc { .as_ref() .or(self.out.injected_ret_tmp.as_ref()), ) { - let gen = if self.receiver.mutability.is_some() { + let gen = if recv_mutable(&self.receiver) { quote!(#name: ::core::mem::MaybeUninit<#ty>,) } else { quote!(#name: ::core::cell::Cell<::core::mem::MaybeUninit<#ty>>,) @@ -624,7 +724,7 @@ impl ParsedFunc { pub fn ret_default_def(&self, stream: &mut TokenStream) { let name = &self.name; if self.out.injected_ret_tmp.is_some() { - let gen = if self.receiver.mutability.is_some() { + let gen = if recv_mutable(&self.receiver) { quote!(#name: ::core::mem::MaybeUninit::uninit(),) } else { quote!(#name: ::core::cell::Cell::new(::core::mem::MaybeUninit::uninit()),) @@ -637,8 +737,8 @@ impl ParsedFunc { let name = &self.name; if let Some(ty) = &self.out.injected_ret_tmp { - let gen = match (&self.out.lifetime, &self.receiver.mutability) { - (Some(lt), Some(_)) => { + let gen = match (&self.out.lifetime, recv_mutable(&self.receiver)) { + (Some(lt), true) => { quote! { fn #name<#lt>(&#lt mut self) -> &#lt mut ::core::mem::MaybeUninit<#ty> { // SAFETY: @@ -649,14 +749,14 @@ impl ParsedFunc { } } } - (None, Some(_)) => { + (None, true) => { quote! { fn #name(&mut self) -> &mut ::core::mem::MaybeUninit<#ty> { &mut self.#name } } } - (Some(lt), None) => { + (Some(lt), false) => { quote! { #[allow(clippy::mut_from_ref)] fn #name<#lt>(&#lt self) -> &#lt mut ::core::mem::MaybeUninit<#ty> { @@ -674,7 +774,7 @@ impl ParsedFunc { } } } - (None, None) => { + (None, false) => { quote! { #[allow(clippy::mut_from_ref)] fn #name(&self) -> &mut ::core::mem::MaybeUninit<#ty> { @@ -990,7 +1090,7 @@ impl ParsedFunc { let mut container_bound = quote!(); - let (c_pre_call, cglue_c_into_inner) = if self.receiver.reference.is_none() { + let (c_pre_call, cglue_c_into_inner) = if !recv_reference(&self.receiver) { container_bound.extend(quote!(#trg_path::CGlueObjBase + )); ( @@ -1003,20 +1103,30 @@ impl ParsedFunc { CGlueC::InstType: #trg_path::IntoInner, )), ) - } else if self.receiver.mutability.is_some() { + } else if recv_mutable(&self.receiver) { + let cobj_func = if recv_pin(&self.receiver) { + quote!(cobj_pin_mut) + } else { + quote!(cobj_mut) + }; container_bound.extend(quote!(#trg_path::CGlueObjMut<#ret_tmp, Context = CGlueCtx> + )); ( quote! { - let (this, ret_tmp, cglue_ctx) = cont.cobj_mut(); + let (this, ret_tmp, cglue_ctx) = cont.#cobj_func(); #c_pre_call }, None, ) } else { + let cobj_func = if recv_pin(&self.receiver) { + quote!(cobj_pin_ref) + } else { + quote!(cobj_ref) + }; container_bound.extend(quote!(#trg_path::CGlueObjRef<#ret_tmp, Context = CGlueCtx> + )); ( quote! { - let (this, ret_tmp, cglue_ctx) = cont.cobj_ref(); + let (this, ret_tmp, cglue_ctx) = cont.#cobj_func(); #c_pre_call }, None, @@ -1096,7 +1206,12 @@ impl ParsedFunc { }; let custom_precall_impl = self.custom_conv.pre_call_impl.to_token_stream(); - let custom_ret_impl = self.custom_conv.impl_func_ret.to_token_stream(); + + let impl_func_ret = if let Some(impl_func_ret) = &self.custom_conv.impl_func_ret { + impl_func_ret + } else { + impl_func_ret + }; let gen = quote! { #[inline(always)] @@ -1107,7 +1222,6 @@ impl ParsedFunc { #c_ret_precall_def let mut ret = __cglue_vfunc(#call_args #c_call_ret_args); #impl_func_ret - #custom_ret_impl } }; @@ -1115,14 +1229,14 @@ impl ParsedFunc { } ( - self.receiver.mutability.is_some(), - self.receiver.reference.is_none(), + recv_mutable(&self.receiver), + !recv_reference(&self.receiver), self.out.return_self, ) } pub fn forward_wrapped_trait_impl(&self, tokens: &mut TokenStream) -> bool { - if self.receiver.reference.is_none() { + if !recv_reference(&self.receiver) { return false; } @@ -1157,7 +1271,7 @@ impl ParsedFunc { tokens.extend(gen); - self.receiver.mutability.is_some() + recv_mutable(&self.receiver) } pub fn arc_wrapped_trait_impl(&self, tokens: &mut TokenStream) { @@ -1176,9 +1290,9 @@ impl ParsedFunc { .. } = &self.sig_generics; - let get_inner = if self.receiver.reference.is_none() { + let get_inner = if !recv_reference(&self.receiver) { quote!(self.into_inner()) - } else if self.receiver.mutability.is_some() { + } else if recv_mutable(&self.receiver) { quote!(self.as_mut()) } else { quote!(self.as_ref()) @@ -1323,7 +1437,7 @@ impl ParsedReturnType { res_override: Option<&Ident>, int_result: bool, unsafety: &TokenStream, - (func_name, receiver): (&Ident, &Receiver), + (func_name, receiver): (&Ident, &FnArg), (crate_path, trait_name, trait_generics): (&TokenStream, &Ident, &ParsedGenerics), ) -> Self { let mut c_ty = c_override.unwrap_or(&ty).clone(); @@ -1354,6 +1468,8 @@ impl ParsedReturnType { if let ReturnType::Type(_, ty) = &mut c_ty { let mut ty_cast = None; + // If this branch is hit (whenever ty includes any of the targets), then return type is + // replaced with c_ty. However, we need to do that regardless in custom impl. if let Some(wrapped) = ret_wrap_type(&mut *ty, targets) { let old_ty = wrapped.0; let trait_ty = wrapped.1; @@ -1492,7 +1608,7 @@ impl ParsedReturnType { _ => (None, quote!()), }; - let c_pre_call = if receiver.reference.is_some() { + let c_pre_call = if recv_reference(receiver) { quote!(#c_pre_call let cglue_ctx = cglue_ctx.clone();) } else { c_pre_call @@ -1530,6 +1646,8 @@ impl ParsedReturnType { ret.use_wrap = true; ret.lifetime = lifetime; ret.lifetime_cast = lifetime_cast; + } else { + ret.c_out = quote!(-> #ty); } match &mut **ty { diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index 5333438..02e98e2 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -1561,13 +1561,19 @@ impl TraitGroup { let ext_name = format_ident!("{}Ext", raw_ident); - let (funcs, _, _, _) = super::traits::parse_trait( + let (funcs, _, (_, assoc_idents, _), _) = super::traits::parse_trait( tr_info, crate_path, false, super::traits::process_item, ); + for a in &assoc_idents { + impls.extend( + quote!(type #a = >::#a;), + ); + } + for func in &funcs { func.int_trait_impl(Some(ext_path), &ext_name, &mut impls); } diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index b91849d..688a4f8 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -535,7 +535,7 @@ pub fn parse_trait( ) -> ( Vec, ParsedGenerics, - (ParsedGenerics, TokenStream), + (ParsedGenerics, Vec, TokenStream), TokenStream, ) { let mut funcs = vec![]; @@ -718,6 +718,8 @@ pub fn parse_trait( // = CGlueA, = CGlueA, ... let mut equality = TokenStream::new(); + let mut assoc_vec = vec![]; + // TODO: please, make this cleaner without reparsing tokens. for (t, mut b) in assocs { let t = t.ident; @@ -731,9 +733,10 @@ pub fn parse_trait( } tokens.extend(quote!(#ident: #b)) } + assoc_vec.push(t); } - (parse2(quote!(<#tokens>)).unwrap(), equality) + (parse2(quote!(<#tokens>)).unwrap(), assoc_vec, equality) }; (funcs, generics, assoc_types, trait_type_defs) @@ -784,7 +787,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { let opaque_ctx_ref_trait_obj_ident = format_ident!("{}CtxRef", trait_name); let opaque_arc_ref_trait_obj_ident = format_ident!("{}ArcRef", trait_name); - let (funcs, generics, (assocs, assoc_equality), trait_type_defs) = + let (funcs, generics, (assocs, assoc_idents, assoc_equality), trait_type_defs) = parse_trait(&tr, &crate_path, true, process_item); let cglue_c_opaque_bound = cglue_c_opaque_bound(); @@ -960,6 +963,10 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { let internal_trait_impl = if let Some(ext_name) = ext_name { let mut impls = TokenStream::new(); + for a in &assoc_idents { + impls.extend(quote!(type #a = >::#a;)); + } + for func in &funcs { func.int_trait_impl(None, ext_name, &mut impls); } diff --git a/cglue-macro/Cargo.toml b/cglue-macro/Cargo.toml index acdc4fb..54bfbf2 100644 --- a/cglue-macro/Cargo.toml +++ b/cglue-macro/Cargo.toml @@ -25,3 +25,4 @@ default = [] rust_void = ["cglue-gen/rust_void"] unstable = ["cglue-gen/unstable"] layout_checks = ["cglue-gen/layout_checks"] +task = ["cglue-gen/task"] diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index e57b1a8..639b120 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -23,13 +23,16 @@ tarc = { version = "0.1", default-features = false } [build-dependencies] rustc_version = "0.4" +[dev-dependencies] +pollster = "0.1" + [features] default = ["std"] std = ["no-std-compat/std", "tarc/std"] rust_void = ["cglue-macro/rust_void"] unstable = ["cglue-macro/unstable", "try_default"] -task_unstable = [] +task = ["cglue-macro/task"] layout_checks = ["cglue-macro/layout_checks", "abi_stable"] [package.metadata.docs.rs] -features = ["std", "task_unstable"] +features = ["std", "task"] diff --git a/cglue/src/lib.rs b/cglue/src/lib.rs index 91e4b15..1ce06ee 100644 --- a/cglue/src/lib.rs +++ b/cglue/src/lib.rs @@ -1007,8 +1007,8 @@ pub mod trait_group; pub mod tuple; pub mod vec; -#[cfg(feature = "task_unstable")] -#[cfg_attr(docsrs, doc(cfg(feature = "task_unstable")))] +#[cfg(feature = "task")] +#[cfg_attr(docsrs, doc(cfg(feature = "task")))] pub mod task; pub use ::cglue_macro::{ diff --git a/cglue/src/task/sound.rs b/cglue/src/task/sound.rs index 09e3d1d..1f2bd58 100644 --- a/cglue/src/task/sound.rs +++ b/cglue/src/task/sound.rs @@ -214,6 +214,7 @@ impl<'a> FastCWaker<'a> { unsafe fn unreach(_: *const ()) { unreachable!() } + unsafe fn noop(_: *const ()) {} unsafe fn clone(data: *const ()) -> RawWaker { let this = &*(data as *const FastCWaker); CWaker::into_raw_waker(this.c_waker()) @@ -245,7 +246,7 @@ impl<'a> FastCWaker<'a> { adapter(data, wake as _) } - let vtbl = &RawWakerVTable::new(clone, unreach, wake_by_ref, unreach); + let vtbl = &RawWakerVTable::new(clone, unreach, wake_by_ref, noop); let waker = RawWaker::new(self as *const Self as *const (), vtbl); let waker = unsafe { Waker::from_raw(waker) }; diff --git a/cglue/src/tests/ext/future.rs b/cglue/src/tests/ext/future.rs new file mode 100644 index 0000000..effcdde --- /dev/null +++ b/cglue/src/tests/ext/future.rs @@ -0,0 +1,17 @@ +use cglue_macro::*; + +#[test] +fn use_future() { + async fn hii() -> u64 { + 42 + } + + let obj = trait_obj!(hii() as Future); + + impl_future(&obj); + + assert_eq!(pollster::block_on(obj), 42); +} + +#[cfg(test)] +fn impl_future(_: &impl ::core::future::Future) {} diff --git a/cglue/src/tests/ext/mod.rs b/cglue/src/tests/ext/mod.rs index 493d331..9686409 100644 --- a/cglue/src/tests/ext/mod.rs +++ b/cglue/src/tests/ext/mod.rs @@ -1,3 +1,5 @@ pub mod as_ref; pub mod clone; pub mod fmt; +#[cfg(feature = "task")] +pub mod future; diff --git a/cglue/src/tests/simple/trait_defs.rs b/cglue/src/tests/simple/trait_defs.rs index 3b7e7b7..f9e4980 100644 --- a/cglue/src/tests/simple/trait_defs.rs +++ b/cglue/src/tests/simple/trait_defs.rs @@ -31,4 +31,5 @@ pub trait TT { #[cglue_trait] pub trait TF { unsafe fn tf_1(&self); + fn tf_2(self: core::pin::Pin<&Self>); } diff --git a/cglue/src/trait_group.rs b/cglue/src/trait_group.rs index 6f32ff8..c69fa4a 100644 --- a/cglue/src/trait_group.rs +++ b/cglue/src/trait_group.rs @@ -8,6 +8,7 @@ use crate::boxed::CBox; use abi_stable::{abi_stability::check_layout_compatibility, type_layout::TypeLayout}; use core::mem::ManuallyDrop; use core::ops::{Deref, DerefMut}; +use core::pin::Pin; #[cfg(feature = "rust_void")] #[allow(non_camel_case_types)] pub type c_void = (); @@ -333,6 +334,12 @@ pub trait CGlueObjBase { pub trait CGlueObjRef: CGlueObjBase { fn cobj_ref(&self) -> (&Self::ObjType, &R, &Self::Context); + + fn cobj_pin_ref(self: Pin<&Self>) -> (Pin<&Self::ObjType>, &R, &Self::Context) { + let this = self.get_ref(); + let (a, b, c) = this.cobj_ref(); + (unsafe { Pin::new_unchecked(a) }, b, c) + } } impl, F, C: ContextBounds, R> CGlueObjBase for CGlueObjContainer { @@ -360,6 +367,12 @@ impl, F, C: ContextBounds, R> CGlueObjRef for CGlueObjCo /// This trait allows to retrieve the mutable `this` pointer on the structure. pub trait CGlueObjMut: CGlueObjRef { fn cobj_mut(&mut self) -> (&mut Self::ObjType, &mut R, &Self::Context); + + fn cobj_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut Self::ObjType>, &mut R, &Self::Context) { + let this = unsafe { self.get_unchecked_mut() }; + let (a, b, c) = this.cobj_mut(); + (unsafe { Pin::new_unchecked(a) }, b, c) + } } impl + DerefMut, F, C: ContextBounds, R> CGlueObjMut @@ -377,6 +390,14 @@ pub trait GetContainer { fn ccont_mut(&mut self) -> &mut Self::ContType; fn into_ccont(self) -> Self::ContType; fn build_with_ccont(&self, container: Self::ContType) -> Self; + + fn ccont_pin_ref(self: Pin<&Self>) -> Pin<&Self::ContType> { + unsafe { self.map_unchecked(Self::ccont_ref) } + } + + fn ccont_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Self::ContType> { + unsafe { self.map_unchecked_mut(Self::ccont_mut) } + } } impl, F, V, C: ContextBounds, R> GetContainer From 3e8e147e547fcbde19de8303935a3e747700aaef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Fri, 21 Jun 2024 19:44:02 +0100 Subject: [PATCH 27/41] Update README --- README.md | 27 +++++++++++++++------------ cglue/src/lib.rs | 22 +++++++++++++--------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index eed3590..f90fc1f 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ If all code is glued together, our glue is the safest on the market. -## FFI-safe trait generation, helper structures, and more! +## The most complete dynamic trait object implementation, period. - [Overview](#overview) @@ -41,8 +41,9 @@ If all code is glued together, our glue is the safest on the market. ## Overview -CGlue bridges Rust traits between C and other languages. It aims to be seamless to integrate - -just add a few annotations around your traits, and they should be good to go! +CGlue exposes `dyn Trait` in FFI-safe manner. It bridges Rust traits between C and other +languages. It aims to be seamless to integrate - just add a few annotations around your traits, +and they should be good to go! ```rust use cglue::*; @@ -50,7 +51,8 @@ use cglue::*; // One annotation for the trait. #[cglue_trait] pub trait InfoPrinter { - fn print_info(&self); + type Mark; + fn print_info(&self, mark: Self::Mark); } struct Info { @@ -58,14 +60,16 @@ struct Info { } impl InfoPrinter for Info { - fn print_info(&self) { - println!("Info struct: {}", self.value); + type Mark = u8; + + fn print_info(&self, mark: Self::Mark) { + println!("{} - info struct: {}", mark, self.value); } } -fn use_info_printer(printer: &impl InfoPrinter) { +fn use_info_printer(printer: &T, mark: T::Mark) { println!("Printing info:"); - printer.print_info(); + printer.print_info(mark); } fn main() -> () { @@ -76,7 +80,7 @@ fn main() -> () { // Here, the object is fully opaque, and is FFI and ABI safe. let obj = trait_obj!(&mut info as InfoPrinter); - use_info_printer(&obj); + use_info_printer(&obj, 42); } ``` @@ -331,7 +335,8 @@ impl< > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, T> for GA where Self: TA, - &'cglue_a TAVtbl<'cglue_a, GenGroupContainer>: + &'cglue_a TAVtbl<'cglue_a, GenGroupContainer, + >: 'cglue_a + Default, T: cglue::trait_group::GenericTypeBounds, { @@ -739,5 +744,3 @@ If you want your project to be added to the list, please open an issue report :) It is available in [CHANGELOG.md](https://github.com/h33p/cglue/blob/main/CHANGELOG.md) file. - -License: MIT diff --git a/cglue/src/lib.rs b/cglue/src/lib.rs index 1ce06ee..f8d7fb6 100644 --- a/cglue/src/lib.rs +++ b/cglue/src/lib.rs @@ -16,7 +16,7 @@ //! //! If all code is glued together, our glue is the safest on the market. //! -//! ## FFI-safe trait generation, helper structures, and more! +//! ## The most complete dynamic trait object implementation, period. //! //! //! - [Overview](#overview) @@ -41,8 +41,9 @@ //! //! ## Overview //! -//! CGlue bridges Rust traits between C and other languages. It aims to be seamless to integrate - -//! just add a few annotations around your traits, and they should be good to go! +//! CGlue exposes `dyn Trait` in FFI-safe manner. It bridges Rust traits between C and other +//! languages. It aims to be seamless to integrate - just add a few annotations around your traits, +//! and they should be good to go! //! //! ```rust //! use cglue::*; @@ -50,7 +51,8 @@ //! // One annotation for the trait. //! #[cglue_trait] //! pub trait InfoPrinter { -//! fn print_info(&self); +//! type Mark; +//! fn print_info(&self, mark: Self::Mark); //! } //! //! struct Info { @@ -58,14 +60,16 @@ //! } //! //! impl InfoPrinter for Info { -//! fn print_info(&self) { -//! println!("Info struct: {}", self.value); +//! type Mark = u8; +//! +//! fn print_info(&self, mark: Self::Mark) { +//! println!("{} - info struct: {}", mark, self.value); //! } //! } //! -//! fn use_info_printer(printer: &impl InfoPrinter) { +//! fn use_info_printer(printer: &T, mark: T::Mark) { //! println!("Printing info:"); -//! printer.print_info(); +//! printer.print_info(mark); //! } //! //! fn main() -> () { @@ -76,7 +80,7 @@ //! // Here, the object is fully opaque, and is FFI and ABI safe. //! let obj = trait_obj!(&mut info as InfoPrinter); //! -//! use_info_printer(&obj); +//! use_info_printer(&obj, 42); //! } //! ``` //! From 95bda810c292f07fabb0f16ce583625a965765a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Wed, 24 Jul 2024 19:58:56 +0100 Subject: [PATCH 28/41] Explicitly set C++ in makefiles --- examples/cpp-plugin-lib/Makefile | 2 +- examples/cpp-user-bin/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/cpp-plugin-lib/Makefile b/examples/cpp-plugin-lib/Makefile index 1fae407..5e25483 100644 --- a/examples/cpp-plugin-lib/Makefile +++ b/examples/cpp-plugin-lib/Makefile @@ -8,7 +8,7 @@ bindings: sh ./bindgen.sh %.o: %.cpp $(DEPS) bindings - $(CC) -c -o $@ $< $(CFLAGS) + $(CC) -c -xc++ -o $@ $< $(CFLAGS) libplugin_cpp.so: main.o cargo build --release diff --git a/examples/cpp-user-bin/Makefile b/examples/cpp-user-bin/Makefile index 4dcd0d5..af5ade6 100644 --- a/examples/cpp-user-bin/Makefile +++ b/examples/cpp-user-bin/Makefile @@ -8,7 +8,7 @@ bindings: sh ./bindgen.sh %.o: %.cpp $(DEPS) bindings - $(CC) -c -o $@ $< $(CFLAGS) + $(CC) -c -xc++ -o $@ $< $(CFLAGS) main.out: main.o cargo build --release From 2d917012db0caa738eb70a89cb1c16f3ec622fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Wed, 24 Jul 2024 20:02:23 +0100 Subject: [PATCH 29/41] Fix #17 --- cglue/src/vec.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/cglue/src/vec.rs b/cglue/src/vec.rs index 225dd6a..640792b 100644 --- a/cglue/src/vec.rs +++ b/cglue/src/vec.rs @@ -97,8 +97,21 @@ impl CVec { self.len += 1; } + /// Insert into the vector + /// + /// # Examples + /// + /// ``` + /// use cglue::vec::CVec; + /// + /// let a: Vec = vec![1, 2, 3]; + /// let mut cvec = CVec::from(a); + /// cvec.insert(1, 2); + /// + /// assert_eq!(&cvec[..], &[1, 2, 2, 3]); + /// ``` pub fn insert(&mut self, index: usize, element: T) { - assert!(index > self.len); + assert!(index <= self.len); self.reserve(1); unsafe { @@ -124,8 +137,21 @@ impl CVec { } } + /// Insert into the vector + /// + /// # Examples + /// + /// ``` + /// use cglue::vec::CVec; + /// + /// let a: Vec = vec![1, 2, 3]; + /// let mut cvec = CVec::from(a); + /// cvec.remove(1); + /// + /// assert_eq!(&cvec[..], &[1, 3]); + /// ``` pub fn remove(&mut self, index: usize) -> T { - assert!(index >= self.len); + assert!(index < self.len); unsafe { let ptr = self.data.add(index); From 609bc203fb4a96541a64be1a8098b9e93a631e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Wed, 24 Jul 2024 21:22:04 +0100 Subject: [PATCH 30/41] Integrate futures streams+sinks --- Cargo.lock | 74 +++++++++++ cglue-gen/Cargo.toml | 1 + cglue-gen/src/ext/futures/mod.rs | 19 +++ cglue-gen/src/ext/futures/sink.rs | 185 ++++++++++++++++++++++++++++ cglue-gen/src/ext/futures/stream.rs | 66 ++++++++++ cglue-gen/src/ext/mod.rs | 6 + cglue-macro/Cargo.toml | 1 + cglue/Cargo.toml | 4 +- cglue/src/lib.rs | 3 + cglue/src/tests/ext/futures.rs | 50 ++++++++ cglue/src/tests/ext/mod.rs | 2 + 11 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 cglue-gen/src/ext/futures/mod.rs create mode 100644 cglue-gen/src/ext/futures/sink.rs create mode 100644 cglue-gen/src/ext/futures/stream.rs create mode 100644 cglue/src/tests/ext/futures.rs diff --git a/Cargo.lock b/Cargo.lock index e347baf..bbe4777 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,6 +94,7 @@ version = "0.2.14" dependencies = [ "abi_stable", "cglue-macro", + "futures", "log", "no-std-compat", "pollster", @@ -176,6 +177,67 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", +] + [[package]] name = "generational-arena" version = "0.2.9" @@ -312,6 +374,18 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "plugin-api" version = "0.1.0" diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index ca0afac..1e05408 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -25,3 +25,4 @@ rust_void = [] unstable = [] layout_checks = [] task = [] +futures = ["task"] diff --git a/cglue-gen/src/ext/futures/mod.rs b/cglue-gen/src/ext/futures/mod.rs new file mode 100644 index 0000000..5aa8e58 --- /dev/null +++ b/cglue-gen/src/ext/futures/mod.rs @@ -0,0 +1,19 @@ +pub mod sink; +pub mod stream; + +use proc_macro2::TokenStream; +use quote::format_ident; +use std::collections::HashMap; +use syn::{Ident, Path}; + +pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { + let cur_path = super::join_paths(parent_path, format_ident!("futures")); + stream::get_impl(&cur_path, out); + sink::get_impl(&cur_path, out); +} + +pub fn get_exports(parent_path: &Path, exports: &mut HashMap) { + let cur_path = super::join_paths(parent_path, format_ident!("futures")); + stream::get_exports(&cur_path, exports); + sink::get_exports(&cur_path, exports); +} diff --git a/cglue-gen/src/ext/futures/sink.rs b/cglue-gen/src/ext/futures/sink.rs new file mode 100644 index 0000000..7b15558 --- /dev/null +++ b/cglue-gen/src/ext/futures/sink.rs @@ -0,0 +1,185 @@ +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use std::collections::HashMap; +use syn::{Ident, Path}; + +pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { + let cur_path = super::super::join_paths(parent_path, format_ident!("sink")); + + let crate_path = crate::util::crate_path(); + + out.push(( + cur_path, + quote! { + pub trait Sink { + type Error; + + #[custom_impl( + // Types within the C interface other than self and additional wrappers. + { + cx: &#crate_path::task::FastCWaker, + out: &mut ::core::mem::MaybeUninit, + }, + // Unwrapped return type + u8, + // Conversion in trait impl to C arguments (signature names are expected). + { + let mut out_v = ::core::mem::MaybeUninit::uninit(); + let out = &mut out_v; + let cx = #crate_path::task::FastCWaker::from(cx.waker()); + let cx = &cx; + }, + // This is the body of C impl minus the automatic wrapping. + { + cx.with_waker(|waker| { + let mut cx = ::core::task::Context::from_waker(waker); + match this.poll_ready(&mut cx) { + ::core::task::Poll::Ready(Ok(())) => 1, + ::core::task::Poll::Ready(Err(e)) => { + out.write(e); + 2 + } + _ => 0 + } + }) + }, + // This part is processed in the trait impl after the call returns (impl_func_ret). + { + if ret == 1 { + ::core::task::Poll::Ready(Ok(())) + } else if ret == 2 { + ::core::task::Poll::Ready(Err(unsafe { out_v.assume_init() })) + } else { + ::core::task::Poll::Pending + } + }, + )] + fn poll_ready(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context) -> ::core::task::Poll>; + + #[custom_impl( + // Types within the C interface other than self and additional wrappers. + { + item: Item, + out: &mut ::core::mem::MaybeUninit, + }, + // Unwrapped return type + u8, + // Conversion in trait impl to C arguments (signature names are expected). + { + let mut out_v = ::core::mem::MaybeUninit::uninit(); + let out = &mut out_v; + }, + // This is the body of C impl minus the automatic wrapping. + { + match this.start_send(item) { + Ok(()) => 0, + Err(e) => { + out.write(e); + 1 + } + } + }, + // This part is processed in the trait impl after the call returns (impl_func_ret). + { + if ret == 0 { + Ok(()) + } else { + Err(unsafe { out_v.assume_init() }) + } + }, + )] + fn start_send(self: ::core::pin::Pin<&mut Self>, item: Item) -> Result<(), Self::Error>; + + #[custom_impl( + // Types within the C interface other than self and additional wrappers. + { + cx: &#crate_path::task::FastCWaker, + out: &mut ::core::mem::MaybeUninit, + }, + // Unwrapped return type + u8, + // Conversion in trait impl to C arguments (signature names are expected). + { + let mut out_v = ::core::mem::MaybeUninit::uninit(); + let out = &mut out_v; + let cx = #crate_path::task::FastCWaker::from(cx.waker()); + let cx = &cx; + }, + // This is the body of C impl minus the automatic wrapping. + { + cx.with_waker(|waker| { + let mut cx = ::core::task::Context::from_waker(waker); + match this.poll_flush(&mut cx) { + ::core::task::Poll::Ready(Ok(())) => 1, + ::core::task::Poll::Ready(Err(e)) => { + out.write(e); + 2 + } + _ => 0 + } + }) + }, + // This part is processed in the trait impl after the call returns (impl_func_ret). + { + if ret == 1 { + ::core::task::Poll::Ready(Ok(())) + } else if ret == 2 { + ::core::task::Poll::Ready(Err(unsafe { out_v.assume_init() })) + } else { + ::core::task::Poll::Pending + } + }, + )] + fn poll_flush(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context) -> ::core::task::Poll>; + + #[custom_impl( + // Types within the C interface other than self and additional wrappers. + { + cx: &#crate_path::task::FastCWaker, + out: &mut ::core::mem::MaybeUninit, + }, + // Unwrapped return type + u8, + // Conversion in trait impl to C arguments (signature names are expected). + { + let mut out_v = ::core::mem::MaybeUninit::uninit(); + let out = &mut out_v; + let cx = #crate_path::task::FastCWaker::from(cx.waker()); + let cx = &cx; + }, + // This is the body of C impl minus the automatic wrapping. + { + cx.with_waker(|waker| { + let mut cx = ::core::task::Context::from_waker(waker); + match this.poll_close(&mut cx) { + ::core::task::Poll::Ready(Ok(())) => 1, + ::core::task::Poll::Ready(Err(e)) => { + out.write(e); + 2 + } + _ => 0 + } + }) + }, + // This part is processed in the trait impl after the call returns (impl_func_ret). + { + if ret == 1 { + ::core::task::Poll::Ready(Ok(())) + } else if ret == 2 { + ::core::task::Poll::Ready(Err(unsafe { out_v.assume_init() })) + } else { + ::core::task::Poll::Pending + } + }, + )] + fn poll_close(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context) -> ::core::task::Poll>; + + } + }, + )); +} + +pub fn get_exports(parent_path: &Path, exports: &mut HashMap) { + let cur_path = super::super::join_paths(parent_path, format_ident!("sink")); + exports.insert(format_ident!("Sink"), cur_path); +} diff --git a/cglue-gen/src/ext/futures/stream.rs b/cglue-gen/src/ext/futures/stream.rs new file mode 100644 index 0000000..9069304 --- /dev/null +++ b/cglue-gen/src/ext/futures/stream.rs @@ -0,0 +1,66 @@ +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use std::collections::HashMap; +use syn::{Ident, Path}; + +pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { + let cur_path = super::super::join_paths(parent_path, format_ident!("stream")); + + let crate_path = crate::util::crate_path(); + + out.push(( + cur_path, + quote! { + pub trait Stream { + type Item; + + #[custom_impl( + // Types within the C interface other than self and additional wrappers. + { + cx: &#crate_path::task::FastCWaker, + out: &mut ::core::mem::MaybeUninit, + }, + // Unwrapped return type + u8, + // Conversion in trait impl to C arguments (signature names are expected). + { + let mut out_v = ::core::mem::MaybeUninit::uninit(); + let out = &mut out_v; + let cx = #crate_path::task::FastCWaker::from(cx.waker()); + let cx = &cx; + }, + // This is the body of C impl minus the automatic wrapping. + { + cx.with_waker(|waker| { + let mut cx = ::core::task::Context::from_waker(waker); + match this.poll_next(&mut cx) { + ::core::task::Poll::Ready(Some(v)) => { + out.write(v); + 1 + } + ::core::task::Poll::Ready(None) => 2, + _ => 0 + } + }) + }, + // This part is processed in the trait impl after the call returns (impl_func_ret). + { + if ret == 1 { + ::core::task::Poll::Ready(Some(unsafe { out_v.assume_init() })) + } else if ret == 2 { + ::core::task::Poll::Ready(None) + } else { + ::core::task::Poll::Pending + } + }, + )] + fn poll_next(self: ::core::pin::Pin<&mut Self>, cx: &mut ::core::task::Context) -> ::core::task::Poll>; + } + }, + )); +} + +pub fn get_exports(parent_path: &Path, exports: &mut HashMap) { + let cur_path = super::super::join_paths(parent_path, format_ident!("stream")); + exports.insert(format_ident!("Stream"), cur_path); +} diff --git a/cglue-gen/src/ext/mod.rs b/cglue-gen/src/ext/mod.rs index ad30b4b..1abf5a8 100644 --- a/cglue-gen/src/ext/mod.rs +++ b/cglue-gen/src/ext/mod.rs @@ -1,4 +1,6 @@ pub mod core; +#[cfg(all(feature = "futures"))] +pub mod futures; use proc_macro2::TokenStream; use quote::{format_ident, quote}; @@ -17,6 +19,8 @@ pub fn get_exports() -> HashMap { ext_path.segments.push_punct(Default::default()); core::get_exports(&ext_path, &mut exports); + #[cfg(all(feature = "futures"))] + futures::get_exports(&ext_path, &mut exports); exports } @@ -28,6 +32,8 @@ pub fn get_store() -> HashMap<(Path, Ident), ItemTrait> { ext_path.segments.push_punct(Default::default()); core::get_impl(&ext_path, &mut token_list); + #[cfg(all(feature = "futures"))] + futures::get_impl(&ext_path, &mut token_list); let mut parsed_traits = HashMap::new(); diff --git a/cglue-macro/Cargo.toml b/cglue-macro/Cargo.toml index 54bfbf2..5afe802 100644 --- a/cglue-macro/Cargo.toml +++ b/cglue-macro/Cargo.toml @@ -26,3 +26,4 @@ rust_void = ["cglue-gen/rust_void"] unstable = ["cglue-gen/unstable"] layout_checks = ["cglue-gen/layout_checks"] task = ["cglue-gen/task"] +futures = ["cglue-gen/futures", "task"] diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 639b120..b240c4e 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -19,6 +19,7 @@ try_default = { version = "= 1.0.0", optional = true } abi_stable = { version = "0.10", optional = true } log = { version = "0.4", optional = true } tarc = { version = "0.1", default-features = false } +_futures = { package = "futures", version = "0.3", optional = true, default-features = false } [build-dependencies] rustc_version = "0.4" @@ -33,6 +34,7 @@ rust_void = ["cglue-macro/rust_void"] unstable = ["cglue-macro/unstable", "try_default"] task = ["cglue-macro/task"] layout_checks = ["cglue-macro/layout_checks", "abi_stable"] +futures = ["_futures", "task", "cglue-macro/futures"] [package.metadata.docs.rs] -features = ["std", "task"] +features = ["std", "task", "futures"] diff --git a/cglue/src/lib.rs b/cglue/src/lib.rs index f8d7fb6..6dbace9 100644 --- a/cglue/src/lib.rs +++ b/cglue/src/lib.rs @@ -997,6 +997,9 @@ #![cfg_attr(not(feature = "std"), no_std)] extern crate no_std_compat as std; +#[cfg(feature = "futures")] +extern crate _futures as futures; + pub mod arc; pub mod boxed; pub mod callback; diff --git a/cglue/src/tests/ext/futures.rs b/cglue/src/tests/ext/futures.rs new file mode 100644 index 0000000..36a4212 --- /dev/null +++ b/cglue/src/tests/ext/futures.rs @@ -0,0 +1,50 @@ +use cglue_macro::*; + +#[test] +fn use_stream() { + use futures::stream::StreamExt; + + let items = [42, 43, 42]; + + let obj = trait_obj!(futures::stream::iter(items) as Stream); + + impl_stream(&obj); + + assert_eq!(pollster::block_on(obj.collect::>()), items,); +} + +#[cfg(test)] +fn impl_stream(_: &impl ::futures::Stream) {} + +#[test] +fn use_sink() { + use futures::sink::SinkExt; + + let items = [42, 43, 42]; + + let sink = futures::sink::unfold(0, |idx, elem: i32| async move { + assert_eq!(elem, items[idx]); + Ok::<_, usize>(idx + 1) + }); + + let mut obj = trait_obj!(sink as Sink); + + impl_sink(&obj); + + pollster::block_on(async { + for i in items { + obj.send(i).await.unwrap(); + } + }); + + // The logic of the sink should force a panic afterwards + assert!( + std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || { + pollster::block_on(obj.send(0)) + })) + .is_err() + ); +} + +#[cfg(test)] +fn impl_sink(_: &impl ::futures::Sink) {} diff --git a/cglue/src/tests/ext/mod.rs b/cglue/src/tests/ext/mod.rs index 9686409..49cf92e 100644 --- a/cglue/src/tests/ext/mod.rs +++ b/cglue/src/tests/ext/mod.rs @@ -3,3 +3,5 @@ pub mod clone; pub mod fmt; #[cfg(feature = "task")] pub mod future; +#[cfg(feature = "futures")] +pub mod futures; From 023a828796bb4037c136c5e8afbe541b0381171d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Fri, 26 Jul 2024 15:36:00 +0100 Subject: [PATCH 31/41] Change macos version in workflows --- .github/workflows/build.yml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 020e5eb..74dc52a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,8 +12,11 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-11, ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest] toolchain: ["1.45.0", "stable"] + include: + - os: macos-14 + toolchain: "stable" steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -30,7 +33,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-12, ubuntu-latest, windows-latest] + os: [macos-14, ubuntu-latest, windows-latest] # 1.57 is needed for const panic # panic in const is used to verify waker layouts toolchain: ["1.57.0", "stable"] @@ -54,8 +57,11 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-11, ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest] toolchain: ["1.46.0", "stable"] + include: + - os: macos-14 + toolchain: "stable" steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -73,7 +79,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-11, ubuntu-latest, windows-latest] + os: [macos-14, ubuntu-latest, windows-latest] toolchain: ["1.57.0", "stable", "nightly-2021-11-05"] steps: - uses: actions/checkout@v2 @@ -114,8 +120,11 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-11, ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest] toolchain: ["1.45.0", "stable"] + include: + - os: macos-14 + toolchain: "stable" steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -130,7 +139,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-11, ubuntu-latest, windows-latest] + os: [macos-14, ubuntu-latest, windows-latest] toolchain: ["1.57.0", "stable", "nightly-2021-11-05"] steps: - uses: actions/checkout@v2 From 6702d29b249700d0c33080a359e3541e740f2697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Fri, 26 Jul 2024 16:00:06 +0100 Subject: [PATCH 32/41] Cleanup task module --- cglue/src/task/mod.rs | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/cglue/src/task/mod.rs b/cglue/src/task/mod.rs index a3cdabe..0f7d5fc 100644 --- a/cglue/src/task/mod.rs +++ b/cglue/src/task/mod.rs @@ -5,33 +5,13 @@ pub use sound::*; use core::task::*; -/// Actual type: unsafe fn(_: *const ()) -> RawWaker; -/// -/// However, we don't want to expose it since it's not ABI safe. -#[cfg(not(feature = "task_unsound"))] -type CloneFn = *const (); -#[cfg(feature = "task_unsound")] -type CloneFn = unsafe fn(_: *const ()) -> RawWaker; - -/// Actual type: unsafe fn(_: *const ()); -/// -/// However, we do not want to expose it since it's not ABI safe. -#[cfg(not(feature = "task_unsound"))] -type OtherFn = *const (); -#[cfg(feature = "task_unsound")] -type OtherFn = unsafe fn(_: *const ()); - #[repr(C)] #[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] -#[cfg_attr( - all(feature = "abi_stable", feature = "task_unsound"), - sabi(unsafe_opaque_fields) -)] pub struct CRawWakerVTable { - clone: CloneFn, - wake: OtherFn, - wake_by_ref: OtherFn, - drop: OtherFn, + clone: *const (), + wake: *const (), + wake_by_ref: *const (), + drop: *const (), } #[repr(transparent)] @@ -155,10 +135,10 @@ const _: () = { // Verify the layout of the vtable. - let clone: CloneFn = unsafe { transmute(1usize) }; - let wake: OtherFn = unsafe { transmute(2usize) }; - let wake_by_ref: OtherFn = unsafe { transmute(3usize) }; - let drop: OtherFn = unsafe { transmute(4usize) }; + let clone: *const () = unsafe { transmute(1usize) }; + let wake: *const () = unsafe { transmute(2usize) }; + let wake_by_ref: *const () = unsafe { transmute(3usize) }; + let drop: *const () = unsafe { transmute(4usize) }; let vtbl = unsafe { RawWakerVTable::new( From cc4bb18b9d40c3680e99e649da71f818f9210dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Sat, 27 Jul 2024 14:47:36 +0100 Subject: [PATCH 33/41] Cleanup, bump to 0.3, update CHANGELOG --- CHANGELOG.md | 62 ++++++++++++++++++++++++++++++++ Cargo.lock | 8 ++--- Cargo.toml | 22 ++++++------ cglue-bindgen/Cargo.toml | 2 +- cglue-gen/Cargo.toml | 2 +- cglue-gen/src/ext/mod.rs | 6 ++-- cglue-macro/Cargo.toml | 4 +-- cglue/Cargo.toml | 4 +-- cglue/src/task/mod.rs | 1 + cglue/src/tests/ext/futures.rs | 2 +- cglue/src/tests/extra/forward.rs | 1 + 11 files changed, 89 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3e3226..449a940 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,67 @@ # CGlue changelog +## Changes in 0.3.0: + +### [Stabilize `task` feature](https://github.com/h33p/cglue/blob/e6458ae5542daa489561495fb6c613307bb80001/cglue/src/task/mod.rs) + +Enable with `task` feature. Provides C equivalents for `Waker`, `RawWaker`, `RawWakerVtable`. + +### [Trait alias within trait groups](https://github.com/h33p/cglue/commit/35b0da5bdf6cfe6ecaeedf07ba795d618113477f) + +Enables specifying different generic instantiations of the same trait in the same group. Example: + +```rust +cglue_trait_group!(TestGroupGen, TT, { TT = TTUsize, TT = TTUSixtyFour }); +cglue_impl_group!(SA, TestGroupGen, { TT = TTUsize }); +``` + +### [Support traits with associated types](https://github.com/h33p/cglue/commit/5d26c373bd49e935dc65b4434bb6593e2109b8fc) + +The following now compiles: + +```rust +#[cglue_trait] +pub trait WithAssoc { + type AssocTy: Clone; + + fn with_assoc(&self, assoc: &Self::AssocTy) -> T; +} +``` + +### [Add Future support + Pin Self parameters](https://github.com/h33p/cglue/commit/6c1662a6db80390690361804626d31b72834ea3c) + +The following now works: + +```rust +async fn hii() -> u64 { + 42 +} + +let obj = trait_obj!(hii() as Future); + +assert_eq!(pollster::block_on(obj), 42); +``` + +### [Add futures Stream+Sink support](https://github.com/h33p/cglue/commit/609bc203fb4a96541a64be1a8098b9e93a631e4e) + +The following now works: + +```rust +let items = [42, 43, 42]; + +let obj = trait_obj!(futures::stream::iter(items) as Stream); + +assert_eq!(pollster::block_on(obj.collect::>()), items); +``` + +### [Fix #17](https://github.com/h33p/cglue/commit/2d917012db0caa738eb70a89cb1c16f3ec622fb6) + +## Changes in 0.2.14: + +[Add unstable task feature](https://github.com/h33p/cglue/commit/9fbee903963b1b407ca218609e43a65cfd1eb219) + +[Automatically wrap 'Into' arguments](https://github.com/h33p/cglue/commit/081c590f4eb97b1be10eaeaa9cbf87e7278ea8de) + ## Changes in 0.2.12: [Initial support for GAT lifetimes](https://github.com/h33p/cglue/commit/1a8098181896bb730d276aea59464d577e5d8927) diff --git a/Cargo.lock b/Cargo.lock index bbe4777..72207f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,7 +90,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cglue" -version = "0.2.14" +version = "0.3.0" dependencies = [ "abi_stable", "cglue-macro", @@ -106,7 +106,7 @@ dependencies = [ [[package]] name = "cglue-bindgen" -version = "0.2.3" +version = "0.3.0" dependencies = [ "itertools", "log", @@ -117,7 +117,7 @@ dependencies = [ [[package]] name = "cglue-gen" -version = "0.2.9" +version = "0.3.0" dependencies = [ "itertools", "lazy_static", @@ -129,7 +129,7 @@ dependencies = [ [[package]] name = "cglue-macro" -version = "0.2.3" +version = "0.3.0" dependencies = [ "cglue-gen", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index f38407b..87db28f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,21 +1,21 @@ [workspace] members = [ - "cglue", - "cglue-gen", - "cglue-macro", - "cglue-bindgen", - "examples/plugin-api", - "examples/plugin-lib", - "examples/user-bin", + "cglue", + "cglue-gen", + "cglue-macro", + "cglue-bindgen", + "examples/plugin-api", + "examples/plugin-lib", + "examples/user-bin", "version-hack" ] default-members = [ - "cglue", - "cglue-gen", - "cglue-macro", - "cglue-bindgen", + "cglue", + "cglue-gen", + "cglue-macro", + "cglue-bindgen", "version-hack", ] diff --git a/cglue-bindgen/Cargo.toml b/cglue-bindgen/Cargo.toml index 997e63e..567b191 100644 --- a/cglue-bindgen/Cargo.toml +++ b/cglue-bindgen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-bindgen" -version = "0.2.3" +version = "0.3.0" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" license = "MIT" diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index 1e05408..a7b51b2 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-gen" -version = "0.2.9" +version = "0.3.0" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe code generation for making plugins and C-compatible libraries" diff --git a/cglue-gen/src/ext/mod.rs b/cglue-gen/src/ext/mod.rs index 1abf5a8..a6db48b 100644 --- a/cglue-gen/src/ext/mod.rs +++ b/cglue-gen/src/ext/mod.rs @@ -1,5 +1,5 @@ pub mod core; -#[cfg(all(feature = "futures"))] +#[cfg(feature = "futures")] pub mod futures; use proc_macro2::TokenStream; @@ -19,7 +19,7 @@ pub fn get_exports() -> HashMap { ext_path.segments.push_punct(Default::default()); core::get_exports(&ext_path, &mut exports); - #[cfg(all(feature = "futures"))] + #[cfg(feature = "futures")] futures::get_exports(&ext_path, &mut exports); exports @@ -32,7 +32,7 @@ pub fn get_store() -> HashMap<(Path, Ident), ItemTrait> { ext_path.segments.push_punct(Default::default()); core::get_impl(&ext_path, &mut token_list); - #[cfg(all(feature = "futures"))] + #[cfg(feature = "futures")] futures::get_impl(&ext_path, &mut token_list); let mut parsed_traits = HashMap::new(); diff --git a/cglue-macro/Cargo.toml b/cglue-macro/Cargo.toml index 5afe802..320fbb6 100644 --- a/cglue-macro/Cargo.toml +++ b/cglue-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-macro" -version = "0.2.3" +version = "0.3.0" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe code generation macros for making plugins and C-compatible libraries" @@ -18,7 +18,7 @@ proc-macro = true syn = { version = "1", features = ["full", "extra-traits"] } proc-macro2 = "1" quote = "1" -cglue-gen = { version = "0.2", path = "../cglue-gen" } +cglue-gen = { version = "0.3", path = "../cglue-gen" } [features] default = [] diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index b240c4e..e58c1cc 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue" -version = "0.2.14" +version = "0.3.0" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe abstractions for making plugins and C-compatible libraries" @@ -12,7 +12,7 @@ categories = [ "api-bindings", "accessibility", "parsing" ] readme = "../README.md" [dependencies] -cglue-macro = { version = "0.2", path = "../cglue-macro" } +cglue-macro = { version = "0.3", path = "../cglue-macro" } no-std-compat = { version = "0.4", features = ["alloc"] } serde = { version = "1", optional = true, default-features = false, features = ["derive", "alloc"] } try_default = { version = "= 1.0.0", optional = true } diff --git a/cglue/src/task/mod.rs b/cglue/src/task/mod.rs index 0f7d5fc..83ced60 100644 --- a/cglue/src/task/mod.rs +++ b/cglue/src/task/mod.rs @@ -203,6 +203,7 @@ fn get_order() -> CRawWakerOrder { } #[allow(clippy::useless_transmute)] +#[allow(unused_braces)] #[cfg(not(miri))] const ORDER: CRawWakerOrder = { __order!() }; diff --git a/cglue/src/tests/ext/futures.rs b/cglue/src/tests/ext/futures.rs index 36a4212..e91c2a2 100644 --- a/cglue/src/tests/ext/futures.rs +++ b/cglue/src/tests/ext/futures.rs @@ -10,7 +10,7 @@ fn use_stream() { impl_stream(&obj); - assert_eq!(pollster::block_on(obj.collect::>()), items,); + assert_eq!(pollster::block_on(obj.collect::>()), items); } #[cfg(test)] diff --git a/cglue/src/tests/extra/forward.rs b/cglue/src/tests/extra/forward.rs index 13c3d14..a719620 100644 --- a/cglue/src/tests/extra/forward.rs +++ b/cglue/src/tests/extra/forward.rs @@ -1,5 +1,6 @@ use crate::*; +#[allow(dead_code)] #[cglue_forward] trait ForwardMe { #[skip_func] From 95a9849d533dc856d2d1cdfaf27071b978ac31af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Sat, 27 Jul 2024 14:58:15 +0000 Subject: [PATCH 34/41] Fix FastCWakerState drop code --- Cargo.lock | 7 +-- cglue/Cargo.toml | 4 +- cglue/src/task/sound.rs | 115 ++++++++++++++++++++++++++++++++++++++-- version-hack/Cargo.toml | 3 ++ 4 files changed, 120 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72207f9..c28bbd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,7 +90,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cglue" -version = "0.3.0" +version = "0.3.1" dependencies = [ "abi_stable", "cglue-macro", @@ -406,9 +406,9 @@ dependencies = [ [[package]] name = "pollster" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b647f02b0ae8f6d4f58e06639cf41316a154b5469dc7e833026645aa2807c8ef" +checksum = "9824e18e85003f0b5a38fa1932ae8be8c2aac9447c2f28ab6f9704dbe0a1ab58" [[package]] name = "proc-macro-crate" @@ -658,6 +658,7 @@ dependencies = [ "log", "memchr", "once_cell", + "pollster", "proc-macro2", "serde", "thiserror", diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index e58c1cc..8ffc528 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue" -version = "0.3.0" +version = "0.3.1" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe abstractions for making plugins and C-compatible libraries" @@ -25,7 +25,7 @@ _futures = { package = "futures", version = "0.3", optional = true, default-feat rustc_version = "0.4" [dev-dependencies] -pollster = "0.1" +pollster = "0.2" [features] default = ["std"] diff --git a/cglue/src/task/sound.rs b/cglue/src/task/sound.rs index 1f2bd58..bae93ff 100644 --- a/cglue/src/task/sound.rs +++ b/cglue/src/task/sound.rs @@ -7,8 +7,8 @@ use core::task::*; use tarc::BaseArc; unsafe extern "C" fn clone_adapter(data: *const (), clone: *const ()) -> CRawWaker { - let clone: unsafe fn(*const ()) -> CRawWaker = core::mem::transmute(clone); - clone(data) + let clone: unsafe fn(*const ()) -> RawWaker = core::mem::transmute(clone); + core::mem::transmute(clone(data)) } unsafe extern "C" fn other_adapter(data: *const (), other: *const ()) { @@ -178,7 +178,7 @@ impl<'a> FastCWaker<'a> { impl<'a> Drop for FastCWakerState<'a> { fn drop(&mut self) { if let Self::Owned(s) = self { - unsafe { BaseArc::decrement_strong_count(s) }; + unsafe { BaseArc::decrement_strong_count(s.as_ptr()) }; } } } @@ -243,7 +243,7 @@ impl<'a> FastCWaker<'a> { }; this.release(); - adapter(data, wake as _) + adapter(data, wake as _); } let vtbl = &RawWakerVTable::new(clone, unreach, wake_by_ref, noop); @@ -293,3 +293,110 @@ impl<'a> FastCWaker<'a> { ret } } + +#[cfg(test)] +mod tests { + use super::*; + use pollster::block_on; + + // Since unavailable before 1.64 + use core::fmt; + use core::future::Future; + use core::pin::*; + + pub fn poll_fn(f: F) -> PollFn + where + F: FnMut(&mut Context<'_>) -> Poll, + { + PollFn { f } + } + + /// A Future that wraps a function returning [`Poll`]. + /// + /// This `struct` is created by [`poll_fn()`]. See its + /// documentation for more. + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct PollFn { + f: F, + } + + impl Unpin for PollFn {} + + impl fmt::Debug for PollFn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PollFn").finish() + } + } + + impl Future for PollFn + where + F: FnMut(&mut Context<'_>) -> Poll, + { + type Output = T; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // SAFETY: We are not moving out of the pinned field. + (unsafe { &mut self.get_unchecked_mut().f })(cx) + } + } + + #[test] + fn fastcwaker_simple() { + let mut polled = false; + let fut = poll_fn(|cx| { + if !polled { + polled = true; + cx.waker().wake_by_ref(); + Poll::Pending + } else { + Poll::Ready(()) + } + }); + let fut = crate::trait_obj!(fut as Future); + block_on(fut) + } + + #[test] + fn fastcwaker_simple_cloned() { + let mut polled = false; + let fut = poll_fn(|cx| { + if !polled { + polled = true; + cx.waker().clone().wake(); + Poll::Pending + } else { + Poll::Ready(()) + } + }); + let fut = crate::trait_obj!(fut as Future); + block_on(fut) + } + + #[test] + fn fastcwaker_threaded() { + let (tx, rx) = std::sync::mpsc::channel::(); + + let thread = std::thread::spawn(move || { + for waker in rx.into_iter() { + waker.wake(); + } + }); + + let mut polled = false; + let fut = poll_fn(|cx| { + if !polled { + polled = true; + tx.send(cx.waker().clone()).unwrap(); + Poll::Pending + } else { + Poll::Ready(()) + } + }); + let fut = crate::trait_obj!(fut as Future); + block_on(fut); + + core::mem::drop(tx); + + thread.join().unwrap(); + } +} diff --git a/version-hack/Cargo.toml b/version-hack/Cargo.toml index 410e87d..7037b91 100644 --- a/version-hack/Cargo.toml +++ b/version-hack/Cargo.toml @@ -14,3 +14,6 @@ proc-macro2 = "=1.0.65" memchr = "=2.4.1" log = "=0.4.18" crossbeam-utils = "=0.8.16" + +[dev-dependencies] +pollster = "=0.2.0" From 6eb2baaa7a32bfb27b8f9d6cbc5bbee159271386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Mon, 29 Jul 2024 16:20:35 +0100 Subject: [PATCH 35/41] Remove FastCWaker and VUB --- Cargo.lock | 2 +- cglue-gen/Cargo.toml | 2 +- cglue-gen/src/ext/core/future.rs | 4 +- cglue-gen/src/ext/futures/sink.rs | 12 +- cglue-gen/src/ext/futures/stream.rs | 4 +- cglue/Cargo.toml | 2 +- cglue/src/task/mod.rs | 386 ++++++++++++++------------ cglue/src/task/sound.rs | 402 ---------------------------- 8 files changed, 229 insertions(+), 585 deletions(-) delete mode 100644 cglue/src/task/sound.rs diff --git a/Cargo.lock b/Cargo.lock index c28bbd9..305742a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,7 +90,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cglue" -version = "0.3.1" +version = "0.3.2" dependencies = [ "abi_stable", "cglue-macro", diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index a7b51b2..6674faf 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-gen" -version = "0.3.0" +version = "0.3.1" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe code generation for making plugins and C-compatible libraries" diff --git a/cglue-gen/src/ext/core/future.rs b/cglue-gen/src/ext/core/future.rs index a12485c..a1bc4fb 100644 --- a/cglue-gen/src/ext/core/future.rs +++ b/cglue-gen/src/ext/core/future.rs @@ -17,7 +17,7 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { #[custom_impl( // Types within the C interface other than self and additional wrappers. { - cx: &#crate_path::task::FastCWaker, + cx: &#crate_path::task::CRefWaker, out: &mut ::core::mem::MaybeUninit, }, // Unwrapped return type @@ -26,7 +26,7 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { { let mut out_v = ::core::mem::MaybeUninit::uninit(); let out = &mut out_v; - let cx = #crate_path::task::FastCWaker::from(cx.waker()); + let cx = #crate_path::task::CRefWaker::from(cx.waker()); let cx = &cx; }, // This is the body of C impl minus the automatic wrapping. diff --git a/cglue-gen/src/ext/futures/sink.rs b/cglue-gen/src/ext/futures/sink.rs index 7b15558..7f8acaa 100644 --- a/cglue-gen/src/ext/futures/sink.rs +++ b/cglue-gen/src/ext/futures/sink.rs @@ -17,7 +17,7 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { #[custom_impl( // Types within the C interface other than self and additional wrappers. { - cx: &#crate_path::task::FastCWaker, + cx: &#crate_path::task::CRefWaker, out: &mut ::core::mem::MaybeUninit, }, // Unwrapped return type @@ -26,7 +26,7 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { { let mut out_v = ::core::mem::MaybeUninit::uninit(); let out = &mut out_v; - let cx = #crate_path::task::FastCWaker::from(cx.waker()); + let cx = #crate_path::task::CRefWaker::from(cx.waker()); let cx = &cx; }, // This is the body of C impl minus the automatic wrapping. @@ -93,7 +93,7 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { #[custom_impl( // Types within the C interface other than self and additional wrappers. { - cx: &#crate_path::task::FastCWaker, + cx: &#crate_path::task::CRefWaker, out: &mut ::core::mem::MaybeUninit, }, // Unwrapped return type @@ -102,7 +102,7 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { { let mut out_v = ::core::mem::MaybeUninit::uninit(); let out = &mut out_v; - let cx = #crate_path::task::FastCWaker::from(cx.waker()); + let cx = #crate_path::task::CRefWaker::from(cx.waker()); let cx = &cx; }, // This is the body of C impl minus the automatic wrapping. @@ -135,7 +135,7 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { #[custom_impl( // Types within the C interface other than self and additional wrappers. { - cx: &#crate_path::task::FastCWaker, + cx: &#crate_path::task::CRefWaker, out: &mut ::core::mem::MaybeUninit, }, // Unwrapped return type @@ -144,7 +144,7 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { { let mut out_v = ::core::mem::MaybeUninit::uninit(); let out = &mut out_v; - let cx = #crate_path::task::FastCWaker::from(cx.waker()); + let cx = #crate_path::task::CRefWaker::from(cx.waker()); let cx = &cx; }, // This is the body of C impl minus the automatic wrapping. diff --git a/cglue-gen/src/ext/futures/stream.rs b/cglue-gen/src/ext/futures/stream.rs index 9069304..faffbfc 100644 --- a/cglue-gen/src/ext/futures/stream.rs +++ b/cglue-gen/src/ext/futures/stream.rs @@ -17,7 +17,7 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { #[custom_impl( // Types within the C interface other than self and additional wrappers. { - cx: &#crate_path::task::FastCWaker, + cx: &#crate_path::task::CRefWaker, out: &mut ::core::mem::MaybeUninit, }, // Unwrapped return type @@ -26,7 +26,7 @@ pub fn get_impl(parent_path: &Path, out: &mut Vec<(Path, TokenStream)>) { { let mut out_v = ::core::mem::MaybeUninit::uninit(); let out = &mut out_v; - let cx = #crate_path::task::FastCWaker::from(cx.waker()); + let cx = #crate_path::task::CRefWaker::from(cx.waker()); let cx = &cx; }, // This is the body of C impl minus the automatic wrapping. diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 8ffc528..fbc590d 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue" -version = "0.3.1" +version = "0.3.3" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe abstractions for making plugins and C-compatible libraries" diff --git a/cglue/src/task/mod.rs b/cglue/src/task/mod.rs index 83ced60..a811b77 100644 --- a/cglue/src/task/mod.rs +++ b/cglue/src/task/mod.rs @@ -1,213 +1,259 @@ //! C-compatible task structures. -mod sound; -pub use sound::*; - use core::task::*; +use tarc::BaseArc; #[repr(C)] #[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] -pub struct CRawWakerVTable { - clone: *const (), - wake: *const (), - wake_by_ref: *const (), - drop: *const (), +struct OpaqueRawWakerVtbl { + clone: unsafe extern "C" fn(OpaqueRawWaker) -> CRawWaker, + wake: unsafe extern "C" fn(OpaqueRawWaker), + wake_by_ref: unsafe extern "C" fn(OpaqueRawWaker), + drop: unsafe extern "C" fn(OpaqueRawWaker), } -#[repr(transparent)] -#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] -#[derive(Clone, Copy)] -pub struct CRawWaker { - ptrs: [*const (); 2], -} +impl Default for &'static OpaqueRawWakerVtbl { + fn default() -> Self { + unsafe extern "C" fn clone(w: OpaqueRawWaker) -> CRawWaker { + let waker: RawWaker = core::mem::transmute(w); + waker_clone(&waker as *const _ as *const ()) + } + + unsafe extern "C" fn wake(w: OpaqueRawWaker) { + let waker: Waker = core::mem::transmute(w); + waker.wake() + } -impl From<&Waker> for &CRawWaker { - fn from(w: &Waker) -> Self { - unsafe { &*(w as *const Waker as *const CRawWaker) } + unsafe extern "C" fn wake_by_ref(w: OpaqueRawWaker) { + let waker: RawWaker = core::mem::transmute(w); + let waker: &Waker = core::mem::transmute(&waker); + waker.wake_by_ref() + } + + unsafe extern "C" fn drop(w: OpaqueRawWaker) { + let _: Waker = core::mem::transmute(w); + } + + &OpaqueRawWakerVtbl { + clone, + wake, + wake_by_ref, + drop, + } } } +#[repr(C)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +struct CRawWaker { + waker: OpaqueRawWaker, + vtable: &'static OpaqueRawWakerVtbl, +} + impl CRawWaker { - fn data(&self, order: &CRawWakerOrder) -> *const () { - self.ptrs[order.data] + fn to_raw(this: BaseArc) -> RawWaker { + unsafe fn clone(data: *const ()) -> RawWaker { + let data = data as *const CRawWaker; + BaseArc::increment_strong_count(data); + let waker = BaseArc::from_raw(data); + CRawWaker::to_raw(waker) + } + unsafe fn wake(data: *const ()) { + let this = BaseArc::from_raw(data as *const CRawWaker); + (this.vtable.wake)(this.waker) + } + unsafe fn wake_by_ref(data: *const ()) { + let data = data as *const CRawWaker; + let this = &*data; + (this.vtable.wake_by_ref)(this.waker) + } + unsafe fn drop(data: *const ()) { + let this = BaseArc::from_raw(data as *const CRawWaker); + (this.vtable.drop)(this.waker) + } + + let vtbl = &RawWakerVTable::new(clone, wake, wake_by_ref, drop); + + RawWaker::new(this.into_raw() as *const (), vtbl) } +} - unsafe fn vtable(&self, order: &CRawWakerOrder) -> &'static CRawWakerVTable { - &*(self.ptrs[order.vtable] as *const CRawWakerVTable) +unsafe extern "C" fn waker_clone(waker: *const ()) -> CRawWaker { + let waker: &Waker = &*(waker as *const Waker); + let waker = core::mem::transmute(waker.clone()); + + CRawWaker { + waker, + vtable: Default::default(), } } +unsafe extern "C" fn waker_wake_by_ref(waker: *const ()) { + let waker: &Waker = &*(waker as *const Waker); + waker.wake_by_ref() +} + +#[repr(transparent)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +#[derive(Clone, Copy)] +struct OpaqueRawWaker { + waker: [*const (); 2], +} + #[repr(C)] #[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] #[derive(Clone, Copy)] -struct CRawWakerOrder { - data: usize, - vtable: usize, +pub struct CRefWaker<'a> { + raw: &'a OpaqueRawWaker, + clone: unsafe extern "C" fn(*const ()) -> CRawWaker, + wake_by_ref: unsafe extern "C" fn(*const ()), } -// Verify the layouts of reimplemented data structures -// -// Unfortunately, we cannot verify function ABI. -#[allow(clippy::useless_transmute)] -#[cfg(not(miri))] -const _: () = { - use core::mem::{size_of, transmute}; - - if size_of::() != size_of::() { - #[cfg(not(const_panic_on_stable))] - let _ = "Raw waker size mismatch".as_bytes()[!0]; - #[cfg(const_panic_on_stable)] - panic!("Raw waker size mismatch"); +impl<'a> CRefWaker<'a> { + pub unsafe fn from_raw(raw: &'a RawWaker) -> Self { + let raw: &'a OpaqueRawWaker = core::mem::transmute(raw); + + Self { + raw, + clone: waker_clone, + wake_by_ref: waker_wake_by_ref, + } } - if size_of::() != size_of::() { - #[cfg(not(const_panic_on_stable))] - let _ = "Raw waker size mismatch".as_bytes()[!0]; - #[cfg(const_panic_on_stable)] - panic!("Raw waker size mismatch"); + pub fn with_waker(&self, cb: impl FnOnce(&Waker) -> T) -> T { + unsafe fn unreach(_: *const ()) { + unreachable!() + } + unsafe fn noop(_: *const ()) {} + unsafe fn clone(data: *const ()) -> RawWaker { + let this = &*(data as *const CRefWaker); + let waker = unsafe { (this.clone)(this.raw as *const _ as *const ()) }; + let waker = BaseArc::new(waker); + CRawWaker::to_raw(waker) + } + unsafe fn wake_by_ref(data: *const ()) { + let this = &*(data as *const CRefWaker); + unsafe { (this.wake_by_ref)(this.raw as *const _ as *const ()) }; + } + + let vtbl = &RawWakerVTable::new(clone, unreach, wake_by_ref, noop); + let waker = RawWaker::new(self as *const Self as *const (), vtbl); + let waker = unsafe { Waker::from_raw(waker) }; + + cb(&waker) } +} - if size_of::() != size_of::() { - #[cfg(not(const_panic_on_stable))] - let _ = "Raw waker vtbl size mismatch".as_bytes()[!0]; - #[cfg(const_panic_on_stable)] - panic!("Raw waker vtbl size mismatch"); +impl<'a> From<&'a Waker> for CRefWaker<'a> { + fn from(waker: &'a Waker) -> Self { + const _: [(); core::mem::size_of::()] = [(); core::mem::size_of::()]; + unsafe { Self::from_raw(core::mem::transmute(waker)) } } +} - macro_rules! expand { - ($c:literal, $s:literal, $($e:expr),*) => { - [$(concat!($c, " ", $s, " idx ", stringify!($e)),)*] - } +#[cfg(test)] +mod tests { + use super::*; + use pollster::block_on; + + // Since unavailable before 1.64 + use core::fmt; + use core::future::Future; + use core::pin::*; + + pub fn poll_fn(f: F) -> PollFn + where + F: FnMut(&mut Context<'_>) -> Poll, + { + PollFn { f } } - macro_rules! comp_arr { - ($a:ident, $b:ident, $c:literal) => {{ - const BUF: &[&str] = &expand!( - $c, - "buffers not equal!", - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32 - ); - - let mut cnt = 0; - while cnt < $a.len() { - if $a[cnt] != $b[cnt] { - #[cfg(not(const_panic_on_stable))] - let _buffers_not_equal: () = [][cnt]; - #[cfg(const_panic_on_stable)] - panic!("{}", BUF[cnt]); - } - cnt += 1; - } - }}; + /// A Future that wraps a function returning [`Poll`]. + /// + /// This `struct` is created by [`poll_fn()`]. See its + /// documentation for more. + #[must_use = "futures do nothing unless you `.await` or poll them"] + pub struct PollFn { + f: F, } - // Verify the layout of the vtable. - - let clone: *const () = unsafe { transmute(1usize) }; - let wake: *const () = unsafe { transmute(2usize) }; - let wake_by_ref: *const () = unsafe { transmute(3usize) }; - let drop: *const () = unsafe { transmute(4usize) }; - - let vtbl = unsafe { - RawWakerVTable::new( - transmute(clone), - transmute(wake), - transmute(wake_by_ref), - transmute(drop), - ) - }; - let vtbl_c = CRawWakerVTable { - clone, - wake, - wake_by_ref, - drop, - }; - - let bvtbl = unsafe { transmute::<_, [u8; size_of::()]>(vtbl) }; - let bvtbl_c = unsafe { transmute::<_, [u8; size_of::()]>(vtbl_c) }; - - comp_arr!(bvtbl, bvtbl_c, "vtable"); -}; - -macro_rules! __order { - () => {{ - use core::mem::transmute; - - // Verify the layout of the raw waker. - - let data = core::ptr::null(); - - #[cfg(miri)] - let vtbl = unsafe { - unsafe fn clone(data: *const ()) -> RawWaker { - todo!() - } + impl Unpin for PollFn {} - unsafe fn null(data: *const ()) {} + impl fmt::Debug for PollFn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PollFn").finish() + } + } - &RawWakerVTable::new(clone, null, null, null) - }; - #[cfg(not(miri))] - let vtbl = unsafe { transmute(1 as *const ()) }; + impl Future for PollFn + where + F: FnMut(&mut Context<'_>) -> Poll, + { + type Output = T; - let waker = RawWaker::new(data, vtbl); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // SAFETY: We are not moving out of the pinned field. + (unsafe { &mut self.get_unchecked_mut().f })(cx) + } + } - // This verifies the size of the object - will not compile if RawWaker is not the size of 2 - // pointers, or if usize != pointer size. - let bwaker = unsafe { transmute::<_, [usize; 2]>(waker) }; + #[test] + fn cwaker_simple() { + let mut polled = false; + let fut = poll_fn(|cx| { + if !polled { + polled = true; + cx.waker().wake_by_ref(); + Poll::Pending + } else { + Poll::Ready(()) + } + }); + let fut = crate::trait_obj!(fut as Future); + block_on(fut) + } - // This will return us the order - let data = if bwaker[0] == 0 { 0 } else { 1 }; - let vtable = if bwaker[0] == 0 { 1 } else { 0 }; + #[test] + fn cwaker_simple_cloned() { + let mut polled = false; + let fut = poll_fn(|cx| { + if !polled { + polled = true; + cx.waker().clone().wake(); + Poll::Pending + } else { + Poll::Ready(()) + } + }); + let fut = crate::trait_obj!(fut as Future); + block_on(fut) + } - CRawWakerOrder { data, vtable } - }}; -} + #[test] + fn cwaker_threaded() { + let (tx, rx) = std::sync::mpsc::channel::(); -#[cfg(miri)] -#[allow(clippy::useless_transmute)] -fn get_order() -> CRawWakerOrder { - __order!() -} + let thread = std::thread::spawn(move || { + for waker in rx.into_iter() { + waker.wake(); + } + }); + + let mut polled = false; + let fut = poll_fn(|cx| { + if !polled { + polled = true; + tx.send(cx.waker().clone()).unwrap(); + Poll::Pending + } else { + Poll::Ready(()) + } + }); + let fut = crate::trait_obj!(fut as Future); + block_on(fut); -#[allow(clippy::useless_transmute)] -#[allow(unused_braces)] -#[cfg(not(miri))] -const ORDER: CRawWakerOrder = { __order!() }; + core::mem::drop(tx); -#[cfg(not(miri))] -const fn get_order() -> CRawWakerOrder { - ORDER + thread.join().unwrap(); + } } diff --git a/cglue/src/task/sound.rs b/cglue/src/task/sound.rs deleted file mode 100644 index bae93ff..0000000 --- a/cglue/src/task/sound.rs +++ /dev/null @@ -1,402 +0,0 @@ -use super::*; - -use core::cell::UnsafeCell; -use core::ptr::NonNull; -use core::sync::atomic::{AtomicBool, Ordering}; -use core::task::*; -use tarc::BaseArc; - -unsafe extern "C" fn clone_adapter(data: *const (), clone: *const ()) -> CRawWaker { - let clone: unsafe fn(*const ()) -> RawWaker = core::mem::transmute(clone); - core::mem::transmute(clone(data)) -} - -unsafe extern "C" fn other_adapter(data: *const (), other: *const ()) { - let other: unsafe fn(_: *const ()) = core::mem::transmute(other); - other(data) -} - -#[repr(C)] -#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] -pub struct CWaker { - raw: CRawWaker, - order: CRawWakerOrder, - clone_adapter: unsafe extern "C" fn(*const (), *const ()) -> CRawWaker, - other_adapter: unsafe extern "C" fn(*const (), *const ()), -} - -impl CWaker { - fn data(&self) -> *const () { - self.raw.data(&self.order) - } - - fn vtable(&self) -> &'static CRawWakerVTable { - // SAFETY: we ensure safety during construction of `CWaker` - the order used is always - // correct and tied to the raw vtable. - unsafe { self.raw.vtable(&self.order) } - } - - pub fn into_waker(this: BaseArc) -> Waker { - unsafe { Waker::from_raw(Self::into_raw_waker(this)) } - } - - pub fn into_raw_waker(this: BaseArc) -> RawWaker { - unsafe fn clone(data: *const ()) -> RawWaker { - let waker = data as *const CWaker; - BaseArc::increment_strong_count(waker); - CWaker::into_raw_waker(BaseArc::from_raw(waker)) - } - - unsafe fn wake(data: *const ()) { - let waker = &*(data as *const CWaker); - (waker.other_adapter)(waker.data(), waker.vtable().wake_by_ref as _); - BaseArc::decrement_strong_count(waker); - } - - unsafe fn wake_by_ref(data: *const ()) { - let waker = &*(data as *const CWaker); - (waker.other_adapter)(waker.data(), waker.vtable().wake_by_ref as _); - } - - unsafe fn drop(data: *const ()) { - BaseArc::decrement_strong_count(data as *const CWaker); - } - - let vtbl = &RawWakerVTable::new(clone, wake, wake_by_ref, drop); - RawWaker::new(this.into_raw() as *const (), vtbl) - } - - pub fn wake(self) { - let other_adapter = self.other_adapter; - let wake = self.vtable().wake; - let data = self.data(); - // Don't call `drop` -- the waker will be consumed by `wake`. - core::mem::forget(self); - // SAFETY: This is safe because `Waker::from_raw` is the only way - // to initialize `wake` and `data` requiring the user to acknowledge - // that the contract of `RawWaker` is upheld. - - // This is also FFI-safe because `other_adapter` adapts the calling convention. - unsafe { (other_adapter)(data, wake as _) }; - } - - pub fn wake_by_ref(&self) { - let other_adapter = self.other_adapter; - let wake_by_ref = self.vtable().wake_by_ref; - let data = self.data(); - // SAFETY: This is safe because `Waker::from_raw` is the only way - // to initialize `wake` and `data` requiring the user to acknowledge - // that the contract of `RawWaker` is upheld. - - // This is also FFI-safe because `other_adapter` adapts the calling convention. - unsafe { (other_adapter)(data, wake_by_ref as _) }; - } - - pub unsafe fn from_raw(raw: RawWaker) -> Self { - let raw: CRawWaker = core::mem::transmute(raw); - - Self { - raw, - order: get_order(), - clone_adapter, - other_adapter, - } - } -} - -impl Drop for CWaker { - fn drop(&mut self) { - let other_adapter = self.other_adapter; - let drop = self.vtable().drop; - let data = self.data(); - // SAFETY: This is safe because `Waker::from_raw` is the only way - // to initialize `wake` and `data` requiring the user to acknowledge - // that the contract of `RawWaker` is upheld. - - // This is also FFI-safe because `other_adapter` adapts the calling convention. - unsafe { (other_adapter)(data, drop as *const ()) }; - } -} - -impl Clone for CWaker { - #[inline] - fn clone(&self) -> Self { - Self { - // SAFETY: This is safe because `Waker::from_raw` is the only way - // to initialize `clone` and `data` requiring the user to acknowledge - // that the contract of [`RawWaker`] is upheld. - raw: unsafe { (self.clone_adapter)(self.data(), self.vtable().clone as *const ()) }, - order: self.order, - clone_adapter: self.clone_adapter, - other_adapter: self.other_adapter, - } - } -} - -impl From for CWaker { - fn from(waker: Waker) -> Self { - unsafe { Self::from_raw(core::mem::transmute(waker)) } - } -} - -#[repr(C, u8)] -#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] -enum FastCWakerState<'a> { - Borrowed { - waker: &'a CRawWaker, - order: CRawWakerOrder, - clone_adapter: unsafe extern "C" fn(*const (), *const ()) -> CRawWaker, - other_adapter: unsafe extern "C" fn(*const (), *const ()), - }, - Owned(NonNull), -} - -#[repr(C)] -#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] -pub struct FastCWaker<'a> { - lock: AtomicBool, - state: UnsafeCell>, -} - -impl<'a> FastCWaker<'a> { - #[allow(clippy::mut_from_ref)] - unsafe fn lock(&self) -> &mut FastCWakerState<'a> { - while self.lock.fetch_or(true, Ordering::Acquire) { - while self.lock.load(Ordering::Relaxed) { - #[allow(deprecated)] - core::sync::atomic::spin_loop_hint(); - } - } - unsafe { &mut *self.state.get() } - } - - fn release(&self) { - self.lock.store(false, Ordering::Release); - } -} - -impl<'a> Drop for FastCWakerState<'a> { - fn drop(&mut self) { - if let Self::Owned(s) = self { - unsafe { BaseArc::decrement_strong_count(s.as_ptr()) }; - } - } -} - -impl<'a> From<&'a Waker> for FastCWaker<'a> { - fn from(waker: &'a Waker) -> Self { - Self { - lock: Default::default(), - state: UnsafeCell::new(FastCWakerState::Borrowed { - waker: waker.into(), - order: get_order(), - clone_adapter, - other_adapter, - }), - } - } -} - -impl<'a> FastCWaker<'a> { - pub fn with_waker(&self, cb: impl FnOnce(&Waker) -> T) -> T { - if let FastCWakerState::Owned(owned) = unsafe { self.lock() } { - let owned = unsafe { - let owned = owned.as_ptr(); - BaseArc::increment_strong_count(owned); - BaseArc::from_raw(owned) - }; - self.release(); - cb(&CWaker::into_waker(owned)) - } else { - self.release(); - // Create a waker that modifies self upon clone - - unsafe fn unreach(_: *const ()) { - unreachable!() - } - unsafe fn noop(_: *const ()) {} - unsafe fn clone(data: *const ()) -> RawWaker { - let this = &*(data as *const FastCWaker); - CWaker::into_raw_waker(this.c_waker()) - } - unsafe fn wake_by_ref(data: *const ()) { - let this = &*(data as *const FastCWaker); - let (data, wake, adapter) = match unsafe { this.lock() } { - FastCWakerState::Borrowed { - waker, - order, - other_adapter, - .. - } => ( - waker.data(order), - waker.vtable(order).wake_by_ref, - *other_adapter, - ), - FastCWakerState::Owned(d) => { - let waker = &*d.as_ptr(); - ( - waker.data(), - waker.vtable().wake_by_ref, - waker.other_adapter, - ) - } - }; - this.release(); - - adapter(data, wake as _); - } - - let vtbl = &RawWakerVTable::new(clone, unreach, wake_by_ref, noop); - let waker = RawWaker::new(self as *const Self as *const (), vtbl); - let waker = unsafe { Waker::from_raw(waker) }; - - cb(&waker) - } - } - - pub fn clone_waker(&self) -> Waker { - self.with_waker(|w| w.clone()) - } - - pub fn c_waker(&self) -> BaseArc { - let state = unsafe { self.lock() }; - - let ret = match state { - FastCWakerState::Owned(owned) => unsafe { - let owned = owned.as_ptr(); - BaseArc::increment_strong_count(owned); - BaseArc::from_raw(owned) - }, - FastCWakerState::Borrowed { - waker, - order, - clone_adapter, - other_adapter, - } => { - let waker = - unsafe { clone_adapter(waker.data(order), waker.vtable(order).clone as _) }; - let owned: BaseArc = BaseArc::from(CWaker { - raw: waker, - order: *order, - clone_adapter: *clone_adapter, - other_adapter: *other_adapter, - }); - *state = FastCWakerState::Owned(unsafe { - NonNull::new_unchecked(owned.clone().into_raw() as *mut _) - }); - owned - } - }; - - self.release(); - - ret - } -} - -#[cfg(test)] -mod tests { - use super::*; - use pollster::block_on; - - // Since unavailable before 1.64 - use core::fmt; - use core::future::Future; - use core::pin::*; - - pub fn poll_fn(f: F) -> PollFn - where - F: FnMut(&mut Context<'_>) -> Poll, - { - PollFn { f } - } - - /// A Future that wraps a function returning [`Poll`]. - /// - /// This `struct` is created by [`poll_fn()`]. See its - /// documentation for more. - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub struct PollFn { - f: F, - } - - impl Unpin for PollFn {} - - impl fmt::Debug for PollFn { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PollFn").finish() - } - } - - impl Future for PollFn - where - F: FnMut(&mut Context<'_>) -> Poll, - { - type Output = T; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // SAFETY: We are not moving out of the pinned field. - (unsafe { &mut self.get_unchecked_mut().f })(cx) - } - } - - #[test] - fn fastcwaker_simple() { - let mut polled = false; - let fut = poll_fn(|cx| { - if !polled { - polled = true; - cx.waker().wake_by_ref(); - Poll::Pending - } else { - Poll::Ready(()) - } - }); - let fut = crate::trait_obj!(fut as Future); - block_on(fut) - } - - #[test] - fn fastcwaker_simple_cloned() { - let mut polled = false; - let fut = poll_fn(|cx| { - if !polled { - polled = true; - cx.waker().clone().wake(); - Poll::Pending - } else { - Poll::Ready(()) - } - }); - let fut = crate::trait_obj!(fut as Future); - block_on(fut) - } - - #[test] - fn fastcwaker_threaded() { - let (tx, rx) = std::sync::mpsc::channel::(); - - let thread = std::thread::spawn(move || { - for waker in rx.into_iter() { - waker.wake(); - } - }); - - let mut polled = false; - let fut = poll_fn(|cx| { - if !polled { - polled = true; - tx.send(cx.waker().clone()).unwrap(); - Poll::Pending - } else { - Poll::Ready(()) - } - }); - let fut = crate::trait_obj!(fut as Future); - block_on(fut); - - core::mem::drop(tx); - - thread.join().unwrap(); - } -} From 5384133494ee285d2b5cc72182215f9dd32eeb84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Tue, 30 Jul 2024 21:55:01 +0100 Subject: [PATCH 36/41] Hack around a soundness issue Prevent `CBox` from being opaquable if it isn't `Send`. This effectively works around #18, albeit does not solve it. This will prevent `!Send` futures from being turned into CGlue's opaque, `CBox: Send`. --- Cargo.lock | 4 ++-- cglue/Cargo.toml | 2 +- cglue/src/boxed.rs | 3 ++- cglue/src/task/mod.rs | 4 +--- cglue/src/tests/extra/wrap_default.rs | 2 +- cglue/src/tests/simple/trait_groups.rs | 2 +- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 305742a..06a9ae7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -90,7 +90,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cglue" -version = "0.3.2" +version = "0.3.4" dependencies = [ "abi_stable", "cglue-macro", @@ -117,7 +117,7 @@ dependencies = [ [[package]] name = "cglue-gen" -version = "0.3.0" +version = "0.3.1" dependencies = [ "itertools", "lazy_static", diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index fbc590d..9c033ce 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue" -version = "0.3.3" +version = "0.3.4" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe abstractions for making plugins and C-compatible libraries" diff --git a/cglue/src/boxed.rs b/cglue/src/boxed.rs index 1af477c..d7c600a 100644 --- a/cglue/src/boxed.rs +++ b/cglue/src/boxed.rs @@ -74,7 +74,8 @@ impl Drop for CBox<'_, T> { } } -unsafe impl<'a, T> Opaquable for CBox<'a, T> { +// FIXME: express both Send and !Send box safely (https://github.com/h33p/cglue/issues/18) +unsafe impl<'a, T: Send> Opaquable for CBox<'a, T> { type OpaqueTarget = CBox<'a, c_void>; } diff --git a/cglue/src/task/mod.rs b/cglue/src/task/mod.rs index a811b77..9e7d219 100644 --- a/cglue/src/task/mod.rs +++ b/cglue/src/task/mod.rs @@ -240,7 +240,7 @@ mod tests { }); let mut polled = false; - let fut = poll_fn(|cx| { + let fut = poll_fn(move |cx| { if !polled { polled = true; tx.send(cx.waker().clone()).unwrap(); @@ -252,8 +252,6 @@ mod tests { let fut = crate::trait_obj!(fut as Future); block_on(fut); - core::mem::drop(tx); - thread.join().unwrap(); } } diff --git a/cglue/src/tests/extra/wrap_default.rs b/cglue/src/tests/extra/wrap_default.rs index 8db348f..9515045 100644 --- a/cglue/src/tests/extra/wrap_default.rs +++ b/cglue/src/tests/extra/wrap_default.rs @@ -11,7 +11,7 @@ pub trait ExtraFeature { } #[cglue_trait] -pub trait Basic: Sized { +pub trait Basic: Sized + Send + Sync { #[vtbl_only('_, wrap_with_obj(ExtraFeature))] fn b_1(&self) -> ExtraFeatureWrap<&Self> { ExtraFeatureWrap { _v: self } diff --git a/cglue/src/tests/simple/trait_groups.rs b/cglue/src/tests/simple/trait_groups.rs index c6ccb74..7d53018 100644 --- a/cglue/src/tests/simple/trait_groups.rs +++ b/cglue/src/tests/simple/trait_groups.rs @@ -22,7 +22,7 @@ fn test_group() { // and a ref group impl. // // Having both requres explicitly specifying inner type like done here. - fn into_test<'a, T: Into> + 'a>(t: T) -> TestGroupBox<'a> { + fn into_test<'a, T: Into> + Send + 'a>(t: T) -> TestGroupBox<'a> { group_obj!(t as TestGroup) } let _ = into_test(&a); From 5302a750bdd483b01b5ea7de5ab4f8ad2036f8d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Wed, 23 Apr 2025 19:56:34 +0100 Subject: [PATCH 37/41] Add CWaker --- cglue/src/task/mod.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/cglue/src/task/mod.rs b/cglue/src/task/mod.rs index 9e7d219..1a2b4c3 100644 --- a/cglue/src/task/mod.rs +++ b/cglue/src/task/mod.rs @@ -93,6 +93,47 @@ unsafe extern "C" fn waker_wake_by_ref(waker: *const ()) { waker.wake_by_ref() } +#[repr(C)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +pub struct CWaker(CRawWaker); + +impl From for CWaker { + fn from(waker: Waker) -> Self { + let waker: OpaqueRawWaker = unsafe { core::mem::transmute(waker) }; + Self(CRawWaker { + waker, + vtable: Default::default(), + }) + } +} + +impl Clone for CWaker { + fn clone(&self) -> Self { + Self(unsafe { (self.0.vtable.clone)(self.0.waker) }) + } +} + +impl Drop for CWaker { + fn drop(&mut self) { + unsafe { + (self.0.vtable.drop)(self.0.waker); + } + } +} + +impl CWaker { + pub fn wake_by_ref(&self) { + unsafe { (self.0.vtable.wake_by_ref)(self.0.waker) } + } + + pub fn wake(self) { + let vtable = self.0.vtable; + let waker = self.0.waker; + core::mem::forget(self); + unsafe { (vtable.wake)(waker) }; + } +} + #[repr(transparent)] #[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] #[derive(Clone, Copy)] From 7ccbdb762785609409a5dd0d16b315fee2dcf2ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Thu, 24 Apr 2025 11:38:06 +0100 Subject: [PATCH 38/41] C-unwind ABI support --- .github/workflows/build.yml | 12 ++++++++++- Cargo.lock | 2 -- cglue-gen/Cargo.toml | 2 ++ cglue-gen/build.rs | 3 +++ cglue-gen/src/ext/mod.rs | 8 ++++++- cglue-gen/src/func.rs | 35 ++++++++++++++++++++++++++---- cglue-gen/src/traits.rs | 21 ++++++++++++++++++ cglue-macro/Cargo.toml | 2 ++ cglue-macro/src/lib.rs | 12 +++++++++++ cglue/Cargo.toml | 2 ++ cglue/build.rs | 21 ++++++++++++++---- cglue/src/tests/ext/futures.rs | 6 ++++++ cglue/src/tests/simple/traits.rs | 37 +++++++++++++++++++------------- 13 files changed, 136 insertions(+), 27 deletions(-) create mode 100644 cglue-gen/build.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 74dc52a..8b312f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -92,11 +92,13 @@ jobs: run: cargo build --workspace --all-features --verbose env: RUSTC_BOOTSTRAP: try_default + RUSTFLAGS: ${{ matrix.toolchain != 'stable' && '--cfg __cglue_force_no_unwind_abi' || '' }} - name: Build examples run: cargo build --workspace --all-features --examples --verbose env: RUSTC_BOOTSTRAP: try_default + RUSTFLAGS: ${{ matrix.toolchain != 'stable' && '--cfg __cglue_force_no_unwind_abi' || '' }} build-cross-aarch64: runs-on: ubuntu-latest @@ -134,6 +136,8 @@ jobs: - name: Run all tests run: cargo test --verbose -p cglue + env: + RUSTFLAGS: ${{ matrix.toolchain != 'stable' && '--cfg __cglue_force_no_unwind_abi' || '' }} test-all-features: runs-on: ${{ matrix.os }} @@ -152,6 +156,7 @@ jobs: run: cargo test --workspace --all-features --verbose env: RUSTC_BOOTSTRAP: try_default + RUSTFLAGS: ${{ matrix.toolchain != 'stable' && '--cfg __cglue_force_no_unwind_abi' || '' }} lint: runs-on: ubuntu-latest @@ -188,10 +193,13 @@ jobs: miri-rustabi-patcher ~/.rustup/toolchains/${{ matrix.toolchain }}-x86_64-unknown-linux-gnu/bin/miri mv ~/.rustup/toolchains/${{ matrix.toolchain }}-x86_64-unknown-linux-gnu/bin/miri.patched ~/.rustup/toolchains/${{ matrix.toolchain }}-x86_64-unknown-linux-gnu/bin/miri chmod +x ~/.rustup/toolchains/${{ matrix.toolchain }}-x86_64-unknown-linux-gnu/bin/miri + - name: Install locked xargo + run: | + cargo install xargo --locked --version 0.3.26 - name: Run miri run: | cd cglue - MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri test --features rust_void + MIRIFLAGS="-Zmiri-disable-stacked-borrows" RUSTFLAGS="--cfg __cglue_force_no_unwind_abi" cargo miri test --features rust_void c-examples: runs-on: ubuntu-latest @@ -215,6 +223,8 @@ jobs: platform: x64 - name: Build the plugins run: cargo build --release -p plugin-api -p plugin-lib -p cglue-bindgen + env: + RUSTFLAGS: ${{ matrix.toolchain != 'stable' && '--cfg __cglue_force_no_unwind_abi' || '' }} - name: Build C++ plugin library run: | cd examples/cpp-plugin-lib/ diff --git a/Cargo.lock b/Cargo.lock index 06a9ae7..dd4946c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "abi_stable" version = "0.10.4" diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index 6674faf..e46ae20 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -26,3 +26,5 @@ unstable = [] layout_checks = [] task = [] futures = ["task"] +unwind_abi_default = [] +unwind_abi_ext = [] diff --git a/cglue-gen/build.rs b/cglue-gen/build.rs new file mode 100644 index 0000000..6a2b6d7 --- /dev/null +++ b/cglue-gen/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo::rustc-check-cfg=cfg(__cglue_force_no_unwind_abi)"); +} diff --git a/cglue-gen/src/ext/mod.rs b/cglue-gen/src/ext/mod.rs index a6db48b..34110b4 100644 --- a/cglue-gen/src/ext/mod.rs +++ b/cglue-gen/src/ext/mod.rs @@ -180,9 +180,15 @@ pub fn impl_ext_forward() -> TokenStream { /// Implement the external trait store. pub fn impl_store() -> TokenStream { + let unwind_abi = if cfg!(feature = "unwind_abi_ext") { + quote!(#[unwind_abi]) + } else { + quote!() + }; + impl_inner( |subpath, name| quote!(pub use #subpath #name;), - |_, _| quote!(#[cglue_trait_ext]), + |_, _| quote!(#[cglue_trait_ext] #unwind_abi), |exports, out| { // Re-export everything for (k, v) in exports.into_iter() { diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index 468e367..161c574 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -503,6 +503,7 @@ pub struct ParsedFunc { trait_name: Ident, safe: bool, abi: FuncAbi, + unwind_safe: bool, receiver: FnArg, orig_args: Vec, args: Vec, @@ -584,6 +585,7 @@ impl ParsedFunc { crate_path: &TokenStream, only_c_side: bool, custom_impl: Option, + unwind_safe: bool, ) -> Option { let name = sig.ident; let safe = sig.unsafety.is_none(); @@ -691,6 +693,7 @@ impl ParsedFunc { trait_name, safe, abi, + unwind_safe, receiver, orig_args, args, @@ -895,6 +898,7 @@ impl ParsedFunc { pub fn vtbl_def(&self, stream: &mut TokenStream) { let name = &self.name; let unsafety = &self.get_safety(); + let extern_abi = self.extern_abi(); let args = self.vtbl_args(); let ParsedReturnType { c_out, @@ -927,9 +931,16 @@ impl ParsedFunc { let sig_life_declare = merge_lifetime_declarations(&sig_life_declare, &parse_quote!(#hrtb)); let gen = quote! { - #name: for<#sig_life_declare> #unsafety extern "C" fn(#args #c_ret_params) #c_out, + #name: for<#sig_life_declare> #unsafety extern #extern_abi fn(#args #c_ret_params) #c_out, }; + // ABI-Stable does not support C-unwind ABI, so hack around that. + if cfg!(feature = "layout_checks") && self.unwind_safe { + let ty = quote!(for<#sig_life_declare> #unsafety extern "C" fn(#args #c_ret_params)) + .to_string(); + stream.extend(quote!(#[sabi(unsafe_change_type = #ty)])); + } + stream.extend(gen); } @@ -937,6 +948,7 @@ impl ParsedFunc { pub fn vtbl_getter_def(&self, stream: &mut TokenStream) { let name = &self.name; let args = self.vtbl_args(); + let extern_abi = self.extern_abi(); let ParsedReturnType { c_out, c_cast_out, @@ -974,7 +986,7 @@ impl ParsedFunc { /// /// Note that this function is wrapped into unsafe, because if already were is an /// opaque one, it would allow to invoke undefined behaviour. - pub fn #name(&self) -> for<#sig_life_declare> unsafe extern "C" fn(#args #c_ret_params) #c_out { + pub fn #name(&self) -> for<#sig_life_declare> unsafe extern #extern_abi fn(#args #c_ret_params) #c_out { unsafe { ::core::mem::transmute(self.#name) } } }; @@ -998,7 +1010,7 @@ impl ParsedFunc { /// /// This ought to only be used when references to objects are being returned, /// otherwise there is a risk of lifetime rule breakage. - unsafe fn #name2(&self) -> for<#lifetime_cast> #safety extern "C" fn(#args_cast #c_ret_params) #c_cast_out { + unsafe fn #name2(&self) -> for<#lifetime_cast> #safety extern #extern_abi fn(#args_cast #c_ret_params) #c_cast_out { ::core::mem::transmute(self.#name) } }; @@ -1028,6 +1040,7 @@ impl ParsedFunc { let name = &self.name; let args = self.vtbl_args(); + let extern_abi = self.extern_abi(); let ParsedReturnType { c_out, c_where_bounds, @@ -1148,7 +1161,7 @@ impl ParsedFunc { let ctx_bound = super::traits::ctx_bound(); let gen = quote! { - #safety extern "C" fn #fnname<#sig_life_declare CGlueC: #container_bound, CGlueCtx: #ctx_bound, #gen_declare #assoc_declare>(#args #c_ret_params) #c_out where #gen_where_bounds #c_where_bounds #cglue_c_into_inner CGlueC::ObjType: for<'cglue_b> #trname<#tmp_lifetime #gen_use #assoc_equality>, { + #safety extern #extern_abi fn #fnname<#sig_life_declare CGlueC: #container_bound, CGlueCtx: #ctx_bound, #gen_declare #assoc_declare>(#args #c_ret_params) #c_out where #gen_where_bounds #c_where_bounds #cglue_c_into_inner CGlueC::ObjType: for<'cglue_b> #trname<#tmp_lifetime #gen_use #assoc_equality>, { #c_pre_call let ret = #inner_impl; #c_ret @@ -1174,6 +1187,14 @@ impl ParsedFunc { } } + pub fn extern_abi(&self) -> TokenStream { + if self.unwind_safe { + quote!("C-unwind") + } else { + quote!("C") + } + } + pub fn trait_impl(&self, tokens: &mut TokenStream) -> (bool, bool, bool) { if !self.only_c_side { let name = &self.name; @@ -1343,6 +1364,7 @@ impl ParsedFunc { #[derive(Debug, Eq, PartialEq)] enum FuncAbi { ReprC, + ReprCUnwind, Wrapped, } @@ -1350,6 +1372,7 @@ impl FuncAbi { pub fn prefix(&self) -> TokenStream { match self { FuncAbi::ReprC => quote!(extern "C"), + FuncAbi::ReprCUnwind => quote!(extern "C-unwind"), FuncAbi::Wrapped => quote!(), } } @@ -1366,6 +1389,10 @@ impl From> for FuncAbi { if abi.value() == "C" { return FuncAbi::ReprC; } + + if abi.value() == "C-unwind" { + return FuncAbi::ReprCUnwind; + } } FuncAbi::Wrapped diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index 688a4f8..d6284c7 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -582,6 +582,24 @@ pub fn parse_trait( }) .next(); + fn unwind_abi(attrs: &[impl AsRef]) -> Option { + if cfg!(__cglue_force_no_unwind_abi) || attrs.iter().any(|i| i.as_ref() == "no_unwind_abi") + { + return Some(false); + } + if attrs.iter().any(|i| i.as_ref() == "unwind_abi") { + return Some(true); + } + None + } + + let global_unwind_abi = unwind_abi( + &tr.attrs + .iter() + .map(|a| a.path.to_token_stream().to_string()) + .collect::>(), + ); + // Parse all functions in the trait for item in &tr.items { match item { @@ -706,6 +724,9 @@ pub fn parse_trait( crate_path, only_c_side, custom_impl, + unwind_abi(&attrs) + .or(global_unwind_abi) + .unwrap_or(cfg!(feature = "unwind_abi_default")), )); } _ => {} diff --git a/cglue-macro/Cargo.toml b/cglue-macro/Cargo.toml index 320fbb6..766e6cc 100644 --- a/cglue-macro/Cargo.toml +++ b/cglue-macro/Cargo.toml @@ -27,3 +27,5 @@ unstable = ["cglue-gen/unstable"] layout_checks = ["cglue-gen/layout_checks"] task = ["cglue-gen/task"] futures = ["cglue-gen/futures", "task"] +unwind_abi_default = ["cglue-gen/unwind_abi_default"] +unwind_abi_ext = ["cglue-gen/unwind_abi_ext"] diff --git a/cglue-macro/src/lib.rs b/cglue-macro/src/lib.rs index a68d896..8e549d9 100644 --- a/cglue-macro/src/lib.rs +++ b/cglue-macro/src/lib.rs @@ -455,3 +455,15 @@ pub fn custom_impl(_: TokenStream, input: TokenStream) -> TokenStream { pub fn vtbl_only(_: TokenStream, input: TokenStream) -> TokenStream { input } + +/// Make the resulting C function support C++ unwinding (overrides default). +#[proc_macro_attribute] +pub fn unwind_abi(_: TokenStream, input: TokenStream) -> TokenStream { + input +} + +/// Make the resulting C function NOT support C++ unwinding (overrides default). +#[proc_macro_attribute] +pub fn no_unwind_abi(_: TokenStream, input: TokenStream) -> TokenStream { + input +} diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 9c033ce..992b24a 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -35,6 +35,8 @@ unstable = ["cglue-macro/unstable", "try_default"] task = ["cglue-macro/task"] layout_checks = ["cglue-macro/layout_checks", "abi_stable"] futures = ["_futures", "task", "cglue-macro/futures"] +unwind_abi_default = ["cglue-macro/unwind_abi_default"] +unwind_abi_ext = ["cglue-macro/unwind_abi_ext"] [package.metadata.docs.rs] features = ["std", "task", "futures"] diff --git a/cglue/build.rs b/cglue/build.rs index 3294c6a..a534c2c 100644 --- a/cglue/build.rs +++ b/cglue/build.rs @@ -1,11 +1,24 @@ use rustc_version::{version, Version}; fn main() { + let cfgs = [ + ("1.57.0", "const_panic_on_stable"), + ("1.65.0", "gats_on_stable"), + ("1.81.0", "c_unwind_on_stable"), + ]; + let version = version().unwrap(); - if version >= Version::parse("1.57.0").unwrap() { - println!("cargo:rustc-cfg=const_panic_on_stable"); + + for (v, c) in &cfgs { + println!("cargo::rustc-check-cfg=cfg({})", c); + if version >= Version::parse(v).unwrap() { + println!("cargo:rustc-cfg={}", c); + } } - if version >= Version::parse("1.65.0").unwrap() { - println!("cargo:rustc-cfg=gats_on_stable"); + + let test_cfgs = ["__cglue_force_no_unwind_abi"]; + + for c in &test_cfgs { + println!("cargo::rustc-check-cfg=cfg({})", c); } } diff --git a/cglue/src/tests/ext/futures.rs b/cglue/src/tests/ext/futures.rs index e91c2a2..b071f4e 100644 --- a/cglue/src/tests/ext/futures.rs +++ b/cglue/src/tests/ext/futures.rs @@ -38,6 +38,12 @@ fn use_sink() { }); // The logic of the sink should force a panic afterwards + // However, we cannot test this post 1.81 without explicitly opting in C-unwind ABI. + #[cfg(any( + feature = "unwind_abi_ext", + feature = "unwind_abi_default", + not(c_unwind_on_stable) + ))] assert!( std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || { pollster::block_on(obj.send(0)) diff --git a/cglue/src/tests/simple/traits.rs b/cglue/src/tests/simple/traits.rs index eb6f988..247ba68 100644 --- a/cglue/src/tests/simple/traits.rs +++ b/cglue/src/tests/simple/traits.rs @@ -38,6 +38,7 @@ type AliasResult = Result; #[cglue_trait] #[int_result(AliasResult)] pub trait WithAliasIntResult { + #[no_unwind_abi] fn waint_1(&self, val: usize) -> AliasResult { Ok(val) } @@ -70,47 +71,54 @@ type WIRCont = IRefCont>; type WAIRCont = IRefCont>; type WINTOCont = IRefCont>; +#[cfg(all(feature = "unwind_abi_default", not(__cglue_force_no_unwind_abi)))] +macro_rules! extern_fn { + ($(for<$lt:lifetime>)? ($($tt:ty),*) $(-> $ty:ty)?) => { $(for<$lt>)? unsafe extern "C-unwind" fn($($tt),*) $(-> $ty)? } +} + +#[cfg(any(not(feature = "unwind_abi_default"), __cglue_force_no_unwind_abi))] +macro_rules! extern_fn { + ($(for<$lt:lifetime>)? ($($tt:ty),*) $(-> $ty:ty)?) => { $(for<$lt>)? unsafe extern "C" fn($($tt),*) $(-> $ty)? } +} + #[test] fn slices_wrapped() { let vtbl = <&WithSliceVtbl>::default(); - let _: unsafe extern "C" fn(&mut WSCont, CSliceRef) = vtbl.wslice_1(); - let _: unsafe extern "C" fn(&mut WSCont, CSliceRef) = vtbl.wslice_2(); - let _: unsafe extern "C" fn(&mut WSCont) -> CSliceRef = vtbl.wslice_3(); - let _: for<'a> unsafe extern "C" fn(&'a mut WSCont, CSliceRef) -> CSliceRef<'a, u8> = + let _: extern_fn!((&mut WSCont, CSliceRef)) = vtbl.wslice_1(); + let _: extern_fn!((&mut WSCont, CSliceRef)) = vtbl.wslice_2(); + let _: extern_fn!((&mut WSCont) -> CSliceRef) = vtbl.wslice_3(); + let _: extern_fn!(for<'a> (&'a mut WSCont, CSliceRef) -> CSliceRef<'a, u8>) = vtbl.wslice_4(); } #[test] fn npo_option_forwarded() { let vtbl = <&WithOptionsVtbl>::default(); - let _: unsafe extern "C" fn(&WOCont, Option<&usize>) = vtbl.wopt_1(); + let _: extern_fn!((&WOCont, Option<&usize>)) = vtbl.wopt_1(); } #[test] fn non_npo_option_wrapped() { let vtbl = <&WithOptionsVtbl>::default(); - let _: unsafe extern "C" fn(&WOCont, crate::option::COption) = vtbl.wopt_2(); + let _: extern_fn!((&WOCont, crate::option::COption)) = vtbl.wopt_2(); } #[test] fn mixed_options() { let vtbl = <&WithOptionsVtbl>::default(); - let _: unsafe extern "C" fn(&mut WOCont, Option<&u64>, crate::option::COption) = - vtbl.wopt_3(); + let _: extern_fn!((&mut WOCont, Option<&u64>, crate::option::COption)) = vtbl.wopt_3(); } #[test] fn int_result() { let vtbl = <&WithIntResultVtbl>::default(); - let _: unsafe extern "C" fn(&WIRCont, usize, &mut core::mem::MaybeUninit) -> i32 = - vtbl.wint_1(); + let _: extern_fn!((&WIRCont, usize, &mut core::mem::MaybeUninit) -> i32) = vtbl.wint_1(); } #[test] fn no_int_result() { let vtbl = <&WithIntResultVtbl>::default(); - let _: unsafe extern "C" fn(&WIRCont, usize) -> crate::result::CResult = - vtbl.wint_2(); + let _: extern_fn!((&WIRCont, usize) -> crate::result::CResult) = vtbl.wint_2(); } #[test] @@ -123,12 +131,11 @@ fn alias_int_result() { #[test] fn alias_no_int_result() { let vtbl = <&WithAliasIntResultVtbl>::default(); - let _: unsafe extern "C" fn(&WAIRCont, usize) -> crate::result::CResult = - vtbl.waint_2(); + let _: extern_fn!((&WAIRCont, usize) -> crate::result::CResult) = vtbl.waint_2(); } #[test] fn into_t_wrapped() { let vtbl = <&WithIntoVtbl>::default(); - let _: unsafe extern "C" fn(&WINTOCont, usize) = vtbl.winto_1(); + let _: extern_fn!((&WINTOCont, usize)) = vtbl.winto_1(); } From a18dce0c59a40f51b6cbdb5cc4156ce5a6655648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Wed, 23 Apr 2025 20:00:51 +0100 Subject: [PATCH 39/41] Update CHANGELOG --- CHANGELOG.md | 13 +++++++++++++ Cargo.lock | 6 +++--- cglue-gen/Cargo.toml | 2 +- cglue-macro/Cargo.toml | 2 +- cglue/Cargo.toml | 2 +- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 449a940..c498fdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # CGlue changelog +## Changes in 0.3.5: + +### [Support `C-unwind` ABI](https://github.com/h33p/cglue/blob/7ccbdb762785609409a5dd0d16b315fee2dcf2ee) + +Adds support for `extern "C-unwind"` ABI through `#[unwind_abi]` attribute and `unwind_abi_default`/`unwind_abi_ext` feature flags: + +- `unwind_abi_default` will default all functions to support unwinding, which can be overridden with `#[no_unwind_abi]` attribute. +- `unwind_abi_ext` will add `#[unwind_abi]` to all functions in the builtin ext system. + +### [Add `CWaker`](https://github.com/h33p/cglue/blob/5302a750bdd483b01b5ea7de5ab4f8ad2036f8d3) + +Exposes `CWaker` as a static stable ABI waker type. + ## Changes in 0.3.0: ### [Stabilize `task` feature](https://github.com/h33p/cglue/blob/e6458ae5542daa489561495fb6c613307bb80001/cglue/src/task/mod.rs) diff --git a/Cargo.lock b/Cargo.lock index dd4946c..e4aa20e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,7 +88,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cglue" -version = "0.3.4" +version = "0.3.5" dependencies = [ "abi_stable", "cglue-macro", @@ -115,7 +115,7 @@ dependencies = [ [[package]] name = "cglue-gen" -version = "0.3.1" +version = "0.3.2" dependencies = [ "itertools", "lazy_static", @@ -127,7 +127,7 @@ dependencies = [ [[package]] name = "cglue-macro" -version = "0.3.0" +version = "0.3.1" dependencies = [ "cglue-gen", "proc-macro2", diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index e46ae20..1e1e0ad 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-gen" -version = "0.3.1" +version = "0.3.2" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe code generation for making plugins and C-compatible libraries" diff --git a/cglue-macro/Cargo.toml b/cglue-macro/Cargo.toml index 766e6cc..862877a 100644 --- a/cglue-macro/Cargo.toml +++ b/cglue-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue-macro" -version = "0.3.0" +version = "0.3.1" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe code generation macros for making plugins and C-compatible libraries" diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 992b24a..3817962 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cglue" -version = "0.3.4" +version = "0.3.5" authors = ["Aurimas Blažulionis <0x60@pm.me>"] edition = "2018" description = "FFI safe abstractions for making plugins and C-compatible libraries" From e0bf31daeae4ad11f558ac304e421a561f0f56f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Thu, 24 Apr 2025 20:22:21 +0000 Subject: [PATCH 40/41] Add feature for abi_stable 0.11 --- Cargo.lock | 197 +++++++++++++++++++++++++++++++--- Cargo.toml | 2 + cglue-gen/Cargo.toml | 1 + cglue-gen/src/func.rs | 5 +- cglue-gen/src/trait_groups.rs | 2 +- cglue-gen/src/traits.rs | 10 +- cglue-macro/Cargo.toml | 1 + cglue/Cargo.toml | 5 +- cglue/src/lib.rs | 49 ++++++++- version-hack/Cargo.toml | 2 +- 10 files changed, 247 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4aa20e..58298e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,14 +6,37 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7725ddc1a1204829816071550fdffafe7e66498e7a99e5f703da71801101ccb9" dependencies = [ - "abi_stable_derive", - "abi_stable_shared", + "abi_stable_derive 0.10.3", + "abi_stable_shared 0.10.3", "core_extensions", "crossbeam-channel", "generational-arena", "libloading", "lock_api", - "parking_lot", + "parking_lot 0.11.2", + "paste", + "repr_offset", + "rustc_version 0.4.0", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "abi_stable" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d6512d3eb05ffe5004c59c206de7f99c34951504056ce23fc953842f12c445" +dependencies = [ + "abi_stable_derive 0.11.3", + "abi_stable_shared 0.11.0", + "const_panic", + "core_extensions", + "crossbeam-channel", + "generational-arena", + "libloading", + "lock_api", + "parking_lot 0.12.3", "paste", "repr_offset", "rustc_version 0.4.0", @@ -28,8 +51,8 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b9810ef8debee5544010d92dac0b88b32853cd5bd5ca3298243c99e931da0f0" dependencies = [ - "abi_stable_shared", - "as_derive_utils", + "abi_stable_shared 0.10.3", + "as_derive_utils 0.10.3", "core_extensions", "proc-macro2", "quote", @@ -38,6 +61,22 @@ dependencies = [ "typed-arena", ] +[[package]] +name = "abi_stable_derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7178468b407a4ee10e881bc7a328a65e739f0863615cca4429d43916b05e898" +dependencies = [ + "abi_stable_shared 0.11.0", + "as_derive_utils 0.11.0", + "core_extensions", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn", + "typed-arena", +] + [[package]] name = "abi_stable_shared" version = "0.10.3" @@ -47,6 +86,15 @@ dependencies = [ "core_extensions", ] +[[package]] +name = "abi_stable_shared" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b5df7688c123e63f4d4d649cba63f2967ba7f7861b1664fca3f77d3dad2b63" +dependencies = [ + "core_extensions", +] + [[package]] name = "aho-corasick" version = "0.7.20" @@ -68,6 +116,18 @@ dependencies = [ "syn", ] +[[package]] +name = "as_derive_utils" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff3c96645900a44cf11941c111bd08a6573b0e2f9f69bc9264b179d8fae753c4" +dependencies = [ + "core_extensions", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -80,6 +140,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + [[package]] name = "cfg-if" version = "1.0.0" @@ -90,7 +156,8 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "cglue" version = "0.3.5" dependencies = [ - "abi_stable", + "abi_stable 0.10.4", + "abi_stable 0.11.3", "cglue-macro", "futures", "log", @@ -135,6 +202,12 @@ dependencies = [ "syn", ] +[[package]] +name = "const_panic" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2459fc9262a1aa204eb4b5764ad4f189caec88aea9634389c0a25f8be7f6265e" + [[package]] name = "core_extensions" version = "1.5.3" @@ -349,7 +422,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.10", ] [[package]] @@ -361,11 +444,24 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.11", + "smallvec", + "windows-targets", +] + [[package]] name = "paste" version = "1.0.14" @@ -388,7 +484,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" name = "plugin-api" version = "0.1.0" dependencies = [ - "abi_stable", + "abi_stable 0.10.4", "cglue", "libloading", ] @@ -443,7 +539,16 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +dependencies = [ + "bitflags 2.9.0", ] [[package]] @@ -525,18 +630,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.127" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.127" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -684,3 +789,67 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index 87db28f..e915d54 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,5 @@ default-members = [ "version-hack", ] +#[patch.crates-io] +#abi_stable = { version = "0.11", path = "../../other/abi_stable_crates/abi_stable" } diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index 1e1e0ad..90a9b44 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -28,3 +28,4 @@ task = [] futures = ["task"] unwind_abi_default = [] unwind_abi_ext = [] +abi_stable11 = [] diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index 161c574..bbc99cc 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -936,8 +936,9 @@ impl ParsedFunc { // ABI-Stable does not support C-unwind ABI, so hack around that. if cfg!(feature = "layout_checks") && self.unwind_safe { - let ty = quote!(for<#sig_life_declare> #unsafety extern "C" fn(#args #c_ret_params)) - .to_string(); + let ty = quote!(for<#sig_life_declare> #unsafety extern "C" fn(#args #c_ret_params)); + #[cfg(not(feature = "abi_stable11"))] + let ty = ty.to_string(); stream.extend(quote!(#[sabi(unsafe_change_type = #ty)])); } diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index 02e98e2..ffdcebe 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -742,7 +742,7 @@ impl TraitGroup { let mut enable_funcs_vtbl = TokenStream::new(); #[cfg(feature = "layout_checks")] - let derive_layouts = quote!(#[derive(::abi_stable::StableAbi)]); + let derive_layouts = quote!(#[derive(#crate_path::__sabi::StableAbi)]); #[cfg(not(feature = "layout_checks"))] let derive_layouts = quote!(); diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index d6284c7..b871be3 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -865,7 +865,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { }; #[cfg(feature = "layout_checks")] - let derive_layouts = quote!(#[derive(::abi_stable::StableAbi)]); + let derive_layouts = quote!(#[derive(#crate_path::__sabi::StableAbi)]); #[cfg(not(feature = "layout_checks"))] let derive_layouts = quote!(); @@ -1122,16 +1122,16 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { #[cfg(feature = "layout_checks")] let (opaque_vtbl_bounds, container_vtbl_bounds) = ( - quote!(#vtbl_ident<'cglue_a, CGlueC::OpaqueTarget, #gen_use #assoc_use>: ::abi_stable::StableAbi,), - quote!(#vtbl_ident<'cglue_a, ::ContType, #gen_use #assoc_use>: ::abi_stable::StableAbi,), + quote!(#vtbl_ident<'cglue_a, CGlueC::OpaqueTarget, #gen_use #assoc_use>: #crate_path::__sabi::StableAbi,), + quote!(#vtbl_ident<'cglue_a, ::ContType, #gen_use #assoc_use>: #crate_path::__sabi::StableAbi,), ); #[cfg(not(feature = "layout_checks"))] let (opaque_vtbl_bounds, container_vtbl_bounds) = (quote!(), quote!()); #[cfg(feature = "layout_checks")] let (layout_checkable_bound, objcont_accessor_bound) = ( - quote!(::abi_stable::StableAbi), - quote!(::ContType: ::abi_stable::StableAbi,), + quote!(#crate_path::__sabi::StableAbi), + quote!(::ContType: #crate_path::__sabi::StableAbi,), ); #[cfg(not(feature = "layout_checks"))] let (layout_checkable_bound, objcont_accessor_bound) = (quote!(), quote!()); diff --git a/cglue-macro/Cargo.toml b/cglue-macro/Cargo.toml index 862877a..c3f3a0b 100644 --- a/cglue-macro/Cargo.toml +++ b/cglue-macro/Cargo.toml @@ -29,3 +29,4 @@ task = ["cglue-gen/task"] futures = ["cglue-gen/futures", "task"] unwind_abi_default = ["cglue-gen/unwind_abi_default"] unwind_abi_ext = ["cglue-gen/unwind_abi_ext"] +abi_stable11 = ["cglue-gen/abi_stable11"] diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index 3817962..e06a165 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -16,10 +16,11 @@ cglue-macro = { version = "0.3", path = "../cglue-macro" } no-std-compat = { version = "0.4", features = ["alloc"] } serde = { version = "1", optional = true, default-features = false, features = ["derive", "alloc"] } try_default = { version = "= 1.0.0", optional = true } -abi_stable = { version = "0.10", optional = true } log = { version = "0.4", optional = true } tarc = { version = "0.1", default-features = false } _futures = { package = "futures", version = "0.3", optional = true, default-features = false } +abi_stable10 = { package = "abi_stable", version = "0.10", optional = true, default-features = false } +_abi_stable11 = { package = "abi_stable", version = "0.11", optional = true, default-features = false, features = ["rust_latest_stable"] } [build-dependencies] rustc_version = "0.4" @@ -37,6 +38,8 @@ layout_checks = ["cglue-macro/layout_checks", "abi_stable"] futures = ["_futures", "task", "cglue-macro/futures"] unwind_abi_default = ["cglue-macro/unwind_abi_default"] unwind_abi_ext = ["cglue-macro/unwind_abi_ext"] +abi_stable11 = ["_abi_stable11", "cglue-macro/abi_stable11"] +abi_stable = ["abi_stable10"] [package.metadata.docs.rs] features = ["std", "task", "futures"] diff --git a/cglue/src/lib.rs b/cglue/src/lib.rs index 6dbace9..e5e416e 100644 --- a/cglue/src/lib.rs +++ b/cglue/src/lib.rs @@ -46,6 +46,7 @@ //! and they should be good to go! //! //! ```rust +//! # __export_abi_stable!(); //! use cglue::*; //! //! // One annotation for the trait. @@ -95,6 +96,7 @@ //! But that's not all, you can also group traits together! //! //! ``` +//! # __export_abi_stable!(); //! use cglue::*; //! //! # // Previous definitions @@ -291,6 +293,7 @@ //! Define a group with the standard template syntax: //! //! ``` +//! # __export_abi_stable!(); //! # use cglue::*; //! # #[cglue_trait] //! # pub trait TA { @@ -320,6 +323,7 @@ //! It is also possible to specify trait bounds: //! //! ``` +//! # __export_abi_stable!(); //! # use cglue::*; //! # #[cglue_trait] //! # pub trait TA { @@ -349,6 +353,7 @@ //! Or: //! //! ``` +//! # __export_abi_stable!(); //! # use cglue::*; //! # #[cglue_trait] //! # pub trait TA { @@ -378,6 +383,7 @@ //! Implement the group on a generic type: //! //! ``` +//! # __export_abi_stable!(); //! # use cglue::*; //! # #[cglue_trait] //! # pub trait TA { @@ -412,6 +418,7 @@ //! on the line: //! //! ``` +//! # __export_abi_stable!(); //! # use cglue::*; //! # #[cglue_trait] //! # pub trait TA { @@ -447,6 +454,7 @@ //! optional traits defined: //! //! ``` +//! # __export_abi_stable!(); //! # use cglue::*; //! # #[cglue_trait] //! # pub trait TA { @@ -484,6 +492,7 @@ //! the above 2 macro invocations expand to: //! //! ``` +//! # __export_abi_stable!(); //! # use cglue::*; //! # #[cglue_trait] //! # pub trait TA { @@ -553,6 +562,7 @@ //! actual trait, like so: //! //! ```ignore +//! # __export_abi_stable!(); //! # use cglue::*; //! #[cglue_trait_ext] //! pub trait Clone { @@ -569,6 +579,7 @@ //! complicated when groups are involved. This is how a `MaybeClone` group would be implemented: //! //! ```ignore +//! # __export_abi_stable!(); //! # use cglue::*; //! # #[cglue_trait_ext] //! # pub trait Clone { @@ -593,6 +604,7 @@ //! code gets simplified to just this: //! //! ``` +//! # __export_abi_stable!(); //! # use cglue::*; //! cglue_trait_group!(MaybeClone, { }, { Clone }); //! # fn main() {} @@ -601,6 +613,7 @@ //! For traits not in the prelude, they can be accessed through their fully qualified `::ext` path: //! //! ``` +//! # __export_abi_stable!(); //! # use cglue::*; //! cglue_trait_group!(MaybeAsRef, { }, { ::ext::core::convert::AsRef }); //! # fn main() {} @@ -666,6 +679,7 @@ //! this in action: //! //! ``` +//! # __export_abi_stable!(); //! use cglue::*; //! # // Previous definitions //! # #[cglue_trait] @@ -755,6 +769,8 @@ //! //! ``` //! # #[cfg(gats_on_stable)] +//! # cglue::__export_abi_stable!(); +//! # #[cfg(gats_on_stable)] //! # mod gats { //! use cglue::*; //! # // Previous definitions @@ -762,8 +778,8 @@ //! # pub trait InfoPrinter { //! # fn print_info(&self); //! # } -//! # struct Info { -//! # value: usize +//! # pub struct Info { +//! # pub value: usize //! # } //! # impl InfoPrinter for Info { //! # fn print_info(&self) { @@ -784,7 +800,9 @@ //! } //! } //! +//! # pub //! struct InfoStore { +//! # pub //! info: Info, //! } //! @@ -795,8 +813,12 @@ //! &mut self.info //! } //! } +//! # } //! +//! # #[cfg(gats_on_stable)] //! # fn main() { +//! # use gats::*; +//! # use cglue::*; //! let builder = InfoStore { info: Info { value: 50 } }; //! //! let mut obj = trait_obj!(builder as LendingPrinter); @@ -805,7 +827,6 @@ //! //! info_printer.print_info(); //! # } -//! # } //! ``` //! //! ### Plugin system @@ -818,6 +839,7 @@ //! until all of the CGlue objects are dropped. //! //! ``` +//! # __export_abi_stable!(); //! use cglue::prelude::v1::*; //! //! #[cglue_trait] @@ -845,6 +867,7 @@ //! object. //! //! ``` +//! # __export_abi_stable!(); //! # use cglue::prelude::v1::*; //! # use std::sync::Arc; //! # #[cglue_trait] @@ -997,6 +1020,26 @@ #![cfg_attr(not(feature = "std"), no_std)] extern crate no_std_compat as std; +#[doc(hidden)] +#[macro_export] +macro_rules! __export_abi_stable { + () => { + #[cfg(all(feature = "abi_stable10", not(feature = "_abi_stable11")))] + extern crate abi_stable10 as abi_stable; + + #[cfg(feature = "_abi_stable11")] + extern crate _abi_stable11 as abi_stable; + }; +} + +__export_abi_stable!(); + +#[cfg(feature = "abi_stable")] +#[doc(hidden)] +pub mod __sabi { + pub use ::abi_stable::*; +} + #[cfg(feature = "futures")] extern crate _futures as futures; diff --git a/version-hack/Cargo.toml b/version-hack/Cargo.toml index 7037b91..b719ff0 100644 --- a/version-hack/Cargo.toml +++ b/version-hack/Cargo.toml @@ -9,7 +9,7 @@ indexmap = "~1.7" once_cell = "~1.14" thiserror = "=1.0.24" thiserror-impl = "=1.0.24" -serde = "=1.0.127" +serde = "=1.0.136" proc-macro2 = "=1.0.65" memchr = "=2.4.1" log = "=0.4.18" From 4ce5752f7005fb917ce263fc8bd2af238355ee24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aurimas=20Bla=C5=BEulionis?= <0x60@pm.me> Date: Fri, 25 Apr 2025 15:15:16 +0000 Subject: [PATCH 41/41] Fix with latest miri --- .github/workflows/build.yml | 26 +++---- Cargo.lock | 40 +--------- README.md | 10 +-- cglue-bindgen/src/codegen/c.rs | 18 ++++- cglue-bindgen/src/codegen/cpp.rs | 18 ++++- cglue-bindgen/src/types.rs | 2 +- cglue-gen/Cargo.toml | 1 + cglue-gen/build.rs | 2 +- cglue-gen/src/func.rs | 60 +++++++++------ cglue-gen/src/trait_groups.rs | 39 +++++----- cglue-gen/src/traits.rs | 24 ++++-- cglue-macro/Cargo.toml | 1 + cglue/Cargo.toml | 1 + cglue/build.rs | 4 +- cglue/src/arc.rs | 125 +++++++++++++++++++++---------- cglue/src/boxed.rs | 46 +++++++++--- cglue/src/lib.rs | 14 ++-- cglue/src/trait_group.rs | 119 ++++++++++++++++++----------- examples/plugin-api/Cargo.toml | 6 +- examples/plugin-api/src/lib.rs | 6 ++ 20 files changed, 347 insertions(+), 215 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8b312f3..ed3ea8b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - toolchain: ["1.45.0", "stable"] + toolchain: ["1.56.0", "stable"] include: - os: macos-14 toolchain: "stable" @@ -58,7 +58,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - toolchain: ["1.46.0", "stable"] + toolchain: ["1.56.0", "stable"] include: - os: macos-14 toolchain: "stable" @@ -80,7 +80,7 @@ jobs: strategy: matrix: os: [macos-14, ubuntu-latest, windows-latest] - toolchain: ["1.57.0", "stable", "nightly-2021-11-05"] + toolchain: ["1.64.0", "stable", "nightly-2022-08-08"] steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -104,7 +104,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - toolchain: ["1.45.0", "stable"] + toolchain: ["1.56.0", "stable"] steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -123,7 +123,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - toolchain: ["1.45.0", "stable"] + toolchain: ["1.56.0", "stable"] include: - os: macos-14 toolchain: "stable" @@ -144,7 +144,7 @@ jobs: strategy: matrix: os: [macos-14, ubuntu-latest, windows-latest] - toolchain: ["1.57.0", "stable", "nightly-2021-11-05"] + toolchain: ["1.64.0", "stable", "nightly-2022-08-08"] steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -175,11 +175,11 @@ jobs: env: RUSTC_BOOTSTRAP: try_default - patched-miri: + miri: runs-on: ubuntu-latest strategy: matrix: - toolchain: ["nightly-2021-11-05"] + toolchain: ["nightly-2024-11-22"] steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -187,25 +187,19 @@ jobs: toolchain: ${{ matrix.toolchain }} override: true - run: rustup component add miri - - name: Patch out a part of miri to allow type erasure - run: | - cargo install --git https://github.com/h33p/miri-rustabi-patcher.git - miri-rustabi-patcher ~/.rustup/toolchains/${{ matrix.toolchain }}-x86_64-unknown-linux-gnu/bin/miri - mv ~/.rustup/toolchains/${{ matrix.toolchain }}-x86_64-unknown-linux-gnu/bin/miri.patched ~/.rustup/toolchains/${{ matrix.toolchain }}-x86_64-unknown-linux-gnu/bin/miri - chmod +x ~/.rustup/toolchains/${{ matrix.toolchain }}-x86_64-unknown-linux-gnu/bin/miri - name: Install locked xargo run: | cargo install xargo --locked --version 0.3.26 - name: Run miri run: | cd cglue - MIRIFLAGS="-Zmiri-disable-stacked-borrows" RUSTFLAGS="--cfg __cglue_force_no_unwind_abi" cargo miri test --features rust_void + MIRIFLAGS="-Zmiri-symbolic-alignment-check -Zmiri-retag-fields=all -Zmiri-symbolic-alignment-check -Zmiri-strict-provenance -Zmiri-tree-borrows" RUSTFLAGS="--cfg __cglue_force_no_unwind_abi" cargo miri test --features rust_void c-examples: runs-on: ubuntu-latest strategy: matrix: - toolchain: ["1.46.0", "stable"] + toolchain: ["1.56.0", "stable"] steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 diff --git a/Cargo.lock b/Cargo.lock index 58298e3..717bffe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "abi_stable" version = "0.10.4" @@ -9,7 +11,6 @@ dependencies = [ "abi_stable_derive 0.10.3", "abi_stable_shared 0.10.3", "core_extensions", - "crossbeam-channel", "generational-arena", "libloading", "lock_api", @@ -19,7 +20,6 @@ dependencies = [ "rustc_version 0.4.0", "serde", "serde_derive", - "serde_json", ] [[package]] @@ -32,7 +32,6 @@ dependencies = [ "abi_stable_shared 0.11.0", "const_panic", "core_extensions", - "crossbeam-channel", "generational-arena", "libloading", "lock_api", @@ -42,7 +41,6 @@ dependencies = [ "rustc_version 0.4.0", "serde", "serde_derive", - "serde_json", ] [[package]] @@ -223,16 +221,6 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6" -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.16" @@ -352,12 +340,6 @@ dependencies = [ "either", ] -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - [[package]] name = "lazy_static" version = "1.4.0" @@ -485,6 +467,7 @@ name = "plugin-api" version = "0.1.0" dependencies = [ "abi_stable 0.10.4", + "abi_stable 0.11.3", "cglue", "libloading", ] @@ -595,12 +578,6 @@ dependencies = [ "semver 1.0.21", ] -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - [[package]] name = "scopeguard" version = "1.2.0" @@ -648,17 +625,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "smallvec" version = "1.13.1" diff --git a/README.md b/README.md index f90fc1f..a9199e8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # CGlue -[![Crates.io]][crates] [![API Docs]][docs] [![Build and test]][workflows] [![MIT licensed]][license] [![Rustc 1.45]][rust] +[![Crates.io]][crates] [![API Docs]][docs] [![Build and test]][workflows] [![MIT licensed]][license] [![Rustc 1.56]][rust] [Crates.io]: https://img.shields.io/crates/v/cglue.svg [crates]: https://crates.io/crates/cglue @@ -11,8 +11,8 @@ [workflows]: https://github.com/h33p/cglue/actions/workflows/build.yml [MIT licensed]: https://img.shields.io/badge/license-MIT-blue.svg [license]: https://github.com/h33p/cglue/blob/main/LICENSE -[Rustc 1.45]: https://img.shields.io/badge/rustc-1.45+-lightgray.svg -[rust]: https://blog.rust-lang.org/2020/07/16/Rust-1.45.0.html +[Rustc 1.56]: https://img.shields.io/badge/rustc-1.56+-lightgray.svg +[rust]: https://blog.rust-lang.org/2020/07/16/Rust-1.56.0.html If all code is glued together, our glue is the safest on the market. @@ -329,7 +329,7 @@ the above 2 macro invocations expand to: ```rust impl< 'cglue_a, - CGlueInst: ::core::ops::Deref>, + CGlueInst: cglue::trait_group::InstanceBounds>, CGlueCtx: cglue::trait_group::ContextBounds, T: Eq, > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, T> for GA @@ -348,7 +348,7 @@ where } impl< 'cglue_a, - CGlueInst: ::core::ops::Deref>, + CGlueInst: cglue::trait_group::InstanceBounds>, CGlueCtx: cglue::trait_group::ContextBounds, > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, u64> for GA { diff --git a/cglue-bindgen/src/codegen/c.rs b/cglue-bindgen/src/codegen/c.rs index 83a33c0..c50e267 100644 --- a/cglue-bindgen/src/codegen/c.rs +++ b/cglue-bindgen/src/codegen/c.rs @@ -76,8 +76,16 @@ pub fn parse_header(header: &str, config: &Config) -> Result { // PROCESSING: + // Remove OpaqueHelper definition + let oht_regex = opaque_helper_typedef_regex()?; + let header = oht_regex.replace_all(&header, ""); + + // Remap all OpaqueHelper usage + let ohu_regex = opaque_helper_usage_regex()?; + let header = ohu_regex.replace_all(&header, "struct "); + // Remove zsized ret tmps - let header = zsr_regex.replace_all(header, ""); + let header = zsr_regex.replace_all(&header, ""); let gr_regex = group_ret_tmp_regex(&zst_rets)?; let header = gr_regex.replace_all(&header, ""); @@ -804,6 +812,14 @@ fn callback_regex() -> Result { .map_err(Into::into) } +fn opaque_helper_typedef_regex() -> Result { + Regex::new("(\n)?typedef OpaqueTarget OpaqueHelper_.*;\n").map_err(Into::into) +} + +fn opaque_helper_usage_regex() -> Result { + Regex::new("OpaqueHelper_").map_err(Into::into) +} + fn zero_sized_ret_regex() -> Result { Regex::new( r" diff --git a/cglue-bindgen/src/codegen/cpp.rs b/cglue-bindgen/src/codegen/cpp.rs index 8584e06..e9989ca 100644 --- a/cglue-bindgen/src/codegen/cpp.rs +++ b/cglue-bindgen/src/codegen/cpp.rs @@ -115,7 +115,11 @@ pub fn parse_header(header: &str, config: &Config) -> Result { // Fix up the MaybeUninit // Basically, we strip it completely, and then define `RustMaybeUninit` for special cases. - let header = &strip_maybe_uninit(header); + let mut header = header.to_string(); + for w in &["MaybeUninit", "OpaqueHelper"] { + header = strip_wrapper(&header, w); + } + let header = &header; // COLLECTION: @@ -164,6 +168,13 @@ pub fn parse_header(header: &str, config: &Config) -> Result { // PROCESSING: + let header = header.replace( + r" +template +using OpaqueHelper = OpaqueTarget;", + "", + ); + let header = header.replace( "struct MaybeUninit;", r"struct alignas(alignof(T)) RustMaybeUninit { @@ -895,10 +906,11 @@ struct [^\{\}\n]+<.*CGlueInst.*>)?", Ok(header) } -fn strip_maybe_uninit(header: &str) -> String { +fn strip_wrapper(header: &str, wrapper: &str) -> String { let mut out = String::new(); - let mut iter = header.split("MaybeUninit<"); + let split = format!("{}<", wrapper); + let mut iter = header.split(&split); if let Some(v) = iter.next() { out += v; diff --git a/cglue-bindgen/src/types.rs b/cglue-bindgen/src/types.rs index f2a6385..9cbabc5 100644 --- a/cglue-bindgen/src/types.rs +++ b/cglue-bindgen/src/types.rs @@ -201,7 +201,7 @@ impl Function { if wrap_in_container { for v in vtbls { - copied_vtbls.push_str(&format!("\n __ret.{} = {}{};", v, this_access, v)); + copied_vtbls.push_str(&format!("\n __ret.{} = {}{};", v, this_access, v)); } } diff --git a/cglue-gen/Cargo.toml b/cglue-gen/Cargo.toml index 90a9b44..7679796 100644 --- a/cglue-gen/Cargo.toml +++ b/cglue-gen/Cargo.toml @@ -10,6 +10,7 @@ repository = "https://github.com/h33p/cglue" keywords = [ "cglue", "abi", "ffi", "cbindgen", "macro" ] categories = [ "api-bindings", "accessibility", "parsing" ] readme = "../README.md" +rust-version = "1.56" [dependencies] syn = { version = "1", features = ["full", "extra-traits"] } diff --git a/cglue-gen/build.rs b/cglue-gen/build.rs index 6a2b6d7..6278b41 100644 --- a/cglue-gen/build.rs +++ b/cglue-gen/build.rs @@ -1,3 +1,3 @@ fn main() { - println!("cargo::rustc-check-cfg=cfg(__cglue_force_no_unwind_abi)"); + println!("cargo:rustc-check-cfg=cfg(__cglue_force_no_unwind_abi)"); } diff --git a/cglue-gen/src/func.rs b/cglue-gen/src/func.rs index bbc99cc..dfb9370 100644 --- a/cglue-gen/src/func.rs +++ b/cglue-gen/src/func.rs @@ -146,10 +146,10 @@ struct TraitArgConv { to_c_args: TokenStream, /// Arguments inside the call to the C vtable function. call_c_args: TokenStream, - /// C function signature. - c_args: TokenStream, - /// C function signature, where 'cglue_a lifetimes are replaced with 'cglue_b. - c_cast_args: TokenStream, + /// C function signature (in getters). + c_impl_args: TokenStream, + /// C function signature (in getters), where 'cglue_a lifetimes are replaced with 'cglue_b. + c_impl_args_cast: TokenStream, /// Arguments inside the call to the trait function. to_trait_arg: TokenStream, } @@ -263,7 +263,7 @@ impl TraitArgConv { inject_lifetime_cast: Option<&Lifetime>, lifetime_map: &BTreeMap, ) -> Self { - let (to_c_args, call_c_args, c_args, c_cast_args, to_trait_arg) = match arg { + let (to_c_args, call_c_args, c_impl_args, c_impl_args_cast, to_trait_arg) = match arg { FnArg::Receiver(r) => { let lifetime = inject_lifetime.or_else(|| r.lifetime()); let lifetime_cast = inject_lifetime_cast.or_else(|| r.lifetime()); @@ -278,10 +278,11 @@ impl TraitArgConv { // separately // TODO 2: figure out how to test this. let __ctx = #crate_path::trait_group::CGlueObjBase::cobj_base_ref(&cont).1.clone(); + let cont = #crate_path::trait_group::OpaqueHelper::new(cont); }, quote!(cont,), - quote!(cont: CGlueC,), - quote!(cont: CGlueC,), + quote!(cont: #crate_path::trait_group::OpaqueHelper,), + quote!(cont: #crate_path::trait_group::OpaqueHelper,), quote!(), ) } else if r.mutability.is_some() { @@ -491,8 +492,8 @@ impl TraitArgConv { Self { to_c_args, call_c_args, - c_args, - c_cast_args, + c_impl_args, + c_impl_args_cast, to_trait_arg, } } @@ -797,21 +798,21 @@ impl ParsedFunc { } } - pub fn vtbl_args(&self) -> TokenStream { + pub fn c_impl_args(&self) -> TokenStream { let mut ret = TokenStream::new(); for arg in &self.args { - arg.c_args.to_tokens(&mut ret); + arg.c_impl_args.to_tokens(&mut ret); } ret } - pub fn vtbl_args_cast(&self) -> TokenStream { + pub fn c_impl_args_cast(&self) -> TokenStream { let mut ret = TokenStream::new(); for arg in &self.args { - arg.c_cast_args.to_tokens(&mut ret); + arg.c_impl_args_cast.to_tokens(&mut ret); } ret @@ -899,7 +900,7 @@ impl ParsedFunc { let name = &self.name; let unsafety = &self.get_safety(); let extern_abi = self.extern_abi(); - let args = self.vtbl_args(); + let args = self.c_impl_args(); let ParsedReturnType { c_out, c_cast_out, @@ -923,7 +924,7 @@ impl ParsedFunc { lifetime_cast, *unbounded_hrtb, ) { - (_, Some(lifetime), false) => (quote!(#lifetime), self.vtbl_args_cast(), c_cast_out), + (_, Some(lifetime), false) => (quote!(#lifetime), self.c_impl_args_cast(), c_cast_out), (Some(lifetime), _, _) => (quote!(#lifetime), args, c_out), _ => (quote!(), args, c_out), }; @@ -948,7 +949,7 @@ impl ParsedFunc { /// Create a VTable definition for this function pub fn vtbl_getter_def(&self, stream: &mut TokenStream) { let name = &self.name; - let args = self.vtbl_args(); + let args = self.c_impl_args(); let extern_abi = self.extern_abi(); let ParsedReturnType { c_out, @@ -973,7 +974,7 @@ impl ParsedFunc { lifetime_cast, *unbounded_hrtb, ) { - (_, Some(lifetime), false) => (quote!(#lifetime), self.vtbl_args_cast(), c_cast_out), + (_, Some(lifetime), false) => (quote!(#lifetime), self.c_impl_args_cast(), c_cast_out), (Some(lifetime), _, _) => (quote!(#lifetime), args, c_out), _ => (quote!(), args, c_out), }; @@ -982,6 +983,9 @@ impl ParsedFunc { let doc_text = format!(" Getter for {}.", name); + let name2 = format_ident!("{}_cast", name); + let safety = self.get_safety(); + let gen = quote! { #[doc = #doc_text] /// @@ -990,16 +994,22 @@ impl ParsedFunc { pub fn #name(&self) -> for<#sig_life_declare> unsafe extern #extern_abi fn(#args #c_ret_params) #c_out { unsafe { ::core::mem::transmute(self.#name) } } + + #[doc = #doc_text] + /// + /// Note that this function is wrapped into unsafe, because if already were is an + /// opaque one, it would allow to invoke undefined behaviour. + unsafe fn #name2(&self) -> for<#sig_life_declare> #safety extern #extern_abi fn(#args #c_ret_params) #c_out { + unsafe { ::core::mem::transmute(self.#name) } + } }; stream.extend(gen); if lifetime_cast.is_some() && *unbounded_hrtb { - let name2 = format_ident!("{}_lifetimed", name); - - let safety = self.get_safety(); + let name2 = format_ident!("{}_cast_lifetimed", name); - let args_cast = self.vtbl_args_cast(); + let args_cast = self.c_impl_args_cast(); let gen = quote! { #[doc = #doc_text] @@ -1040,7 +1050,7 @@ impl ParsedFunc { } let name = &self.name; - let args = self.vtbl_args(); + let args = self.c_impl_args(); let extern_abi = self.extern_abi(); let ParsedReturnType { c_out, @@ -1109,6 +1119,7 @@ impl ParsedFunc { ( quote! { + let cont = cont.take_raw(); let (this, cglue_ctx) = cont.cobj_base_owned(); let this = unsafe { #trg_path::IntoInner::into_inner(this) }; #c_pre_call @@ -1221,10 +1232,11 @@ impl ParsedFunc { } = &self.sig_generics; let get_vfunc = if lifetime_cast.is_some() && *unbounded_hrtb { - let name_lifetimed = format_ident!("{}_lifetimed", name); + let name_lifetimed = format_ident!("{}_cast_lifetimed", name); quote!(unsafe { self.get_vtbl().#name_lifetimed() }) } else { - quote!(self.get_vtbl().#name) + let name_cast = format_ident!("{}_cast", name); + quote!(unsafe { self.get_vtbl().#name_cast() }) }; let custom_precall_impl = self.custom_conv.pre_call_impl.to_token_stream(); diff --git a/cglue-gen/src/trait_groups.rs b/cglue-gen/src/trait_groups.rs index ffdcebe..8b6284d 100644 --- a/cglue-gen/src/trait_groups.rs +++ b/cglue-gen/src/trait_groups.rs @@ -391,6 +391,7 @@ impl TraitGroupImpl { #[cfg(not(feature = "unstable"))] pub fn implement_group(&self) -> TokenStream { let crate_path = crate_path(); + let trg_path: TokenStream = quote!(#crate_path::trait_group); let ctx_bound = super::traits::ctx_bound(); @@ -463,7 +464,7 @@ impl TraitGroupImpl { ); let gen = quote! { - impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + impl<#life_declare CGlueInst: #trg_path::InstanceBounds, CGlueCtx: #ctx_bound, #gen_declare> #group_path #filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use> for #ty where #gen_where_bounds #vtbl_where_bounds { fn fill_table(table: #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use>) -> #group_path #vtable_type<#life_use CGlueInst, CGlueCtx, #gen_use> { @@ -491,7 +492,7 @@ impl TraitGroupImpl { quote! { #gen - impl<#life_declare CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + impl<#life_declare CGlueInst: #trg_path::InstanceBounds, CGlueCtx: #ctx_bound, #gen_declare> #group_path #fwd_filler_trait<#life_use CGlueInst, CGlueCtx, #gen_use> for #ty where #cont_name: #crate_path::trait_group::CGlueObjBase, @@ -1111,7 +1112,7 @@ impl TraitGroup { #[cfg(not(feature = "unstable"))] let (extra_filler_traits, filler_trait_imports) = if self.extra_filler_traits { let traits = quote! { - pub trait #fwd_filler_trait<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare>: 'cglue_a + Sized + pub trait #fwd_filler_trait<'cglue_a, CGlueInst: #trg_path::InstanceBounds, CGlueCtx: #ctx_bound, #gen_declare>: 'cglue_a + Sized where #cont_name: #trg_path::CGlueObjBase, #gen_where_bounds @@ -1119,7 +1120,7 @@ impl TraitGroup { fn fill_fwd_table(table: #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>) -> #vtable_type<'cglue_a, CGlueInst, CGlueCtx, #gen_use>; } - impl<'cglue_a, CGlueInst: ::core::ops::Deref>, CGlueT, CGlueCtx: #ctx_bound, #gen_declare> + impl<'cglue_a, CGlueInst: #trg_path::InstanceBounds>, CGlueT, CGlueCtx: #ctx_bound, #gen_declare> #filler_trait<'cglue_a, CGlueInst, CGlueCtx, #gen_use> for #crate_path::forward::Fwd<&'cglue_a mut CGlueT> where @@ -1361,7 +1362,7 @@ impl TraitGroup { = #base_name_arc_box<'cglue_a, #c_void, #c_void, #gen_use>; - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + impl<'cglue_a, CGlueInst: #trg_path::InstanceBounds, CGlueCtx: #ctx_bound, #gen_declare> From<(CGlueInst, CGlueCtx)> for #cont_name where Self: #trg_path::CGlueObjBase @@ -1376,7 +1377,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, CGlueCtx: #ctx_bound, #gen_declare> + impl<'cglue_a, CGlueT: Send, CGlueCtx: #ctx_bound, #gen_declare> From<(CGlueT, CGlueCtx)> for #cont_name<#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use> where Self: #trg_path::CGlueObjBase @@ -1386,7 +1387,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + impl<'cglue_a, CGlueInst: #trg_path::InstanceBounds, CGlueCtx: #ctx_bound, #gen_declare> From<#cont_name> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where #cont_name: #trg_path::CGlueObjBase, @@ -1409,7 +1410,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #gen_declare> + impl<'cglue_a, CGlueInst: #trg_path::InstanceBounds, CGlueCtx: #ctx_bound, #gen_declare> From<(CGlueInst, CGlueCtx)> for #name<'cglue_a, CGlueInst, CGlueCtx, #gen_use> where Self: From<#cont_name>, @@ -1421,7 +1422,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, #gen_declare> + impl<'cglue_a, CGlueT: Send, #gen_declare> From for #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use> where Self: From<(#crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext)>, @@ -1432,7 +1433,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: core::ops::Deref, #gen_declare> From + impl<'cglue_a, CGlueInst: #trg_path::InstanceBounds, #gen_declare> From for #name<'cglue_a, CGlueInst, #trg_path::NoContext, #gen_use> where Self: From<(CGlueInst, #crate_path::trait_group::NoContext)>, @@ -1444,7 +1445,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, CGlueCtx: #ctx_bound, #gen_declare> From<(CGlueT, CGlueCtx)> + impl<'cglue_a, CGlueT: Send, CGlueCtx: #ctx_bound, #gen_declare> From<(CGlueT, CGlueCtx)> for #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx, #gen_use> where Self: From<(#crate_path::boxed::CBox<'cglue_a, CGlueT>, CGlueCtx)>, @@ -1479,7 +1480,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueT, #gen_declare> #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use> + impl<'cglue_a, CGlueT: Send, #gen_declare> #name<'cglue_a, #crate_path::boxed::CBox<'cglue_a, CGlueT>, #crate_path::trait_group::NoContext, #gen_use> where #gen_where_bounds { #[doc = #new_doc] @@ -1507,7 +1508,7 @@ impl TraitGroup { impl< 'cglue_a, - CGlueInst, //: ::core::ops::Deref + CGlueInst, //: #trg_path::InstanceBounds CGlueCtx: #ctx_bound, #gen_declare > @@ -1790,7 +1791,7 @@ impl TraitGroup { let ctx_bound = super::traits::ctx_bound(); quote! { - impl + impl #trg_path::GetContainer for #name<'_, CGlueInst, CGlueCtx, #gen_use> where #cont_name: #trg_path::CGlueObjBase, @@ -1833,7 +1834,7 @@ impl TraitGroup { let ctx_bound = super::traits::ctx_bound(); let mut ret = quote! { - impl #trg_path::CGlueObjBase + impl #trg_path::CGlueObjBase for #cont_name where CGlueInst::Target: Sized, @@ -1865,7 +1866,7 @@ impl TraitGroup { } in self.mandatory_vtbl.iter().chain(self.optional_vtbl.iter()) { ret.extend(quote!{ - impl + impl #trg_path::CGlueObjRef<#path #ret_tmp_typename> for #cont_name where @@ -1878,7 +1879,7 @@ impl TraitGroup { } impl< - CGlueInst: ::core::ops::DerefMut, + CGlueInst: #trg_path::InstanceBounds + ::core::ops::DerefMut, CGlueCtx: #ctx_bound, #all_gen_declare > #trg_path::CGlueObjMut<#path #ret_tmp_typename> @@ -1962,7 +1963,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #all_gen_declare> #path #vtbl_get_ident<'cglue_a, #gen_use #assoc_use> + impl<'cglue_a, CGlueInst: #trg_path::InstanceBounds, CGlueCtx: #ctx_bound, #all_gen_declare> #path #vtbl_get_ident<'cglue_a, #gen_use #assoc_use> for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use> where ::Target: Sized, @@ -1974,7 +1975,7 @@ impl TraitGroup { } } - impl<'cglue_a, CGlueInst: ::core::ops::Deref, CGlueCtx: #ctx_bound, #all_gen_declare> #path #assoc_bind_ident<#gen_use> + impl<'cglue_a, CGlueInst: #trg_path::InstanceBounds, CGlueCtx: #ctx_bound, #all_gen_declare> #path #assoc_bind_ident<#gen_use> for #name<'cglue_a, CGlueInst, CGlueCtx, #all_gen_use> where ::Target: Sized, diff --git a/cglue-gen/src/traits.rs b/cglue-gen/src/traits.rs index b871be3..b03f3de 100644 --- a/cglue-gen/src/traits.rs +++ b/cglue-gen/src/traits.rs @@ -341,15 +341,21 @@ pub fn process_item( ) }; - let type_bounds = quote! { + let mut type_bounds = quote! { for<#hrtb_lifetime> #ty_ref: Into<#from_new_ty>, for<#hrtb_lifetime> #from_new_ty: #crate_path::trait_group::Opaquable, }; - let type_bounds_simple = quote! { + let mut type_bounds_simple = quote! { #ty_ref_simple: Into<#from_new_ty_simple>, #from_new_ty_simple: #crate_path::trait_group::Opaquable, }; + + if ["wrap_with_group", "wrap_with_obj"].contains(&x) { + type_bounds.extend(quote!(for<#hrtb_lifetime> #from_new_ty_ref #cglue_f_ty_def: Send,)); + type_bounds_simple.extend(quote!(for<#hrtb_lifetime> #from_new_ty_simple_ref #cglue_f_ty_simple_ident: Send,)); + } + (Some(type_bounds), Some(type_bounds_simple)) } else if lifetime_bound == Some(&static_lifetime) { ( @@ -550,15 +556,19 @@ pub fn parse_trait( types.insert( Some(AssocType::from(format_ident!("Self"))), + // TODO: do not expose OpaqueHelper in the non-shadow vtable + // Need to rework return type wrapping... WrappedType { - ty: parse2(quote!(CGlueC)).unwrap(), + ty: parse2(quote!(#crate_path::trait_group::OpaqueHelper)).unwrap(), // TODO: should we forward ty in here?? ty_ret_tmp: None, ty_static: None, return_conv: Some( parse2(quote!(|ret| { use #crate_path::from2::From2; - CGlueC::from2((ret, cglue_ctx)) + #crate_path::trait_group::OpaqueHelper::new( + CGlueC::from2((ret, cglue_ctx)) + ) })) .expect("Internal closure parsing fail"), ), @@ -566,7 +576,7 @@ pub fn parse_trait( lifetime_type_bound: None, other_bounds: Some(quote!((CGlueC::ObjType, CGlueCtx): Into,)), other_bounds_simple: Some(quote!((CGlueC::ObjType, CGlueCtx): Into,)), - impl_return_conv: Some(quote!(self.build_with_ccont(ret))), + impl_return_conv: Some(quote!(self.build_with_ccont(ret.take_raw()))), inject_ret_tmp: false, unbounded_hrtb: true, }, @@ -1395,7 +1405,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { impl< 'cglue_a, - CGlueT: ::core::ops::Deref, + CGlueT: #trg_path::InstanceBounds, CGlueF, CGlueCtx: #ctx_bound, CGlueRetTmp, @@ -1422,7 +1432,7 @@ pub fn gen_trait(mut tr: ItemTrait, ext_name: Option<&Ident>) -> TokenStream { impl< 'cglue_a, - CGlueT: ::core::ops::Deref, + CGlueT: #trg_path::InstanceBounds, CGlueF, CGlueCtx: #ctx_bound, CGlueRetTmp, diff --git a/cglue-macro/Cargo.toml b/cglue-macro/Cargo.toml index c3f3a0b..923555c 100644 --- a/cglue-macro/Cargo.toml +++ b/cglue-macro/Cargo.toml @@ -10,6 +10,7 @@ repository = "https://github.com/h33p/cglue" keywords = [ "cglue", "abi", "ffi", "cbindgen", "macro" ] categories = [ "api-bindings", "accessibility", "parsing" ] readme = "../README.md" +rust-version = "1.56" [lib] proc-macro = true diff --git a/cglue/Cargo.toml b/cglue/Cargo.toml index e06a165..134c0a5 100644 --- a/cglue/Cargo.toml +++ b/cglue/Cargo.toml @@ -10,6 +10,7 @@ repository = "https://github.com/h33p/cglue" keywords = [ "cglue", "abi", "ffi", "cbindgen", "macro" ] categories = [ "api-bindings", "accessibility", "parsing" ] readme = "../README.md" +rust-version = "1.56" [dependencies] cglue-macro = { version = "0.3", path = "../cglue-macro" } diff --git a/cglue/build.rs b/cglue/build.rs index a534c2c..22f6899 100644 --- a/cglue/build.rs +++ b/cglue/build.rs @@ -10,7 +10,7 @@ fn main() { let version = version().unwrap(); for (v, c) in &cfgs { - println!("cargo::rustc-check-cfg=cfg({})", c); + println!("cargo:rustc-check-cfg=cfg({})", c); if version >= Version::parse(v).unwrap() { println!("cargo:rustc-cfg={}", c); } @@ -19,6 +19,6 @@ fn main() { let test_cfgs = ["__cglue_force_no_unwind_abi"]; for c in &test_cfgs { - println!("cargo::rustc-check-cfg=cfg({})", c); + println!("cargo:rustc-check-cfg=cfg({})", c); } } diff --git a/cglue/src/arc.rs b/cglue/src/arc.rs index 0dc37a3..53d5683 100644 --- a/cglue/src/arc.rs +++ b/cglue/src/arc.rs @@ -1,6 +1,7 @@ //! # FFI-safe Arc. use crate::trait_group::c_void; use crate::trait_group::Opaquable; +use core::ptr::NonNull; use std::sync::Arc; unsafe impl Send for CArc {} @@ -12,14 +13,32 @@ unsafe impl Sync for CArc {} #[repr(C)] #[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] pub struct CArc { - instance: Option<&'static T>, - clone_fn: Option) -> Option<&'static T>>, - drop_fn: Option)>, + // TODO: remove these remaps in 0.4 + #[cfg_attr( + all(feature = "abi_stable10", not(feature = "abi_stable11")), + sabi(unsafe_change_type = "Option<&'static T>") + )] + #[cfg_attr(feature = "abi_stable11", sabi(unsafe_change_type = Option<&'static T>))] + instance: *const T, + #[cfg_attr( + all(feature = "abi_stable10", not(feature = "abi_stable11")), + sabi( + unsafe_change_type = "Option) -> Option<&'static T>>" + ) + )] + #[cfg_attr(feature = "abi_stable11", sabi(unsafe_change_type = Option) -> Option<&'static T>>))] + clone_fn: Option *const T>, + #[cfg_attr( + all(feature = "abi_stable10", not(feature = "abi_stable11")), + sabi(unsafe_change_type = "Option)>") + )] + #[cfg_attr(feature = "abi_stable11", sabi(unsafe_change_type = Option)>))] + drop_fn: Option, } impl AsRef> for CArc { fn as_ref(&self) -> &Option<&'static T> { - &self.instance + unsafe { core::mem::transmute(&self.instance) } } } @@ -59,7 +78,7 @@ impl CArc { /// ``` pub fn take(&mut self) -> CArc { Self { - instance: self.instance.take(), + instance: core::mem::replace(&mut self.instance, core::ptr::null()), clone_fn: self.clone_fn.take(), drop_fn: self.drop_fn.take(), } @@ -88,13 +107,17 @@ impl CArc { impl From>> for CArc { fn from(opt: Option>) -> Self { match opt { - Some(mut arc) => Self { - instance: Some(arc.instance), - clone_fn: Some(arc.clone_fn), - drop_fn: arc.drop_fn.take(), - }, + Some(mut arc) => { + let ret = Self { + instance: arc.instance.as_ptr(), + clone_fn: Some(arc.clone_fn), + drop_fn: arc.drop_fn.take(), + }; + core::mem::forget(arc); + ret + } None => Self { - instance: None, + instance: core::ptr::null(), clone_fn: None, drop_fn: None, }, @@ -111,7 +134,7 @@ impl From for CArc { impl From> for CArc { fn from(arc: Arc) -> Self { Self { - instance: unsafe { Arc::into_raw(arc).as_ref() }, + instance: Arc::into_raw(arc), clone_fn: Some(c_clone), drop_fn: Some(c_drop), } @@ -129,7 +152,7 @@ impl From>> for CArc { impl From<&mut CArc> for Option<&mut CArcSome> { fn from(copt: &mut CArc) -> Self { - if copt.instance.is_none() { + if copt.instance.is_null() { None } else { unsafe { (copt as *mut CArc).cast::>().as_mut() } @@ -139,7 +162,7 @@ impl From<&mut CArc> for Option<&mut CArcSome> { impl From<&CArc> for Option<&CArcSome> { fn from(copt: &CArc) -> Self { - if copt.instance.is_none() { + if copt.instance.is_null() { None } else { unsafe { (copt as *const CArc).cast::>().as_ref() } @@ -148,20 +171,21 @@ impl From<&CArc> for Option<&CArcSome> { } impl From> for Option> { - fn from(mut copt: CArc) -> Self { - let instance = copt.instance.take()?; - match copt.take() { - CArc { + fn from(copt: CArc) -> Self { + let ret = match &copt { + &CArc { + instance, clone_fn: Some(clone_fn), drop_fn, - .. } => Some(CArcSome { - instance, + instance: NonNull::new(instance as _)?, clone_fn, drop_fn, }), _ => None, - } + }; + core::mem::forget(copt); + ret } } @@ -172,29 +196,27 @@ unsafe impl Opaquable for CArc { impl Default for CArc { fn default() -> Self { Self { - instance: None, + instance: core::ptr::null(), clone_fn: None, drop_fn: None, } } } -unsafe extern "C" fn c_clone( - ptr_to_arc: Option<&'static T>, -) -> Option<&'static T> { - if let Some(p) = ptr_to_arc { - let arc = Arc::from_raw(p); +unsafe extern "C" fn c_clone(ptr_to_arc: *const T) -> *const T { + if !ptr_to_arc.is_null() { + let arc = Arc::from_raw(ptr_to_arc); let cloned_arc = arc.clone(); let _ = Arc::into_raw(arc); - Arc::into_raw(cloned_arc).as_ref() + Arc::into_raw(cloned_arc) } else { - None + core::ptr::null() } } -unsafe extern "C" fn c_drop(ptr_to_arc: Option<&T>) { - if let Some(p) = ptr_to_arc { - let _ = Arc::from_raw(p); +unsafe extern "C" fn c_drop(ptr_to_arc: *const T) { + if !ptr_to_arc.is_null() { + let _ = Arc::from_raw(ptr_to_arc); } } @@ -210,9 +232,27 @@ const _: [(); std::mem::size_of::>()] = [(); std::mem::size_of::< #[repr(C)] #[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] pub struct CArcSome { - instance: &'static T, - clone_fn: unsafe extern "C" fn(Option<&'static T>) -> Option<&'static T>, - drop_fn: Option)>, + // TODO: remove these remaps in 0.4 + #[cfg_attr( + all(feature = "abi_stable10", not(feature = "abi_stable11")), + sabi(unsafe_change_type = "&'static T") + )] + #[cfg_attr(feature = "abi_stable11", sabi(unsafe_change_type = &'static T))] + instance: core::ptr::NonNull, + #[cfg_attr( + all(feature = "abi_stable10", not(feature = "abi_stable11")), + sabi( + unsafe_change_type = "unsafe extern \"C\" fn (Option<&'static T>) -> Option<&'static T>" + ) + )] + #[cfg_attr(feature = "abi_stable11", sabi(unsafe_change_type = unsafe extern "C" fn (Option<&'static T>) -> Option<&'static T>))] + clone_fn: unsafe extern "C" fn(*const T) -> *const T, + #[cfg_attr( + all(feature = "abi_stable10", not(feature = "abi_stable11")), + sabi(unsafe_change_type = "Option)>") + )] + #[cfg_attr(feature = "abi_stable11", sabi(unsafe_change_type = Option)>))] + drop_fn: Option, } unsafe impl Send for CArcSome {} @@ -243,7 +283,7 @@ impl CArcSome { /// This function is only safe when the underlying arc was created in the same binary/library. /// If a third-party arc is used, the behavior is undefined. pub unsafe fn into_arc(self) -> Arc { - let ptr = self.instance as *const _; + let ptr = self.instance.as_ptr(); std::mem::forget(self); Arc::from_raw(ptr) } @@ -258,7 +298,8 @@ impl From for CArcSome { impl From> for CArcSome { fn from(arc: Arc) -> Self { Self { - instance: unsafe { Arc::into_raw(arc).as_ref().unwrap() }, + // TODO: use new_unchecked? + instance: NonNull::new(Arc::into_raw(arc) as _).unwrap(), clone_fn: c_clone, drop_fn: Some(c_drop), } @@ -268,7 +309,9 @@ impl From> for CArcSome { impl Clone for CArcSome { fn clone(&self) -> Self { Self { - instance: unsafe { (self.clone_fn)(Some(self.instance)).unwrap() }, + instance: unsafe { + NonNull::new((self.clone_fn)(self.instance.as_ptr()) as _).unwrap() + }, ..*self } } @@ -277,14 +320,14 @@ impl Clone for CArcSome { impl Drop for CArcSome { fn drop(&mut self) { if let Some(drop_fn) = self.drop_fn { - unsafe { drop_fn(Some(self.instance)) } + unsafe { drop_fn(self.instance.as_ptr()) } } } } impl AsRef for CArcSome { fn as_ref(&self) -> &T { - self.instance + unsafe { self.instance.as_ref() } } } @@ -292,7 +335,7 @@ impl core::ops::Deref for CArcSome { type Target = T; fn deref(&self) -> &Self::Target { - self.instance + unsafe { self.instance.as_ref() } } } diff --git a/cglue/src/boxed.rs b/cglue/src/boxed.rs index d7c600a..e8ed8b0 100644 --- a/cglue/src/boxed.rs +++ b/cglue/src/boxed.rs @@ -3,6 +3,7 @@ use crate::slice::CSliceMut; use crate::trait_group::c_void; use crate::trait_group::*; use core::ops::{Deref, DerefMut}; +use core::ptr::NonNull; use std::boxed::Box; /// FFI-safe box @@ -13,15 +14,41 @@ use std::boxed::Box; #[repr(C)] #[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] pub struct CBox<'a, T: 'a> { - instance: &'a mut T, - drop_fn: Option, -} + // TODO: remove these remaps in 0.4 + #[cfg_attr( + all(feature = "abi_stable10", not(feature = "abi_stable11")), + sabi(unsafe_change_type = "&'a mut T") + )] + #[cfg_attr(feature = "abi_stable11", sabi(unsafe_change_type = &'a mut T))] + instance: NonNull, + #[cfg_attr( + all(feature = "abi_stable10", not(feature = "abi_stable11")), + sabi(unsafe_change_type = "Option") + )] + #[cfg_attr( + feature = "abi_stable11", + sabi(unsafe_change_type = Option) + )] + drop_fn: Option)>, + #[cfg_attr( + all(feature = "abi_stable10", not(feature = "abi_stable11")), + sabi(unsafe_change_type = "::abi_stable::marker_type::UnsafeIgnoredType<()>") + )] + #[cfg_attr( + feature = "abi_stable11", + sabi(unsafe_change_type = ::abi_stable::marker_type::UnsafeIgnoredType<()>) + )] + _phantom: core::marker::PhantomData<&'a mut T>, +} + +unsafe impl<'a, T: 'a> Send for CBox<'a, T> where &'a mut T: Send {} +unsafe impl<'a, T: 'a> Sync for CBox<'a, T> where &'a mut T: Sync {} impl super::trait_group::IntoInner for CBox<'_, T> { type InnerTarget = T; unsafe fn into_inner(self) -> Self::InnerTarget { - let b = Box::from_raw(self.instance); + let b = Box::from_raw(self.instance.as_ptr()); std::mem::forget(self); *b } @@ -31,22 +58,23 @@ impl Deref for CBox<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { - self.instance + unsafe { &*self.instance.as_ptr() } } } impl DerefMut for CBox<'_, T> { fn deref_mut(&mut self) -> &mut Self::Target { - self.instance + unsafe { &mut *self.instance.as_ptr() } } } impl From> for CBox<'_, T> { fn from(this: Box) -> Self { - let instance = Box::leak(this); + let instance = unsafe { NonNull::new_unchecked(Box::into_raw(this)) }; Self { instance, drop_fn: Some(cglue_drop_box::), + _phantom: core::marker::PhantomData, } } } @@ -79,8 +107,8 @@ unsafe impl<'a, T: Send> Opaquable for CBox<'a, T> { type OpaqueTarget = CBox<'a, c_void>; } -unsafe extern "C" fn cglue_drop_box(this: &mut T) { - let _ = Box::from_raw(this); +unsafe extern "C" fn cglue_drop_box(this: NonNull) { + let _ = Box::from_raw(this.as_ptr()); } /// FFI-safe (unsized) boxed slice diff --git a/cglue/src/lib.rs b/cglue/src/lib.rs index e5e416e..1cef5a3 100644 --- a/cglue/src/lib.rs +++ b/cglue/src/lib.rs @@ -1,7 +1,7 @@ //! //! # CGlue //! -//! [![Crates.io]][crates] [![API Docs]][docs] [![Build and test]][workflows] [![MIT licensed]][license] [![Rustc 1.45]][rust] +//! [![Crates.io]][crates] [![API Docs]][docs] [![Build and test]][workflows] [![MIT licensed]][license] [![Rustc 1.56]][rust] //! //! [Crates.io]: https://img.shields.io/crates/v/cglue.svg //! [crates]: https://crates.io/crates/cglue @@ -11,8 +11,8 @@ //! [workflows]: https://github.com/h33p/cglue/actions/workflows/build.yml //! [MIT licensed]: https://img.shields.io/badge/license-MIT-blue.svg //! [license]: https://github.com/h33p/cglue/blob/main/LICENSE -//! [Rustc 1.45]: https://img.shields.io/badge/rustc-1.45+-lightgray.svg -//! [rust]: https://blog.rust-lang.org/2020/07/16/Rust-1.45.0.html +//! [Rustc 1.56]: https://img.shields.io/badge/rustc-1.56+-lightgray.svg +//! [rust]: https://blog.rust-lang.org/2020/07/16/Rust-1.56.0.html //! //! If all code is glued together, our glue is the safest on the market. //! @@ -521,7 +521,7 @@ //! # #[cfg(not(feature = "unstable"))] //! impl< //! 'cglue_a, -//! CGlueInst: ::core::ops::Deref>, +//! CGlueInst: cglue::trait_group::InstanceBounds>, //! CGlueCtx: cglue::trait_group::ContextBounds, //! T: Eq, //! > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, T> for GA @@ -541,7 +541,7 @@ //! # #[cfg(not(feature = "unstable"))] //! impl< //! 'cglue_a, -//! CGlueInst: ::core::ops::Deref>, +//! CGlueInst: cglue::trait_group::InstanceBounds>, //! CGlueCtx: cglue::trait_group::ContextBounds, //! > GenGroupVtableFiller<'cglue_a, CGlueInst, CGlueCtx, u64> for GA //! { @@ -815,8 +815,9 @@ //! } //! # } //! -//! # #[cfg(gats_on_stable)] //! # fn main() { +//! # #[cfg(gats_on_stable)] +//! # { //! # use gats::*; //! # use cglue::*; //! let builder = InfoStore { info: Info { value: 50 } }; @@ -827,6 +828,7 @@ //! //! info_printer.print_info(); //! # } +//! # } //! ``` //! //! ### Plugin system diff --git a/cglue/src/trait_group.rs b/cglue/src/trait_group.rs index c69fa4a..9a58a6c 100644 --- a/cglue/src/trait_group.rs +++ b/cglue/src/trait_group.rs @@ -9,10 +9,10 @@ use abi_stable::{abi_stability::check_layout_compatibility, type_layout::TypeLay use core::mem::ManuallyDrop; use core::ops::{Deref, DerefMut}; use core::pin::Pin; -#[cfg(feature = "rust_void")] +#[cfg(any(feature = "rust_void", miri))] #[allow(non_camel_case_types)] pub type c_void = (); -#[cfg(not(feature = "rust_void"))] +#[cfg(not(any(feature = "rust_void", miri)))] #[allow(non_camel_case_types)] #[repr(transparent)] #[derive(Debug)] @@ -54,6 +54,49 @@ pub struct CGlueObjContainer { ret_tmp: R, } +// This gets cleaned up in post by cglue_bindgen +#[repr(transparent)] +#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))] +pub struct OpaqueHelper( + #[cfg_attr( + all(feature = "abi_stable10", not(feature = "abi_stable11")), + sabi(unsafe_change_type = "T") + )] + #[cfg_attr(feature = "abi_stable11", sabi(unsafe_change_type = T))] + T::OpaqueTarget, +); + +impl OpaqueHelper { + pub fn new(v: T) -> Self { + // Implementors should ensure the same size. + debug_assert_eq!( + core::mem::size_of::(), + core::mem::size_of::() + ); + + let input = ManuallyDrop::new(v); + + // We could use a union here, but that forbids us from using Rust 1.45. + // Rust does optimize this into a no-op anyways + let opaque = unsafe { core::ptr::read(&input as *const _ as *const _) }; + + Self(opaque) + } + + pub unsafe fn from_opaque(v: T::OpaqueTarget) -> Self { + Self(v) + } + + pub fn take_raw(self) -> T { + let this = ManuallyDrop::new(self); + unsafe { core::ptr::read(&this.0 as *const _ as *const _) } + } + + pub fn take_opaque(self) -> T::OpaqueTarget { + self.0 + } +} + /// Describes an opaquable object. /// /// This trait provides a safe many-traits-to-one conversion. For instance, concrete vtable types @@ -76,17 +119,7 @@ pub unsafe trait Opaquable: Sized { /// The opaque version safely destroys type information, and after this point there is no way /// back. fn into_opaque(self) -> Self::OpaqueTarget { - // Implementors should ensure the same size. - debug_assert_eq!( - core::mem::size_of::(), - core::mem::size_of::() - ); - - let input = ManuallyDrop::new(self); - - // We could use a union here, but that forbids us from using Rust 1.45. - // Rust does optimize this into a no-op anyways - unsafe { core::ptr::read(&input as *const _ as *const _) } + OpaqueHelper::new(self).take_opaque() } } @@ -157,9 +190,7 @@ impl GetVtblBase for CGlueTraitObj<'_, T, V, C, R> { // Conversions into container type itself. // Needed when generated code returns Self -impl, F, C: ContextBounds, R: Default> From<(T, C)> - for CGlueObjContainer -{ +impl From<(T, C)> for CGlueObjContainer { fn from((instance, context): (T, C)) -> Self { Self { instance, @@ -169,19 +200,21 @@ impl, F, C: ContextBounds, R: Default> From<(T, C)> } } -impl, F, R: Default> From for CGlueObjContainer { +impl From for CGlueObjContainer { fn from(this: T) -> Self { Self::from((this, Default::default())) } } -impl<'a, T, R: Default> From for CGlueObjContainer, NoContext, R> { +impl<'a, T: Send, R: Default> From for CGlueObjContainer, NoContext, R> { fn from(this: T) -> Self { Self::from(CBox::from(this)) } } -impl<'a, T, C: ContextBounds, R: Default> From<(T, C)> for CGlueObjContainer, C, R> { +impl<'a, T: Send, C: ContextBounds, R: Default> From<(T, C)> + for CGlueObjContainer, C, R> +{ fn from((this, context): (T, C)) -> Self { Self::from((CBox::from(this), context)) } @@ -189,8 +222,7 @@ impl<'a, T, C: ContextBounds, R: Default> From<(T, C)> for CGlueObjContainer, - F, + T: InstanceBounds, V: CGlueVtbl, Context = C, RetTmp = R>, C: ContextBounds, R: Default, @@ -207,8 +239,7 @@ where } impl< 'a, - T: Deref, - F, + T: InstanceBounds, V: CGlueVtbl, Context = C, RetTmp = R>, C: ContextBounds, R: Default, @@ -223,8 +254,7 @@ where impl< 'a, - T: Deref, - F, + T: InstanceBounds, V: CGlueVtbl, Context = C, RetTmp = R>, C: ContextBounds, R: Default, @@ -239,8 +269,7 @@ where impl< 'a, - T: Deref, - F, + T: InstanceBounds, V: CGlueVtbl, Context = NoContext, RetTmp = R>, R: Default, > From for CGlueTraitObj<'a, T, V, V::Context, V::RetTmp> @@ -254,7 +283,7 @@ where impl< 'a, - T, + T: Send, V: CGlueVtbl, NoContext, R>, Context = NoContext, RetTmp = R>, R: Default, > From for CGlueTraitObj<'a, CBox<'a, T>, V, V::Context, V::RetTmp> @@ -268,7 +297,7 @@ where impl< 'a, - T, + T: Send, V: CGlueVtbl, C, R>, Context = C, RetTmp = R>, C: ContextBounds, R: Default, @@ -317,14 +346,22 @@ pub trait GenericTypeBounds {} #[cfg(not(feature = "layout_checks"))] impl GenericTypeBounds for T {} +/// Describe type bounds for Instance (CGlueT) type. +pub trait InstanceBounds: Deref + Opaquable { + type InstanceObjType: Sized; +} +impl + Opaquable, F> InstanceBounds for T { + type InstanceObjType = ::Target; +} + /// CGlue compatible object. /// /// This trait allows to retrieve the constant `this` pointer on the structure. -pub trait CGlueObjBase { +pub trait CGlueObjBase: Opaquable { /// Type of the underlying object. type ObjType; /// Type of the container housing the object. - type InstType: ::core::ops::Deref; + type InstType: InstanceBounds; /// Type of the context associated with the container. type Context: ContextBounds; @@ -342,12 +379,12 @@ pub trait CGlueObjRef: CGlueObjBase { } } -impl, F, C: ContextBounds, R> CGlueObjBase for CGlueObjContainer { - type ObjType = F; +impl CGlueObjBase for CGlueObjContainer { + type ObjType = T::Target; type InstType = T; type Context = C; - fn cobj_base_ref(&self) -> (&F, &Self::Context) { + fn cobj_base_ref(&self) -> (&T::Target, &Self::Context) { (self.instance.deref(), &self.context) } @@ -356,8 +393,8 @@ impl, F, C: ContextBounds, R> CGlueObjBase for CGlueObjCont } } -impl, F, C: ContextBounds, R> CGlueObjRef for CGlueObjContainer { - fn cobj_ref(&self) -> (&F, &R, &Self::Context) { +impl CGlueObjRef for CGlueObjContainer { + fn cobj_ref(&self) -> (&T::Target, &R, &Self::Context) { (self.instance.deref(), &self.ret_tmp, &self.context) } } @@ -375,10 +412,10 @@ pub trait CGlueObjMut: CGlueObjRef { } } -impl + DerefMut, F, C: ContextBounds, R> CGlueObjMut +impl CGlueObjMut for CGlueObjContainer { - fn cobj_mut(&mut self) -> (&mut F, &mut R, &Self::Context) { + fn cobj_mut(&mut self) -> (&mut T::Target, &mut R, &Self::Context) { (self.instance.deref_mut(), &mut self.ret_tmp, &self.context) } } @@ -400,9 +437,7 @@ pub trait GetContainer { } } -impl, F, V, C: ContextBounds, R> GetContainer - for CGlueTraitObj<'_, T, V, C, R> -{ +impl GetContainer for CGlueTraitObj<'_, T, V, C, R> { type ContType = CGlueObjContainer; fn ccont_ref(&self) -> &Self::ContType { @@ -483,7 +518,7 @@ unsafe impl Opaquable for std::marker::PhantomData { type OpaqueTarget = std::marker::PhantomData; } -#[cfg(not(feature = "rust_void"))] +#[cfg(not(any(feature = "rust_void", miri)))] unsafe impl Opaquable for () { type OpaqueTarget = (); } diff --git a/examples/plugin-api/Cargo.toml b/examples/plugin-api/Cargo.toml index ee2a387..790dc21 100644 --- a/examples/plugin-api/Cargo.toml +++ b/examples/plugin-api/Cargo.toml @@ -9,5 +9,9 @@ crate-type = ["lib", "cdylib", "staticlib"] [dependencies] cglue = { path = "../../cglue/", features = ["layout_checks"] } -abi_stable = "0.10" libloading = "0.7" +abi_stable10 = { package = "abi_stable", version = "0.10", default-features = false } +_abi_stable11 = { package = "abi_stable", version = "0.11", optional = true, default-features = false } + +[features] +abi_stable11 = ["_abi_stable11", "cglue/abi_stable11"] diff --git a/examples/plugin-api/src/lib.rs b/examples/plugin-api/src/lib.rs index fc24cff..0a7c6d8 100644 --- a/examples/plugin-api/src/lib.rs +++ b/examples/plugin-api/src/lib.rs @@ -2,6 +2,12 @@ //! //! This crate is shared by plugins and users. +#[cfg(not(feature = "abi_stable11"))] +extern crate abi_stable10 as abi_stable; + +#[cfg(feature = "abi_stable11")] +extern crate _abi_stable11 as abi_stable; + pub use abi_stable::type_layout::TypeLayout; use abi_stable::StableAbi; use cglue::prelude::v1::{trait_group::compare_layouts, *};