summaryrefslogtreecommitdiffstats
path: root/widget/windows/filedialog/WinFileDialogParent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/windows/filedialog/WinFileDialogParent.cpp')
-rw-r--r--widget/windows/filedialog/WinFileDialogParent.cpp80
1 files changed, 80 insertions, 0 deletions
diff --git a/widget/windows/filedialog/WinFileDialogParent.cpp b/widget/windows/filedialog/WinFileDialogParent.cpp
index 2c256a1506..329c72cc94 100644
--- a/widget/windows/filedialog/WinFileDialogParent.cpp
+++ b/widget/windows/filedialog/WinFileDialogParent.cpp
@@ -54,6 +54,86 @@ PWinFileDialogParent::nsresult WinFileDialogParent::BindToUtilityProcess(
return NS_OK;
}
+// Convert the raw IPC promise-type to a filedialog::Promise.
+template <typename T, typename Ex, size_t N>
+static auto ConvertToFDPromise(
+ const char (&aMethod)[N], // __func__
+ Ex&& extractor,
+ RefPtr<MozPromise<T, mozilla::ipc::ResponseRejectReason, true>>
+ aSrcPromise) {
+ // The extractor must produce a `mozilla::Result<..., Error>` from `T`.
+ using SrcResultInfo = detail::DestructureResult<std::invoke_result_t<Ex, T>>;
+ using ResolveT = typename SrcResultInfo::OkT;
+ static_assert(std::is_same_v<typename SrcResultInfo::ErrorT, Error>,
+ "expected T to be a Result<..., Error>");
+
+ using SrcPromiseT = MozPromise<T, mozilla::ipc::ResponseRejectReason, true>;
+ using DstPromiseT = MozPromise<ResolveT, Error, true>;
+
+ RefPtr<DstPromiseT> ret = aSrcPromise->Then(
+ mozilla::GetCurrentSerialEventTarget(), aMethod,
+
+ [extractor, aMethod](T&& val) {
+ mozilla::Result<ResolveT, Error> result = extractor(std::move(val));
+ if (result.isOk()) {
+ return DstPromiseT::CreateAndResolve(result.unwrap(), aMethod);
+ }
+ return DstPromiseT::CreateAndReject(result.unwrapErr(), aMethod);
+ },
+ [aMethod](typename mozilla::ipc::ResponseRejectReason&& val) {
+ return DstPromiseT::CreateAndReject(
+ MOZ_FD_ERROR(IPCError, "IPC", (uint32_t)val), aMethod);
+ });
+
+ return ret;
+}
+
+template <typename Input, typename Output>
+struct Extractor {
+ template <typename Input::Type tag_, Output const& (Input::*getter_)() const>
+ static auto get() {
+ return [](Input&& res) -> Result<Output, Error> {
+ if (res.type() == tag_) {
+ return (res.*getter_)();
+ }
+ if (res.type() == Input::TRemoteError) {
+ RemoteError err = res.get_RemoteError();
+ return Err(Error{.kind = Error::RemoteError,
+ .where = Error::Location::Deserialize(err.where()),
+ .why = err.why()});
+ }
+ MOZ_ASSERT_UNREACHABLE("internal IPC failure?");
+ return Err(MOZ_FD_ERROR(IPCError, "internal IPC failure?", E_FAIL));
+ };
+ }
+};
+
+[[nodiscard]] RefPtr<WinFileDialogParent::ShowFileDialogPromise>
+WinFileDialogParent::ShowFileDialogImpl(HWND parent, const FileDialogType& type,
+ mozilla::Span<Command const> commands) {
+ auto inner_promise = PWinFileDialogParent::SendShowFileDialog(
+ reinterpret_cast<WindowsHandle>(parent), type, std::move(commands));
+
+ return ConvertToFDPromise(
+ __func__,
+ Extractor<FileResult, Maybe<Results>>::get<
+ FileResult::TMaybeResults, &FileResult::get_MaybeResults>(),
+ std::move(inner_promise));
+}
+
+[[nodiscard]] RefPtr<WinFileDialogParent::ShowFolderDialogPromise>
+WinFileDialogParent::ShowFolderDialogImpl(
+ HWND parent, mozilla::Span<Command const> commands) {
+ auto inner_promise = PWinFileDialogParent::SendShowFolderDialog(
+ reinterpret_cast<WindowsHandle>(parent), std::move(commands));
+
+ return ConvertToFDPromise(
+ __func__,
+ Extractor<FolderResult, Maybe<nsString>>::get<
+ FolderResult::TMaybensString, &FolderResult::get_MaybensString>(),
+ std::move(inner_promise));
+}
+
void WinFileDialogParent::ProcessingError(Result aCode, const char* aReason) {
detail::LogProcessingError(sLogFileDialog, this, aCode, aReason);
}