blob: a500d38bcdf8340e7c747cbde949db8f980ea272 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_FILE_UTILS_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_FILE_UTILS_H_
#include <cstddef>
#include <memory>
#include "base/sequence_checker.h"
#include "base/types/pass_key.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h"
#include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
namespace blink {
class ScriptState;
// Extracts the read/write operation size from the buffer size.
int NativeIOOperationSize(const DOMArrayBufferView& buffer);
// Transfers the buffer from source to a new DOMArrayBufferView, preserving the
// its specific type. Returns nullptr when source is not detachable or when the
// transfer fails.
DOMArrayBufferView* TransferToNewArrayBufferView(
v8::Isolate* isolate,
NotShared<DOMArrayBufferView> source);
// Provides cross-thread access to the buffer backing a DOMArrayBufferView.
//
// This class is necessary because DOMArrayBufferView is garbage-collected,
// which entails that each DOMArrayBufferView instance can only be safely
// accessed on the thread where it was created. Note that CrossThreadPersistent
// can be used to keep a DOMArrayBufferView alive across threads, but the
// instance cannot be safely accessed on a different thread. See the comments on
// cppgc::subtle::CrossThreadPersistent for details.
//
// An instance takes over a DOMArrayBufferView's backing buffer at construction.
// The instance exposes the backing buffer via the Data() and DataLength()
// methods. At some point, the backing buffer is turned back into a
// DOMArrayBufferView via the Take() method. Once Take() is called, the instance
// is invalid, and Data() / DataLength() must not be called anymore.
//
// An instance should be owned by a single sequence at a time. Changing the
// owning sequence should be accomplished by PostTask-ing an owning pointer to
// the instance.
//
// Each instance must be destroyed on the same sequence where it was created.
// Take() must be called on the same sequence where the instance was created.
class NativeIODataBuffer {
public:
// Detaches the buffer backing `source`.
//
// Returns nullptr if detaching failed.
static std::unique_ptr<NativeIODataBuffer> Create(
ScriptState* script_state,
NotShared<DOMArrayBufferView> source);
// Exposed for std::make_unique. Instances should be obtained from Create().
NativeIODataBuffer(ArrayBufferContents contents,
DOMArrayBufferView::ViewType type,
size_t offset,
#if DCHECK_IS_ON()
size_t byte_length,
#endif // DCHECK_IS_ON()
size_t length,
base::PassKey<NativeIODataBuffer>);
NativeIODataBuffer(const NativeIODataBuffer&) = delete;
NativeIODataBuffer& operator=(const NativeIODataBuffer&) = delete;
~NativeIODataBuffer();
// Re-creates the DOMArrayBufferView.
//
// Must only be called while this instance is onwed by the same sequence where
// Create() was called. Must only be called if IsValid() is true.
// After the call, IsValid() will return false.
NotShared<DOMArrayBufferView> Take();
// Exposed for DCHECKs.
//
// Can be called while this instance is owned by any sequence.
bool IsValid() const;
// Returns a raw pointer to the DOMArrayBufferView's view.
//
// The return type was chosen so that the raw pointer can be conveniently
// passed to base::File methods.
//
// Can be called while this instance is owned by any sequence. Must only be
// called if IsValid() is true.
char* Data() {
DCHECK(IsValid());
// An invalid ArrayBufferContents (backing an empty array) returns nullptr
// when Data() is called. However, in that case, the offset must be zero.
DCHECK(contents_.Data() || contents_.DataLength() == 0);
DCHECK(contents_.Data() || offset_ == 0);
// According to the DCHECKs above, this branch isn't strictly needed. The
// return statement below the branch will never do pointer arithmetic on
// nullptr, because `offset_` is guaranteed to be zero when
// the ArrayBufferContents is not valid but this instance is.
char* data = static_cast<char*>(contents_.Data());
if (!data) {
DCHECK_EQ(offset_, 0u);
return data;
}
return data + offset_;
}
#if DCHECK_IS_ON()
// Returns the size of the DOMArrayBufferView's view, in bytes.
//
// Exposed for DCHECKs around base::File calls.
//
// Can be called while this instance is owned by any sequence. Must only be
// called if IsValid() is true.
size_t DataLength() const {
DCHECK(IsValid());
return byte_length_;
}
#endif // DCHECK_IS_ON()
private:
SEQUENCE_CHECKER(sequence_checker_);
// May not be valid, as reported by ArrayBufferContents::IsValid().
//
// If valid, guaranteed not to be shared, as reported by
// ArrayBufferContents::IsShared().
ArrayBufferContents contents_;
DOMArrayBufferView::ViewType type_;
const size_t offset_;
#if DCHECK_IS_ON()
const size_t byte_length_;
#endif // DCHECK_IS_ON()
const size_t length_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_IO_NATIVE_IO_FILE_UTILS_H_