diff --git a/dom/chrome-webidl/IteratorResult.webidl b/dom/chrome-webidl/IteratorResult.webidl new file mode 100644 index 000000000000..1fdd26810e07 --- /dev/null +++ b/dom/chrome-webidl/IteratorResult.webidl @@ -0,0 +1,14 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +/** + * A dictionary which represents the result of a call to a next() method on a + * JS iterator object. + */ +dictionary IteratorResult { + required boolean done; + any value; +}; diff --git a/dom/chrome-webidl/moz.build b/dom/chrome-webidl/moz.build index cfd9e800e19a..f7830ca97787 100644 --- a/dom/chrome-webidl/moz.build +++ b/dom/chrome-webidl/moz.build @@ -34,6 +34,7 @@ WEBIDL_FILES = [ 'DominatorTree.webidl', 'HeapSnapshot.webidl', 'InspectorUtils.webidl', + 'IteratorResult.webidl', 'MatchGlob.webidl', 'MatchPattern.webidl', 'MessageManager.webidl', diff --git a/netwerk/test/httpserver/httpd.js b/netwerk/test/httpserver/httpd.js index 9e5a19073557..e5115d44cad3 100644 --- a/netwerk/test/httpserver/httpd.js +++ b/netwerk/test/httpserver/httpd.js @@ -5130,6 +5130,9 @@ nsSimpleEnumerator.prototype = return this._items[this._nextIndex++]; }, + [Symbol.iterator]() { + return this._items.values(); + }, QueryInterface: function(aIID) { if (Ci.nsISimpleEnumerator.equals(aIID) || diff --git a/testing/specialpowers/content/MockFilePicker.jsm b/testing/specialpowers/content/MockFilePicker.jsm index a44338848630..30ac42144bbc 100644 --- a/testing/specialpowers/content/MockFilePicker.jsm +++ b/testing/specialpowers/content/MockFilePicker.jsm @@ -214,12 +214,15 @@ MockFilePickerInstance.prototype = { return { index: 0, QueryInterface: ChromeUtils.generateQI([Ci.nsISimpleEnumerator]), + [Symbol.iterator]() { + return Array.from(MockFilePicker.returnData, d => d.nsIFile).values(); + }, hasMoreElements() { return this.index < MockFilePicker.returnData.length; }, getNext() { if (!MockFilePicker.returnData[this.index].nsIFile) { - return null; + throw Components.Exception("", Cr.NS_ERROR_FAILURE); } return MockFilePicker.returnData[this.index++].nsIFile; } diff --git a/xpcom/ds/nsISimpleEnumerator.idl b/xpcom/ds/nsISimpleEnumerator.idl index cbb0cd2000c6..ccad2a16722e 100644 --- a/xpcom/ds/nsISimpleEnumerator.idl +++ b/xpcom/ds/nsISimpleEnumerator.idl @@ -14,8 +14,38 @@ * @version 1.0 */ +/** + * A wrapper for an nsISimpleEnumerator instance which implements the + * JavaScript iteration protocol. + */ +[scriptable, uuid(4432e8ae-d4d3-42a6-a4d1-829f1c29512b)] +interface nsIJSEnumerator : nsISupports { + [symbol] + nsIJSEnumerator iterator(); + + [implicit_jscontext] + jsval next(); +}; + +[scriptable, uuid(796f340d-0a2a-490b-9c60-640765e99782)] +interface nsISimpleEnumeratorBase : nsISupports { + /** + * Returns a JavaScript iterator for all remaining entries in the enumerator. + * Each entry is queried only to nsISupports. + */ + [symbol] + nsIJSEnumerator iterator(); + + /** + * Returns JavaScript iterator for all remaining entries in the enumerator. + * Each entry is queried only to the supplied interface. If any element + * fails to query to that interface, the error is propagated to the caller. + */ + nsIJSEnumerator entries(in nsIIDRef aIface); +}; + [scriptable, uuid(D1899240-F9D2-11D2-BDD6-000064657374)] -interface nsISimpleEnumerator : nsISupports { +interface nsISimpleEnumerator : nsISimpleEnumeratorBase { /** * Called to determine whether or not the enumerator has * any elements that can be returned via getNext(). This method @@ -27,7 +57,7 @@ interface nsISimpleEnumerator : nsISupports { * @see getNext() * @return true if there are remaining elements in the enumerator. * false if there are no more elements in the enumerator. - */ + */ boolean hasMoreElements(); /** diff --git a/xpcom/ds/nsSimpleEnumerator.cpp b/xpcom/ds/nsSimpleEnumerator.cpp index 8c28c780a1bf..b540ab63e64c 100644 --- a/xpcom/ds/nsSimpleEnumerator.cpp +++ b/xpcom/ds/nsSimpleEnumerator.cpp @@ -6,4 +6,82 @@ #include "nsSimpleEnumerator.h" -NS_IMPL_ISUPPORTS(nsSimpleEnumerator, nsISimpleEnumerator) +#include "mozilla/dom/IteratorResultBinding.h" +#include "mozilla/dom/RootedDictionary.h" +#include "mozilla/dom/ToJSValue.h" +#include "mozilla/ResultExtensions.h" +#include "nsContentUtils.h" + +using namespace mozilla; +using namespace mozilla::dom; + +namespace { + +class JSEnumerator final : public nsIJSEnumerator +{ + NS_DECL_ISUPPORTS + NS_DECL_NSIJSENUMERATOR + + explicit JSEnumerator(nsISimpleEnumerator* aEnumerator, const nsID& aIID) + : mEnumerator(aEnumerator) + , mIID(aIID) + {} + +private: + ~JSEnumerator() = default; + + nsCOMPtr mEnumerator; + const nsID mIID; +}; + +} // anonymous namespace + +nsresult +JSEnumerator::Iterator(nsIJSEnumerator** aResult) +{ + RefPtr result(this); + result.forget(aResult); + return NS_OK; +} + +nsresult +JSEnumerator::Next(JSContext* aCx, JS::MutableHandleValue aResult) +{ + RootedDictionary result(aCx); + + nsCOMPtr elem; + if (NS_FAILED(mEnumerator->GetNext(getter_AddRefs(elem)))) { + result.mDone = true; + } else { + result.mDone = false; + + JS::RootedValue value(aCx); + MOZ_TRY(nsContentUtils::WrapNative(aCx, elem, &mIID, &value)); + result.mValue = value; + } + + if (!ToJSValue(aCx, result, aResult)) { + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +NS_IMPL_ISUPPORTS(JSEnumerator, nsIJSEnumerator) + +nsresult +nsSimpleEnumerator::Iterator(nsIJSEnumerator **aResult) +{ + auto result = MakeRefPtr(this, NS_GET_IID(nsISupports)); + result.forget(aResult); + return NS_OK; +} + +nsresult +nsSimpleEnumerator::Entries(const nsIID& aIface, nsIJSEnumerator **aResult) +{ + auto result = MakeRefPtr(this, aIface); + result.forget(aResult); + return NS_OK; +} + +NS_IMPL_ISUPPORTS(nsSimpleEnumerator, nsISimpleEnumerator, nsISimpleEnumeratorBase) diff --git a/xpcom/ds/nsSimpleEnumerator.h b/xpcom/ds/nsSimpleEnumerator.h index 9c474e32f316..afb195b4c7cf 100644 --- a/xpcom/ds/nsSimpleEnumerator.h +++ b/xpcom/ds/nsSimpleEnumerator.h @@ -12,6 +12,7 @@ class nsSimpleEnumerator : public nsISimpleEnumerator { NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATORBASE protected: virtual ~nsSimpleEnumerator() = default; diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp index b814cc3181fa..b59860286c96 100644 --- a/xpcom/io/nsLocalFileUnix.cpp +++ b/xpcom/io/nsLocalFileUnix.cpp @@ -108,6 +108,8 @@ public: NS_IMETHOD Init(nsLocalFile* aParent, bool aIgnored); + NS_FORWARD_NSISIMPLEENUMERATORBASE(nsSimpleEnumerator::) + private: ~nsDirEnumeratorUnix() override; diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index 1dab317d9abb..e2d334a37341 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -238,6 +238,7 @@ public: nsDriveEnumerator(); NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSISIMPLEENUMERATOR + NS_FORWARD_NSISIMPLEENUMERATORBASE(nsSimpleEnumerator::) nsresult Init(); NS_IMETHOD GetNextFile(nsIFile** aResult) override @@ -694,6 +695,8 @@ private: public: NS_DECL_ISUPPORTS_INHERITED + NS_FORWARD_NSISIMPLEENUMERATORBASE(nsSimpleEnumerator::) + nsDirEnumerator() : mDir(nullptr) { }