diff --git a/loopy-destructure.el b/loopy-destructure.el index d46b40ee..1ec1b1e5 100644 --- a/loopy-destructure.el +++ b/loopy-destructure.el @@ -548,22 +548,28 @@ MAP-OR-KEY-VARS is whether there are map or key variables." (defun loopy--seq-length= (seq n) "Check whether the length of SEQ is equal to N." - (if (sequencep seq) - (compat-call length= seq n) - (= (seq-length seq) n))) + ;; TODO: Simplify when `stream.el' is updated and streams are no longer + ;; implemented as lists. See also `loopy--seq-length>'. + (cond + ((streamp seq) + ;; Avoid traversing long streams. + (let ((s (seq-drop seq (1- n)))) + (and (not (stream-empty-p s)) + (stream-empty-p (stream-rest s))))) + ((listp seq) + (compat-call length= seq n)) + (t + (= (seq-length seq) n)))) (defun loopy--seq-length> (seq n) "Check whether the length of SEQ is greater than to N." (cond - ((sequencep seq) - (compat-call length> seq n)) - ;; Take advantage of lazy evaluation of streams. - ((streamp seq) - (not (stream-empty-p (seq-drop seq n)))) - ((seqp seq) - (> (seq-length seq) n)) - (t - (error "Not a known sequence type")))) + ;; Test streams first, because version 2.3.0 of `stream.el' implements + ;; streams as lists. Take advantage of lazy evaluation of streams. + ((streamp seq) (not (stream-empty-p (seq-drop seq n)))) + ;; `length>' only seems to matter for lists, based on its definition. + ((listp seq) (compat-call length> seq n)) + (t (> (seq-length seq) n)))) (defun loopy--pcase-pat-positional-&seq-pattern (pos-vars opt-vars rest-var map-or-key-vars) "Build a pattern for the positional, `&optional', and `&rest' variables. diff --git a/tests/misc-tests.el b/tests/misc-tests.el index 097840de..21861f7b 100644 --- a/tests/misc-tests.el +++ b/tests/misc-tests.el @@ -36,6 +36,26 @@ INPUT is the destructuring usage. OUTPUT-PATTERN is what to match." ;;; Minor Functions +(ert-deftest loopy--seq-length= () + (should (equal t (loopy--seq-length= '(1 2 3) 3))) + (should (equal t (loopy--seq-length= [1 2 3 4] 4))) + (should (equal t (loopy--seq-length= (stream [1 2 3 4 5]) 5)))) + +(ert-deftest loopy--seq-length> () + (should (equal t (loopy--seq-length> '(1 2 3) 2))) + (should (equal t (loopy--seq-length> [1 2 3 4] 3))) + (should (equal t (loopy--seq-length> (stream [1 2 3 4 5]) 4)))) + +(ert-deftest list-too-short () + (should-error (loopy-let* (((a b c) '(a b))) + (list a b c)) + :type '(loopy-bad-run-time-destructuring (loopy (a b c)) (a b)))) + +(ert-deftest stream-too-short () + (should-error (loopy-let* (((&seq a b c) (stream '(a b)))) + (list a b c)) + :type '(loopy-bad-run-time-destructuring (loopy (a b c)) (a b)))) + (ert-deftest loopy--member-p () (should (loopy--member-p '((a . 1) (b . 2)) '(2 . c) diff --git a/tests/tests.el b/tests/tests.el index baa4976b..2e04c578 100644 --- a/tests/tests.el +++ b/tests/tests.el @@ -3018,12 +3018,23 @@ Using numbers directly will use less variables and more efficient code." (loopy-deftest substream-destr :result '((0 1 2) - (1 2 nil) - (2 nil nil)) + (1 2 3) + (2 3 4)) + :body ((cycle 3) + (substream (&seq i j k) (loopy-test-escape (stream [0 1 2 3 4 5 6]))) + (collect (list i j k))) + :loopy t + :iter-keyword (substream collect cycle) + :iter-bare ((substream . substreaming) + (collect . collecting) + (cycle . cycling))) + +(loopy-deftest substream-destr-too-short + :error loopy-bad-run-time-destructuring :body ((substream (&seq i j k) (loopy-test-escape (stream [0 1 2]))) (collect (list i j k))) :loopy t - :iter-keyword (substream collect) + :iter-keyword (substream collect ) :iter-bare ((substream . substreaming) (collect . collecting)))