branch: externals/futur
commit c4638cdde648a51427d37473c0d7f7bd3a485388
Author: Stefan Monnier <[email protected]>
Commit: Stefan Monnier <[email protected]>

    futur.el: A few minor bug-fixes
    
    * futur.el (futur-bind): Check for aborted future.
    (futur-let*): Actually accept a PAT for the (PAT -> EXP) bindings.
    (futur-blocker-abort): Fix methods so they don't burp when called
    on a blocker that's already completed.
---
 futur.el | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/futur.el b/futur.el
index 568d8b466c..2096c8d6c9 100644
--- a/futur.el
+++ b/futur.el
@@ -126,6 +126,7 @@
 ;; Since 1.0:
 
 ;; - Fix compatibility with Emacs<31.
+;; - Minor bug fixes.
 
 ;; Version 1.0:
 
@@ -267,6 +268,9 @@ A futur has 3 possible states:
     ((futur--waiting _ clients)
      (setf (futur--clients futur) (if err 'error t))
      (setf (futur--value futur) (or err val))
+     ;; FIXME: Should we just always abort the blocker instead of
+     ;; doing it only from `futur-abort'?
+     ;;(futur-blocker-abort blocker)
      ;; CLIENTS is usually in reverse order since we always `push' to them.
      (dolist (client (nreverse clients))
        ;; Don't run the clients directly from here, so we don't nest,
@@ -359,8 +363,12 @@ By default any error in FUTUR is propagated to the 
returned future."
        (setf (futur--clients futur)
              (cons
               (lambda (err val)
-                (if err (futur-deliver-failure new err)
-                  (futur--run-continuation new fun (list val))))
+                ;; If NEW is not waiting any more (e.g. it's been aborted),
+                ;; don't bother running the continuation.
+                (pcase new
+                  ((futur--waiting)
+                   (if err (futur-deliver-failure new err)
+                    (futur--run-continuation new fun (list val))))))
               clients))
        new))
     ((and (futur--error _) (guard (null error-fun))) futur)
@@ -445,11 +453,12 @@ ERROR-FUN is called with a single argument, the error 
object."
         (pcase-exhaustive bindings
           ('() (macroexp-progn body))
           (`((,var ,exp) . ,bindings)
-           ;; FIXME: Catch errors in EXP to run `error-fun'?
+           ;; FIXME: Catch errors in EXP, to run `error-fun'?
            `(pcase-let ((,var ,exp)) ,(loop bindings)))
           (`((,var <- ,exp) . ,bindings)
+           ;; FIXME: Catch errors in EXP, to run `error-fun'?
            `(futur-bind ,exp
-                        (lambda (,var) ,(loop bindings))
+                        (pcase-lambda (,var) ,(loop bindings))
                         ,error-fun)))))))
 
 (oclosure-define futur--aux
@@ -585,7 +594,9 @@ If IDLE is non-nil, then wait for that amount of idle time."
     t))
 
 (cl-defmethod futur-blocker-abort ((timer (head timer)) _error)
-  (cancel-timer (cdr timer)))
+  ;; Older versions of Emacs signal errors if we try to cancel a timer
+  ;; that's already run (or been canceled).
+  (unless (timer--triggered timer) (cancel-timer (cdr timer))))
 
 ;;;; Processes
 
@@ -690,7 +701,7 @@ The DISPLAY argument is ignored: redisplay always happens."
   ;; FIXME: This doesn't guarantee that the thread is aborted.
   ;; FIXME: Let's hope that the undocumented feature of `signal' applies
   ;; also to `thread-signal'.
-  (thread-signal th error nil))
+  (when (thread-live-p th) (thread-signal th error nil)))
 
 ;;;; Multi futures: Futures that are waiting for several other futures.
 

Reply via email to