Repository: dtolnay/cxx (language: rust)

Issue:
UniquePtr<CxxVector<T>> doesn't work for opaque C++ type T containing non-static borrows
There is a spurious `'static` bound on the following UniquePtrTarget impl, which was inconsequential prior to #608, but now is quite limiting. We should find a way to avoid needing that bound.

https://github.com/dtolnay/cxx/blob/3090721172f12f5f88c1853f177c9441e2e1789e/src/unique_ptr.rs#L236-L238

Example:

```rust
use cxx::{CxxVector, UniquePtr};

#[cxx::bridge]
mod ffi {
    extern "C++" {
        include!("example/include/example.h");

        type Thing<'a>;
    }

    impl<'a> CxxVector<Thing<'a>> {}
}

fn f<'a>(_: UniquePtr<CxxVector<ffi::Thing<'a>>>) {}
```

```console
error[E0477]: the type `Thing<'a>` does not fulfill the required lifetime
  --> src/main.rs:14:13
   |
14 | fn f<'a>(_: UniquePtr<CxxVector<ffi::Thing<'a>>>) {}
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: type must satisfy the static lifetime
```


Discussion / hints:

Fix patch:
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 0a88a0499..49b8927bf 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -1276,7 +1276,9 @@ fn expand_unique_ptr(ident: &Ident, types: &Types, explicit_impl: Option<&Impl>)
 
     quote_spanned! {end_span=>
         #unsafe_token impl #impl_generics ::cxx::private::UniquePtrTarget for #ident #ty_generics {
-            const __NAME: &'static dyn ::std::fmt::Display = &#name;
+            fn __typename(f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+                f.write_str(#name)
+            }
             fn __null() -> *mut ::std::ffi::c_void {
                 extern "C" {
                     #[link_name = #link_null]
@@ -1361,7 +1363,9 @@ fn expand_shared_ptr(ident: &Ident, types: &Types, explicit_impl: Option<&Impl>)
 
     quote_spanned! {end_span=>
         #unsafe_token impl #impl_generics ::cxx::private::SharedPtrTarget for #ident #ty_generics {
-            const __NAME: &'static dyn ::std::fmt::Display = &#name;
+            fn __typename(f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+                f.write_str(#name)
+            }
             unsafe fn __null(new: *mut ::std::ffi::c_void) {
                 extern "C" {
                     #[link_name = #link_null]
@@ -1418,7 +1422,9 @@ fn expand_weak_ptr(ident: &Ident, types: &Types, explicit_impl: Option<&Impl>) -
 
     quote_spanned! {end_span=>
         #unsafe_token impl #impl_generics ::cxx::private::WeakPtrTarget for #ident #ty_generics {
-            const __NAME: &'static dyn ::std::fmt::Display = &#name;
+            fn __typename(f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+                f.write_str(#name)
+            }
             unsafe fn __null(new: *mut ::std::ffi::c_void) {
                 extern "C" {
                     #[link_name = #link_null]
@@ -1487,7 +1493,9 @@ fn expand_cxx_vector(elem: &Ident, explicit_impl: Option<&Impl>, types: &Types)
 
     quote_spanned! {end_span=>
         #unsafe_token impl #impl_generics ::cxx::private::VectorElement for #elem #ty_generics {
-            const __NAME: &'static dyn ::std::fmt::Display = &#name;
+            fn __typename(f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+                f.write_str(#name)
+            }
             fn __vector_size(v: &::cxx::CxxVector<Self>) -> usize {
                 extern "C" {
                     #[link_name = #link_size]
diff --git a/src/cxx_vector.rs b/src/cxx_vector.rs
index d78ee478a..c9c7d78cf 100644
--- a/src/cxx_vector.rs
+++ b/src/cxx_vector.rs
@@ -5,7 +5,7 @@ use crate::extern_type::ExternType;
 use crate::kind::Trivial;
 use crate::string::CxxString;
 use core::ffi::c_void;
-use core::fmt::{self, Debug, Display};
+use core::fmt::{self, Debug};
 use core::iter::FusedIterator;
 use core::marker::{PhantomData, PhantomPinned};
 use core::mem;
@@ -263,32 +263,11 @@ where
     }
 }
 
-pub(crate) struct TypeName<T> {
-    element: PhantomData<T>,
-}
-
-impl<T> TypeName<T> {
-    pub const fn new() -> Self {
-        TypeName {
-            element: PhantomData,
-        }
-    }
-}
-
-impl<T> Display for TypeName<T>
-where
-    T: VectorElement,
-{
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
-        write!(formatter, "CxxVector<{}>", T::__NAME)
-    }
-}
-
 // Methods are private; not intended to be implemented outside of cxxbridge
 // codebase.
 #[doc(hidden)]
 pub unsafe trait VectorElement: Sized {
-    const __NAME: &'static dyn Display;
+    fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
     fn __vector_size(v: &CxxVector<Self>) -> usize;
     unsafe fn __get_unchecked(v: *mut CxxVector<Self>, pos: usize) -> *mut Self;
     fn __unique_ptr_null() -> *mut c_void;
@@ -303,7 +282,9 @@ macro_rules! impl_vector_element {
         const_assert_eq!(1, mem::align_of::<CxxVector<$ty>>());
 
         unsafe impl VectorElement for $ty {
-            const __NAME: &'static dyn Display = &$name;
+            fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
+                f.write_str($name)
+            }
             fn __vector_size(v: &CxxVector<$ty>) -> usize {
                 extern "C" {
                     attr! {
diff --git a/src/fmt.rs b/src/fmt.rs
new file mode 100644
index 000000000..db14a7c00
--- /dev/null
+++ b/src/fmt.rs
@@ -0,0 +1,16 @@
+use std::fmt::{self, Display};
+
+pub(crate) fn display(fmt: impl Fn(&mut fmt::Formatter) -> fmt::Result) -> impl Display {
+    DisplayInvoke(fmt)
+}
+
+struct DisplayInvoke<T>(T);
+
+impl<T> Display for DisplayInvoke<T>
+where
+    T: Fn(&mut fmt::Formatter) -> fmt::Result,
+{
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        (self.0)(formatter)
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 8282ea3ce..fb00d9466 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -402,6 +402,7 @@ mod macros;
 
 mod exception;
 mod extern_type;
+mod fmt;
 mod function;
 mod opaque;
 mod result;
diff --git a/src/shared_ptr.rs b/src/shared_ptr.rs
index b3a1b1cca..58930352f 100644
--- a/src/shared_ptr.rs
+++ b/src/shared_ptr.rs
@@ -1,3 +1,4 @@
+use crate::fmt::display;
 use crate::kind::Trivial;
 use crate::string::CxxString;
 use crate::weak_ptr::{WeakPtr, WeakPtrTarget};
@@ -119,7 +120,10 @@ where
     fn deref(&self) -> &Self::Target {
         match self.as_ref() {
             Some(target) => target,
-            None => panic!("called deref on a null SharedPtr<{}>", T::__NAME),
+            None => panic!(
+                "called deref on a null SharedPtr<{}>",
+                display(T::__typename),
+            ),
         }
     }
 }
@@ -152,7 +156,7 @@ where
 // codebase.
 pub unsafe trait SharedPtrTarget {
     #[doc(hidden)]
-    const __NAME: &'static dyn Display;
+    fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
     #[doc(hidden)]
     unsafe fn __null(new: *mut c_void);
     #[doc(hidden)]
@@ -177,7 +181,9 @@ pub unsafe trait SharedPtrTarget {
 macro_rules! impl_shared_ptr_target {
     ($segment:expr, $name:expr, $ty:ty) => {
         unsafe impl SharedPtrTarget for $ty {
-            const __NAME: &'static dyn Display = &$name;
+            fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
+                f.write_str($name)
+            }
             unsafe fn __null(new: *mut c_void) {
                 extern "C" {
                     attr! {
diff --git a/src/unique_ptr.rs b/src/unique_ptr.rs
index 0f9fa8f26..2d16a45f9 100644
--- a/src/unique_ptr.rs
+++ b/src/unique_ptr.rs
@@ -1,6 +1,7 @@
+use crate::fmt::display;
 use crate::kind::Trivial;
 use crate::string::CxxString;
-use crate::vector::{self, CxxVector, VectorElement};
+use crate::vector::{CxxVector, VectorElement};
 use crate::ExternType;
 use core::ffi::c_void;
 use core::fmt::{self, Debug, Display};
@@ -77,7 +78,10 @@ where
     pub fn pin_mut(&mut self) -> Pin<&mut T> {
         match self.as_mut() {
             Some(target) => target,
-            None => panic!("called pin_mut on a null UniquePtr<{}>", T::__NAME),
+            None => panic!(
+                "called pin_mut on a null UniquePtr<{}>",
+                display(T::__typename),
+            ),
         }
     }
 
@@ -127,7 +131,10 @@ where
     fn deref(&self) -> &Self::Target {
         match self.as_ref() {
             Some(target) => target,
-            None => panic!("called deref on a null UniquePtr<{}>", T::__NAME),
+            None => panic!(
+                "called deref on a null UniquePtr<{}>",
+                display(T::__typename),
+            ),
         }
     }
 }
@@ -139,7 +146,10 @@ where
     fn deref_mut(&mut self) -> &mut Self::Target {
         match self.as_mut() {
             Some(target) => Pin::into_inner(target),
-            None => panic!("called deref_mut on a null UniquePtr<{}>", T::__NAME),
+            None => panic!(
+                "called deref_mut on a null UniquePtr<{}>",
+                display(T::__typename),
+            ),
         }
     }
 }
@@ -172,7 +182,7 @@ where
 // codebase.
 pub unsafe trait UniquePtrTarget {
     #[doc(hidden)]
-    const __NAME: &'static dyn Display;
+    fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
     #[doc(hidden)]
     fn __null() -> *mut c_void;
     #[doc(hidden)]
@@ -209,7 +219,9 @@ extern "C" {
 }
 
 unsafe impl UniquePtrTarget for CxxString {
-    const __NAME: &'static dyn Display = &"CxxString";
+    fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str("CxxString")
+    }
     fn __null() -> *mut c_void {
         let mut repr = ptr::null_mut::<c_void>();
         unsafe {
@@ -235,9 +247,11 @@ unsafe impl UniquePtrTarget for CxxString {
 
 unsafe impl<T> UniquePtrTarget for CxxVector<T>
 where
-    T: VectorElement + 'static,
+    T: VectorElement,
 {
-    const __NAME: &'static dyn Display = &vector::TypeName::<T>::new();
+    fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "CxxVector<{}>", display(T::__typename))
+    }
     fn __null() -> *mut c_void {
         T::__unique_ptr_null()
     }
diff --git a/src/weak_ptr.rs b/src/weak_ptr.rs
index 7fc4c78ac..ba7446184 100644
--- a/src/weak_ptr.rs
+++ b/src/weak_ptr.rs
@@ -1,7 +1,7 @@
 use crate::shared_ptr::{SharedPtr, SharedPtrTarget};
 use crate::string::CxxString;
 use core::ffi::c_void;
-use core::fmt::{self, Debug, Display};
+use core::fmt::{self, Debug};
 use core::marker::PhantomData;
 use core::mem::MaybeUninit;
 
@@ -95,7 +95,7 @@ where
 // codebase.
 pub unsafe trait WeakPtrTarget {
     #[doc(hidden)]
-    const __NAME: &'static dyn Display;
+    fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
     #[doc(hidden)]
     unsafe fn __null(new: *mut c_void);
     #[doc(hidden)]
@@ -111,7 +111,9 @@ pub unsafe trait WeakPtrTarget {
 macro_rules! impl_weak_ptr_target {
     ($segment:expr, $name:expr, $ty:ty) => {
         unsafe impl WeakPtrTarget for $ty {
-            const __NAME: &'static dyn Display = &$name;
+            fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
+                f.write_str($name)
+            }
             unsafe fn __null(new: *mut c_void) {
                 extern "C" {
                     attr! {


Test patch: