Bug 1744809 - Reduce boilerplate in IOUtils frontend methods r=nika

Differential Revision: https://phabricator.services.mozilla.com/D133832
This commit is contained in:
Barret Rennie 2021-12-15 19:56:08 +00:00
Родитель cd5d088078
Коммит c7f7e975a9
2 изменённых файлов: 86 добавлений и 197 удалений

Просмотреть файл

@ -64,7 +64,7 @@
(_promise)->MaybeRejectWithOperationError( \
FormatErrorMessage(_rv, "Could not parse path (%s)", \
NS_ConvertUTF16toUTF8(_path).get())); \
return (_promise).forget(); \
return; \
} \
} while (0)
@ -256,6 +256,24 @@ static void RejectShuttingDown(Promise* aPromise) {
/* static */
IOUtils::StateMutex IOUtils::sState{"IOUtils::sState"};
/* static */
template <typename Fn>
already_AddRefed<Promise> IOUtils::WithPromiseAndState(GlobalObject& aGlobal,
Fn aFn) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
aFn(promise, state.ref());
} else {
RejectShuttingDown(promise);
}
return promise.forget();
}
/* static */
template <typename OkT, typename Fn>
void IOUtils::DispatchAndResolve(IOUtils::EventQueue* aQueue, Promise* aPromise,
@ -276,13 +294,7 @@ void IOUtils::DispatchAndResolve(IOUtils::EventQueue* aQueue, Promise* aPromise,
already_AddRefed<Promise> IOUtils::Read(GlobalObject& aGlobal,
const nsAString& aPath,
const ReadOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
@ -292,22 +304,19 @@ already_AddRefed<Promise> IOUtils::Read(GlobalObject& aGlobal,
// Resolve with an empty buffer.
nsTArray<uint8_t> arr(0);
promise->MaybeResolve(TypedArrayCreator<Uint8Array>(arr));
return promise.forget();
return;
}
toRead.emplace(aOptions.mMaxBytes.Value());
}
DispatchAndResolve<JsBuffer>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file), offset = aOptions.mOffset, toRead,
decompress = aOptions.mDecompress]() {
return ReadSync(file, offset, toRead, decompress,
BufferKind::Uint8Array);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
@ -352,49 +361,34 @@ RefPtr<SyncReadFile> IOUtils::OpenFileForSyncReading(GlobalObject& aGlobal,
already_AddRefed<Promise> IOUtils::ReadUTF8(GlobalObject& aGlobal,
const nsAString& aPath,
const ReadUTF8Options& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
DispatchAndResolve<JsBuffer>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file), decompress = aOptions.mDecompress]() {
return ReadUTF8Sync(file, decompress);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
already_AddRefed<Promise> IOUtils::ReadJSON(GlobalObject& aGlobal,
const nsAString& aPath,
const ReadUTF8Options& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
state.ref()
->mEventQueue
->Dispatch<JsBuffer>([file, decompress = aOptions.mDecompress]() {
return ReadUTF8Sync(file, decompress);
})
state->mEventQueue
->template Dispatch<JsBuffer>(
[file, decompress = aOptions.mDecompress]() {
return ReadUTF8Sync(file, decompress);
})
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise, file](JsBuffer&& aBuffer) {
[promise = RefPtr{promise}, file](JsBuffer&& aBuffer) {
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(promise->GetGlobalObject()))) {
promise->MaybeRejectWithUnknownError(
@ -431,11 +425,10 @@ already_AddRefed<Promise> IOUtils::ReadJSON(GlobalObject& aGlobal,
promise->MaybeResolve(val);
},
[promise](const IOError& aErr) { RejectJSPromise(promise, aErr); });
} else {
RejectShuttingDown(promise);
}
return promise.forget();
[promise = RefPtr{promise}](const IOError& aErr) {
RejectJSPromise(promise, aErr);
});
});
}
/* static */
@ -443,13 +436,7 @@ already_AddRefed<Promise> IOUtils::Write(GlobalObject& aGlobal,
const nsAString& aPath,
const Uint8Array& aData,
const WriteOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
@ -458,23 +445,20 @@ already_AddRefed<Promise> IOUtils::Write(GlobalObject& aGlobal,
if (buf.isNothing()) {
promise->MaybeRejectWithOperationError(
"Out of memory: Could not allocate buffer while writing to file");
return promise.forget();
return;
}
auto opts = InternalWriteOpts::FromBinding(aOptions);
if (opts.isErr()) {
RejectJSPromise(promise, opts.unwrapErr());
return promise.forget();
return;
}
DispatchAndResolve<uint32_t>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file), buf = std::move(*buf),
opts = opts.unwrap()]() { return WriteSync(file, buf, opts); });
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
@ -482,32 +466,23 @@ already_AddRefed<Promise> IOUtils::WriteUTF8(GlobalObject& aGlobal,
const nsAString& aPath,
const nsACString& aString,
const WriteOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
auto opts = InternalWriteOpts::FromBinding(aOptions);
if (opts.isErr()) {
RejectJSPromise(promise, opts.unwrapErr());
return promise.forget();
return;
}
DispatchAndResolve<uint32_t>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file), str = nsCString(aString),
opts = opts.unwrap()]() {
return WriteSync(file, AsBytes(Span(str)), opts);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
static bool AppendJsonAsUtf8(const char16_t* aData, uint32_t aLen, void* aStr) {
@ -520,26 +495,20 @@ already_AddRefed<Promise> IOUtils::WriteJSON(GlobalObject& aGlobal,
const nsAString& aPath,
JS::Handle<JS::Value> aValue,
const WriteOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
auto opts = InternalWriteOpts::FromBinding(aOptions);
if (opts.isErr()) {
RejectJSPromise(promise, opts.unwrapErr());
return promise.forget();
return;
}
if (opts.inspect().mMode == WriteMode::Append) {
promise->MaybeRejectWithNotSupportedError(
"IOUtils.writeJSON does not support appending to files."_ns);
return promise.forget();
return;
}
JSContext* cx = aGlobal.Context();
@ -557,19 +526,16 @@ already_AddRefed<Promise> IOUtils::WriteJSON(GlobalObject& aGlobal,
IOError(NS_ERROR_DOM_UNKNOWN_ERR)
.WithMessage("Could not serialize object to JSON"));
}
return promise.forget();
return;
}
DispatchAndResolve<uint32_t>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file), utf8Str = std::move(utf8Str),
opts = opts.unwrap()]() {
return WriteSync(file, AsBytes(Span(utf8Str)), opts);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
@ -577,13 +543,7 @@ already_AddRefed<Promise> IOUtils::Move(GlobalObject& aGlobal,
const nsAString& aSourcePath,
const nsAString& aDestPath,
const MoveOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> sourceFile = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(sourceFile, aSourcePath, promise);
@ -591,90 +551,60 @@ already_AddRefed<Promise> IOUtils::Move(GlobalObject& aGlobal,
REJECT_IF_INIT_PATH_FAILED(destFile, aDestPath, promise);
DispatchAndResolve<Ok>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[sourceFile = std::move(sourceFile), destFile = std::move(destFile),
noOverwrite = aOptions.mNoOverwrite]() {
return MoveSync(sourceFile, destFile, noOverwrite);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
already_AddRefed<Promise> IOUtils::Remove(GlobalObject& aGlobal,
const nsAString& aPath,
const RemoveOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
DispatchAndResolve<Ok>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file), ignoreAbsent = aOptions.mIgnoreAbsent,
recursive = aOptions.mRecursive]() {
return RemoveSync(file, ignoreAbsent, recursive);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
already_AddRefed<Promise> IOUtils::MakeDirectory(
GlobalObject& aGlobal, const nsAString& aPath,
const MakeDirectoryOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
DispatchAndResolve<Ok>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file), createAncestors = aOptions.mCreateAncestors,
ignoreExisting = aOptions.mIgnoreExisting,
permissions = aOptions.mPermissions]() {
return MakeDirectorySync(file, createAncestors, ignoreExisting,
permissions);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
already_AddRefed<Promise> IOUtils::Stat(GlobalObject& aGlobal,
const nsAString& aPath) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
DispatchAndResolve<InternalFileInfo>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file)]() { return StatSync(file); });
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
@ -682,13 +612,7 @@ already_AddRefed<Promise> IOUtils::Copy(GlobalObject& aGlobal,
const nsAString& aSourcePath,
const nsAString& aDestPath,
const CopyOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> sourceFile = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(sourceFile, aSourcePath, promise);
@ -696,29 +620,20 @@ already_AddRefed<Promise> IOUtils::Copy(GlobalObject& aGlobal,
REJECT_IF_INIT_PATH_FAILED(destFile, aDestPath, promise);
DispatchAndResolve<Ok>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[sourceFile = std::move(sourceFile), destFile = std::move(destFile),
noOverwrite = aOptions.mNoOverwrite,
recursive = aOptions.mRecursive]() {
return CopySync(sourceFile, destFile, noOverwrite, recursive);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
already_AddRefed<Promise> IOUtils::SetModificationTime(
GlobalObject& aGlobal, const nsAString& aPath,
const Optional<int64_t>& aModification) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
@ -726,39 +641,27 @@ already_AddRefed<Promise> IOUtils::SetModificationTime(
if (aModification.WasPassed()) {
newTime = Some(aModification.Value());
}
DispatchAndResolve<int64_t>(state.ref()->mEventQueue, promise,
DispatchAndResolve<int64_t>(state->mEventQueue, promise,
[file = std::move(file), newTime]() {
return SetModificationTimeSync(file, newTime);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
already_AddRefed<Promise> IOUtils::GetChildren(
GlobalObject& aGlobal, const nsAString& aPath,
const GetChildrenOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
DispatchAndResolve<nsTArray<nsString>>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file), ignoreAbsent = aOptions.mIgnoreAbsent]() {
return GetChildrenSync(file, ignoreAbsent);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
@ -766,53 +669,35 @@ already_AddRefed<Promise> IOUtils::SetPermissions(GlobalObject& aGlobal,
const nsAString& aPath,
uint32_t aPermissions,
const bool aHonorUmask) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
#if defined(XP_UNIX) && !defined(ANDROID)
if (aHonorUmask) {
aPermissions &= ~nsSystemInfo::gUserUmask;
}
if (aHonorUmask) {
aPermissions &= ~nsSystemInfo::gUserUmask;
}
#endif
if (auto state = GetState()) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
DispatchAndResolve<Ok>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file), permissions = aPermissions]() {
return SetPermissionsSync(file, permissions);
});
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */
already_AddRefed<Promise> IOUtils::Exists(GlobalObject& aGlobal,
const nsAString& aPath) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
if (!promise) {
return nullptr;
}
if (auto state = GetState()) {
return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) {
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
DispatchAndResolve<bool>(
state.ref()->mEventQueue, promise,
state->mEventQueue, promise,
[file = std::move(file)]() { return ExistsSync(file); });
} else {
RejectShuttingDown(promise);
}
return promise.forget();
});
}
/* static */

Просмотреть файл

@ -158,6 +158,10 @@ class IOUtils final {
class EventQueue;
class State;
template <typename Fn>
static already_AddRefed<Promise> WithPromiseAndState(GlobalObject& aGlobal,
Fn aFn);
/**
* Dispatch a task on the event queue and resolve or reject the associated
* promise based on the result.