// Copyright 2015 The Chromium Authors
// 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_INDEXEDDB_IDB_VALUE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_VALUE_H_

#include <memory>
#include <optional>
#include <utility>

#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "mojo/public/cpp/base/big_buffer.h"
#include "third_party/blink/public/mojom/file_system_access/file_system_access_transfer_token.mojom-blink-forward.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom-blink-forward.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_key_path.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/v8_external_memory_accounter.h"
#include "v8/include/v8.h"

namespace blink {

class BlobDataHandle;
class WebBlobInfo;

// Represents an IndexedDB Object Store value retrieved from the backing store,
// or a value to be written into the backing store.
//
// For most purposes, the backing store represents each IndexedDB value as wire
// data (a vector of bytes produced by SerializedScriptValue) and attached Blobs
// (a vector of Blobs).
//
// Object stores with auto-incrementing primary keys are a special case. To
// guarantee that we generate unique sequential numbers, the primary keys for
// these values are generated by the backing store. In this case, the primary
// key must be stored along the wire data. The backing store cannot invoke
// SerializedScriptValue, so it cannot inject the primary key into the wire
// bytes. Instead, when the values are read, Blink receives the primary keys
// along the IndexedDB values, and is responsible for injecting the keys into
// the values before returning them to the user.
class MODULES_EXPORT IDBValue final {
 public:
  IDBValue();
  ~IDBValue();

  // Disallow copy and assign.
  IDBValue(const IDBValue&) = delete;
  IDBValue& operator=(const IDBValue&) = delete;

  scoped_refptr<SerializedScriptValue> CreateSerializedValue() const;

  void SetBlobInfo(Vector<WebBlobInfo> blob_info);
  const Vector<WebBlobInfo>& BlobInfo() const { return blob_info_; }

  void SetData(Vector<uint8_t> data);
  void SetData(SerializedScriptValue::DataBufferPtr data);
  void SetData(mojo_base::BigBuffer data);
  base::span<const uint8_t> Data() const;

  const IDBKey* PrimaryKey() const { return primary_key_.get(); }
  const IDBKeyPath& KeyPath() const { return key_path_; }

  void SetFileSystemAccessTokens(
      Vector<mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>>
          tokens) {
    file_system_access_tokens_ = std::move(tokens);
  }
  Vector<mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>>&
  FileSystemAccessTokens() {
    return file_system_access_tokens_;
  }

  // Injects a primary key into a value coming from the backend.
  void SetInjectedPrimaryKey(std::unique_ptr<IDBKey> primary_key,
                             IDBKeyPath primary_key_path) {
    // If the given key is type None, ignore it.
    if (primary_key && primary_key->GetType() == mojom::IDBKeyType::None)
      primary_key.reset();
    primary_key_ = std::move(primary_key);
    key_path_ = std::move(primary_key_path);
  }

  // Sets the V8 isolate that this value's database lives in.
  //
  // Associating a V8 isolate informs V8's garbage collection about the memory
  // used by the IDBValue's wire data. This is crucial for V8 to be able to
  // schedule garbage collection in a timely manner when large IndexedDB values
  // are in use.
  void SetIsolate(v8::Isolate*);

  // Removes the last Blob from the IDBValue.
  //
  // When wire bytes are wrapped into a Blob, the Blob is appended at the end of
  // the IndexedDB value sent to the backing store. Conversely, removing the
  // last Blob from an IDBValue is used when unwrapping values.
  scoped_refptr<BlobDataHandle> TakeLastBlob();

  static std::unique_ptr<IDBValue> ConvertReturnValue(
      const mojom::blink::IDBReturnValuePtr& input);

 private:
  friend class IDBValueUnwrapper;

  // Data serialized by SerializedScriptValue is stored:
  // - in `data_from_mojo_` when reading from the backend via mojo
  // - in `data_` if the data came straight from SerializedScriptValue
  // - in `massaged_data_` when the SSV data has been compressed and/or wrapped
  //   and/or unwrapped by IDBValueWrapper (in which case, it replaces existing
  //   data)
  mojo_base::BigBuffer data_from_mojo_;
  SerializedScriptValue::DataBufferPtr data_;
  Vector<uint8_t> massaged_data_;

  Vector<WebBlobInfo> blob_info_;

  Vector<mojo::PendingRemote<mojom::blink::FileSystemAccessTransferToken>>
      file_system_access_tokens_;

  std::unique_ptr<IDBKey> primary_key_;
  IDBKeyPath key_path_;

  // Used to register memory externally allocated by the IDBValue, and to
  // unregister that memory in the destructor. Unused in other construction
  // paths.
  raw_ptr<v8::Isolate> isolate_ = nullptr;

  V8ExternalMemoryAccounter external_memory_accounter_;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_VALUE_H_
