// Copyright 2020 The Fuchsia 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 SRC_LIB_VMO_STORE_VMO_STORE_H_
#define SRC_LIB_VMO_STORE_VMO_STORE_H_

#include <lib/fit/result.h>
#include <zircon/status.h>

#include <memory>

#include <fbl/alloc_checker.h>

#include "storage_types.h"

namespace vmo_store {

// `VmoStore` pinning options.
struct PinOptions {
  // The BTI used for pinning.
  // Note that `VmoStore` does *not* take ownership of the BTI handle. It is the caller's
  // responsibility to ensure the BTI handle is valid.
  zx::unowned_bti bti;
  // Options passed to zx_bti_pin. See `StoredVmo::Map` for more details.
  uint32_t bti_pin_options;
  // Index pinned pages for fast lookup. See `StoredVmo::Map` for more details.
  bool index;
};

struct MapOptions {
  // Options passed to `zx_vmar_map`.
  zx_vm_option_t vm_option;
  // Pointer to `VmarManager`. If null, the root `vmar` will be used.
  fbl::RefPtr<fzl::VmarManager> vmar;
};

// `VmoStore` options controlling mapping and pinning behavior.
struct Options {
  // If provided, `VmoStore` will attempt to map stored VMOs.
  fit::optional<MapOptions> map;
  // If provided, `VmoStore` will attempt to pin stored VMOs.
  fit::optional<PinOptions> pin;
};

// A base class used to compose `VmoStore`s.
//
// Users should not use `VmoStoreBase` directly, use `VmoStore` or `OwnedVmoStore` instead.
//
// `Impl` is a base implementation that is either `AbstractStorage` or
// `VmoStoreBase<AbstractStorage>`.
template <typename Impl>
class VmoStoreBase {
 public:
  static_assert(internal::has_key_v<Impl>, "Backing must define a Key type");
  static_assert(internal::has_meta_v<Impl>, "Backing must define a Meta type");
  // The key type used to reference VMOs.
  using Key = typename Impl::Key;
  // User metadata associated with every registered VMO.
  using Meta = typename Impl::Meta;
  using StoredVmo = ::vmo_store::StoredVmo<Meta>;

  // Reserves `capacity` slots on the underlying store.
  // Stores that grow automatically may chose to pre-allocate memory on `Reserve`.
  // Stores that do not grow automatically will only increase their memory consumption upon
  // `Reserve` being called.
  zx_status_t Reserve(size_t capacity) { return impl_.Reserve(capacity); }

  // Returns the number of registered VMOs.
  size_t count() const { return impl_.count(); }
  // Returns `true` if the backing store is full.
  // Stores that grow automatically will never report that they're full.
  bool is_full() const { return impl_.is_full(); }

 protected:
  template <typename... StoreArgs>
  VmoStoreBase(StoreArgs... store_args) : impl_(std::forward<StoreArgs>(store_args)...) {}
  Impl impl_;
};

// A data structure that keeps track of registered VMOs using a `Backing` storage type.
// `VmoStore` keeps track of registered VMOs and performs common mapping and pinning operations,
// providing common operations used in VMO pre-registration on Banjo and FIDL APIs.
// This structure is not thread-safe. Users must provide their own thread-safety accounting for the
// chosen `Backing` format.
// `Backing` is the data structure used to store the registered VMOs. It must implement
// `AbstractStorage`.
//
// Example usage:
// ```
//   using namespace vmo_store;
//   // Declaring our types first.
//   // `MyKey` is the key type that is used to register and retrieve VMOs from a VmoStore.
//   using MyKey = size_t;
//   // `MyMeta` is extra user metadata associated with every stored VMO (can be `void`).
//   using MyMeta = std::string;
//   // Declare our store alias, we're using `HashTableStorage` in this example.
//   // See `storage_types.h` for other Backing storage types.
//   using MyVmoStore = VmoStore<HashTableStorage<MyKey, MyMeta>>;
//   MyVmoStore store(Options{...});
//
//   // Now let's register, retrieve, and unregister a `zx::vmo` obtained through `GetVmo()`.
//   // The second argument to `Register` is our user metadata.
//   fit::result<size_t, zx_status_t> result = store.Register(GetVmo(), "my first VMO");
//   size_t key = result.take_value();
//   auto * my_registered_vmo = store.GetVmo(key);
//
//   // Print metadata associated with VMO.
//   std::cout << "Got Vmo called " << my_registered_vmo->meta() << std::endl;
//   // see `stored_vmo.h` for other `StoredVmo` methods, like retrieving mapped or pinned memory.
//
//   // Finally, unregister the VMO, which will discard the VMO handle along with any mapping or
//   // pinning.
//   store.Unregister(key);
// ```
//
// See `OwnedVmoStore` for an alternative API where registration happens through an ownership agent.
template <typename Backing>
class VmoStore : public VmoStoreBase<Backing> {
 public:
  using typename VmoStoreBase<Backing>::Key;
  using typename VmoStoreBase<Backing>::Meta;
  using typename VmoStoreBase<Backing>::StoredVmo;

  static_assert(
      internal::is_abstract_storage<Backing>,
      "Backing must implement AbstractStorage, see storage_types.h for build in storage classes");

  template <typename... StoreArgs>
  explicit VmoStore(Options options, StoreArgs... store_args)
      : VmoStoreBase<Backing>(std::forward<StoreArgs>(store_args)...),
        options_(std::move(options)){

        };

  // Registers a VMO with this store, returning the key used to access that VMO on success.
  template <typename... MetaArgs>
  fit::result<Key, zx_status_t> Register(zx::vmo vmo, MetaArgs... vmo_args) {
    return Register(StoredVmo(std::move(vmo), std::forward<MetaArgs>(vmo_args)...));
  }

  fit::result<Key, zx_status_t> Register(StoredVmo vmo) {
    zx_status_t status = PrepareStore(&vmo);
    if (status != ZX_OK) {
      return fit::error(status);
    }
    auto key = this->impl_.Push(std::move(vmo));
    if (!key.has_value()) {
      return fit::error(ZX_ERR_NO_RESOURCES);
    }
    return fit::ok(std::move(*key));
  }

  // Registers a VMO with this store using the provided `key`.
  template <typename... MetaArgs>
  zx_status_t RegisterWithKey(Key key, zx::vmo vmo, MetaArgs... vmo_args) {
    return RegisterWithKey(std::move(key),
                           StoredVmo(std::move(vmo), std::forward<MetaArgs>(vmo_args)...));
  }

  zx_status_t RegisterWithKey(Key key, StoredVmo vmo) {
    zx_status_t status = PrepareStore(&vmo);
    if (status != ZX_OK) {
      return status;
    }
    return this->impl_.Insert(std::move(key), std::move(vmo));
  }

  // Unregisters the VMO at `key`.
  // The VMO handle will be dropped, alongside all the mapping and pinning handles.
  // Returns `ZX_ERR_NOT_FOUND` if `key` does not point to a registered VMO.
  zx_status_t Unregister(Key key) {
    if (!this->impl_.Erase(key)) {
      return ZX_ERR_NOT_FOUND;
    }
    return ZX_OK;
  }

  // Gets an _unowned_ pointer to the `StoredVmo` referenced by `key`.
  // Returns `nullptr` if `key` does not point to a register VMO.
  StoredVmo* GetVmo(const Key& key) { return this->impl_.Get(key); }

  DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(VmoStore);

 private:
  zx_status_t PrepareStore(StoredVmo* vmo) {
    if (!vmo->vmo()->is_valid()) {
      return ZX_ERR_BAD_HANDLE;
    }
    zx_status_t status;
    if (options_.map) {
      const auto& map_options = *options_.map;
      status = vmo->Map(map_options.vm_option, map_options.vmar);
      if (status != ZX_OK) {
        return status;
      }
    }
    if (options_.pin) {
      const auto& pin_options = *options_.pin;
      status = vmo->Pin(*pin_options.bti, pin_options.bti_pin_options, pin_options.index);
      if (status != ZX_OK) {
        return status;
      }
    }
    return ZX_OK;
  }

  Options options_;
};

}  // namespace vmo_store

#endif  // SRC_LIB_VMO_STORE_VMO_STORE_H_
