Repository: PistonDevelopers/glfw-rs (language: rust)

Issue:
Things broken by unique fn types
[#19891](https://github.com/rust-lang/rust/pull/19891) gave every fn a unique type, which needs to be explicitly coerced into a function pointer. This breaks glfw-rs in a few places, particularly the callback infrastructure, which uses functions as callbacks a lot.



Discussion / hints:

Fix patch:
diff --git a/src/callbacks.rs b/src/callbacks.rs
index 7af643da..efffc04f 100644
--- a/src/callbacks.rs
+++ b/src/callbacks.rs
@@ -46,7 +46,7 @@ macro_rules! callback(
             CALLBACK_KEY.with(|cb| {
                 *cb.borrow_mut() = boxed_cb.take();
             });
-            ($ext_set)(Some(callback));
+            ($ext_set)(Some(callback as extern "C" fn($($ext_arg: $ext_arg_ty),*)));
         }
 
         pub fn unset() {
@@ -110,16 +110,24 @@ unsafe fn get_sender<'a>(window: &'a *mut ffi::GLFWwindow) -> &'a Sender<(f64, W
     mem::transmute(ffi::glfwGetWindowUserPointer(*window))
 }
 
+// Note that this macro creates a static function pointer rather than a plain function.
+// This makes it more ergonomic to embed in an Option; see set_window_callback! in lib.rs
 macro_rules! window_callback(
     (fn $name:ident () => $event:ident) => (
-        pub extern "C" fn $name(window: *mut ffi::GLFWwindow) {
-            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, WindowEvent::$event)); }
-        }
+        pub static $name: (extern "C" fn(window: *mut ffi::GLFWwindow)) = {
+            extern "C" fn actual_callback(window: *mut ffi::GLFWwindow) {
+                unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, WindowEvent::$event));}
+            }
+            actual_callback
+        };
      );
     (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $event:ident($($arg_conv:expr),*)) => (
-        pub extern "C" fn $name(window: *mut ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
-            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, WindowEvent::$event($($arg_conv),*))); }
-        }
+        pub static $name: (extern "C" fn(window: *mut ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*)) = {
+            extern "C" fn actual_callback(window: *mut ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
+                unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, WindowEvent::$event($($arg_conv),*))); }
+            }
+            actual_callback
+        };
      );
 );
 
diff --git a/src/lib.rs b/src/lib.rs
index 91d25daf..83073977 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -301,7 +301,7 @@ pub fn fail_on_errors(_: Error, description: String, _: &()) {
 
 /// A callback that triggers a task failure when an error is encountered.
 pub static FAIL_ON_ERRORS: Option<ErrorCallback<()>> =
-    Some(Callback { f: fail_on_errors, data: () });
+    Some(Callback { f: fail_on_errors as fn(Error, String, &()), data: () });
 
 /// The function to be used with the `LOG_ERRORS` callback.
 pub fn log_errors(_: Error, description: String, _: &()) {
@@ -311,7 +311,7 @@ pub fn log_errors(_: Error, description: String, _: &()) {
 /// A callback that logs each error as it is encountered without triggering a
 /// task failure.
 pub static LOG_ERRORS: Option<ErrorCallback<()>> =
-    Some(Callback { f: log_errors, data: () });
+    Some(Callback { f: log_errors as fn(Error, String, &()), data: () });
 
 /// Cursor modes.
 #[repr(i32)]


Test patch: