node: Refactor toggles loading into its own file

Change-Id: I6fd05a7af9e81a263d2da974182fed7f64380e27
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/140301
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/dawn/node/binding/CMakeLists.txt b/src/dawn/node/binding/CMakeLists.txt
index 445017c..69b6e93 100644
--- a/src/dawn/node/binding/CMakeLists.txt
+++ b/src/dawn/node/binding/CMakeLists.txt
@@ -71,6 +71,8 @@
     "GPUTextureView.h"
     "Split.cpp"
     "Split.h"
+    "TogglesLoader.cpp"
+    "TogglesLoader.h"
 )
 common_compile_options(dawn_node_binding)
 
diff --git a/src/dawn/node/binding/GPUAdapter.cpp b/src/dawn/node/binding/GPUAdapter.cpp
index 97935ac..922755c 100644
--- a/src/dawn/node/binding/GPUAdapter.cpp
+++ b/src/dawn/node/binding/GPUAdapter.cpp
@@ -25,7 +25,7 @@
 #include "src/dawn/node/binding/GPUDevice.h"
 #include "src/dawn/node/binding/GPUSupportedFeatures.h"
 #include "src/dawn/node/binding/GPUSupportedLimits.h"
-#include "src/dawn/node/binding/Split.h"
+#include "src/dawn/node/binding/TogglesLoader.h"
 
 #define FOR_EACH_LIMIT(X)                        \
     X(maxTextureDimension1D)                     \
@@ -132,37 +132,14 @@
         return promise;
     }
 
-    // Propogate enabled/disabled dawn features
-    // Note: DawnTogglesDescriptor::enabledToggles and disabledToggles are vectors of 'const char*',
-    // so we make sure the parsed strings survive the CreateDevice() call by storing them on the
-    // stack.
-    std::vector<std::string> enabledTogglesString;
-    std::vector<std::string> disabledTogglesString;
-    std::vector<const char*> enabledToggles;
-    std::vector<const char*> disabledToggles;
-    if (auto values = flags_.Get("enable-dawn-features")) {
-        enabledTogglesString = Split(*values, ',');
-        for (auto& t : enabledTogglesString) {
-            enabledToggles.emplace_back(t.c_str());
-        }
-    }
-    if (auto values = flags_.Get("disable-dawn-features")) {
-        disabledTogglesString = Split(*values, ',');
-        for (auto& t : disabledTogglesString) {
-            disabledToggles.emplace_back(t.c_str());
-        }
-    }
-
     desc.requiredFeaturesCount = requiredFeatures.size();
     desc.requiredFeatures = requiredFeatures.data();
     desc.requiredLimits = &limits;
 
-    DawnTogglesDescriptor deviceTogglesDesc = {};
+    // Propagate enabled/disabled dawn features
+    TogglesLoader togglesLoader(flags_);
+    DawnTogglesDescriptor deviceTogglesDesc = togglesLoader.GetDescriptor();
     desc.nextInChain = &deviceTogglesDesc;
-    deviceTogglesDesc.enabledTogglesCount = enabledToggles.size();
-    deviceTogglesDesc.enabledToggles = enabledToggles.data();
-    deviceTogglesDesc.disabledTogglesCount = disabledToggles.size();
-    deviceTogglesDesc.disabledToggles = disabledToggles.data();
 
     auto wgpu_device = adapter_.CreateDevice(&desc);
     if (wgpu_device) {
diff --git a/src/dawn/node/binding/TogglesLoader.cpp b/src/dawn/node/binding/TogglesLoader.cpp
new file mode 100644
index 0000000..28a40fb
--- /dev/null
+++ b/src/dawn/node/binding/TogglesLoader.cpp
@@ -0,0 +1,43 @@
+// Copyright 2023 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/dawn/node/binding/TogglesLoader.h"
+#include "src/dawn/node/binding/Split.h"
+
+namespace wgpu::binding {
+
+TogglesLoader::TogglesLoader(const Flags& flags) {
+    if (auto values = flags.Get("enable-dawn-features")) {
+        enabledTogglesStrings_ = Split(*values, ',');
+        for (auto& t : enabledTogglesStrings_) {
+            enabledToggles_.emplace_back(t.c_str());
+        }
+    }
+    if (auto values = flags.Get("disable-dawn-features")) {
+        disabledTogglesStrings_ = Split(*values, ',');
+        for (auto& t : disabledTogglesStrings_) {
+            disabledToggles_.emplace_back(t.c_str());
+        }
+    }
+}
+
+DawnTogglesDescriptor TogglesLoader::GetDescriptor() {
+    DawnTogglesDescriptor result;
+    result.enabledTogglesCount = enabledToggles_.size();
+    result.enabledToggles = enabledToggles_.data();
+    result.disabledTogglesCount = disabledToggles_.size();
+    result.disabledToggles = disabledToggles_.data();
+    return result;
+}
+}  // namespace wgpu::binding
diff --git a/src/dawn/node/binding/TogglesLoader.h b/src/dawn/node/binding/TogglesLoader.h
new file mode 100644
index 0000000..fb2fe27
--- /dev/null
+++ b/src/dawn/node/binding/TogglesLoader.h
@@ -0,0 +1,53 @@
+// Copyright 2023 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_DAWN_NODE_BINDING_TOGGLESLOADER_H_
+#define SRC_DAWN_NODE_BINDING_TOGGLESLOADER_H_
+
+#include <string>
+#include <vector>
+
+#include "dawn/webgpu_cpp.h"
+#include "src/dawn/node/binding/Flags.h"
+
+namespace wgpu::binding {
+class TogglesLoader {
+  public:
+    // Constructor, reading toggles from the "enable-dawn-features"
+    // and "disable-dawn-features" flags.
+    explicit TogglesLoader(const Flags& flags);
+
+    // Returns a DawnTogglesDescriptor populated with toggles
+    // read at constructor time. It is only valid for the lifetime
+    // of this TogglesLoader object.
+    DawnTogglesDescriptor GetDescriptor();
+
+  private:
+    // Ban copy-assignment and copy-construction. The compiler will
+    // create implicitly-declared move-constructor and move-assignment
+    // implementations as needed.
+    TogglesLoader(const TogglesLoader& other) = delete;
+    TogglesLoader& operator=(const TogglesLoader&) = delete;
+
+    // DawnTogglesDescriptor::enabledToggles and disabledToggles are vectors
+    // of 'const char*', so keep local copies of the strings, and don't allow
+    // them to be relocated.
+    std::vector<std::string> enabledTogglesStrings_;
+    std::vector<std::string> disabledTogglesStrings_;
+    std::vector<const char*> enabledToggles_;
+    std::vector<const char*> disabledToggles_;
+};
+}  // namespace wgpu::binding
+
+#endif  // SRC_DAWN_NODE_BINDING_TOGGLESLOADER_H_