// Copyright 2022 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_DEVICES_SYSMEM_DRIVERS_SYSMEM_VERSIONS_H_
#define SRC_DEVICES_SYSMEM_DRIVERS_SYSMEM_VERSIONS_H_

#include <fidl/fuchsia.sysmem/cpp/fidl.h>
#include <fidl/fuchsia.sysmem2.internal/cpp/fidl.h>
#include <fidl/fuchsia.sysmem2/cpp/fidl.h>
#include <inttypes.h>

enum VersionIndex : size_t {
  kVersionIndexV1 = 0,
  kVersionIndexV2 = 1,
  kVersionIndexCombinedV1AndV2 = 2,
};

// Since CollectionServerEnd and GroupServerEnd never have a combined server end, we use an empty
// protocol server end as a stand-in to avoid complicating the templates below.
using EmptyCombinedServerEnd = fidl::ServerEnd<fuchsia_sysmem2_internal::EmptyCombinedServerEnd>;

using TokenServerEndV1 = fidl::ServerEnd<fuchsia_sysmem::BufferCollectionToken>;
using TokenServerEndV2 = fidl::ServerEnd<fuchsia_sysmem2::BufferCollectionToken>;
using TokenServerEndCombinedV1AndV2 =
    fidl::ServerEnd<fuchsia_sysmem2_internal::CombinedBufferCollectionToken>;
using TokenServerEnd =
    std::variant<TokenServerEndV1, TokenServerEndV2, TokenServerEndCombinedV1AndV2>;

using CollectionServerEndV1 = fidl::ServerEnd<fuchsia_sysmem::BufferCollection>;
using CollectionServerEndV2 = fidl::ServerEnd<fuchsia_sysmem2::BufferCollection>;
using CollectionServerEnd =
    std::variant<CollectionServerEndV1, CollectionServerEndV2, EmptyCombinedServerEnd>;

using GroupServerEndV1 = fidl::ServerEnd<fuchsia_sysmem::BufferCollectionTokenGroup>;
using GroupServerEndV2 = fidl::ServerEnd<fuchsia_sysmem2::BufferCollectionTokenGroup>;
using GroupServerEnd = std::variant<GroupServerEndV1, GroupServerEndV2, EmptyCombinedServerEnd>;

// Use a more specific type above in most places.  In a few places we use this more generic type to
// avoid templates that likely would generate more code.
using NodeServerEnd = std::variant<zx::channel, zx::channel, zx::channel>;

namespace sysmem_driver {

namespace internal {

template <typename T, typename Enable = void>
struct GetUnownedChannelImpl {
  // intentionally no get_unowned_channel() here
};
template <typename T>
struct GetUnownedChannelImpl<T, std::enable_if_t<std::is_same_v<TokenServerEnd, T> ||
                                                 std::is_same_v<CollectionServerEnd, T> ||
                                                 std::is_same_v<GroupServerEnd, T>>> {
  static zx::unowned_channel get_unowned_channel(const T& server_end) {
    switch (server_end.index()) {
      case kVersionIndexV1:
        return zx::unowned_channel(std::get<kVersionIndexV1>(server_end).channel());
      case kVersionIndexV2:
        return zx::unowned_channel(std::get<kVersionIndexV2>(server_end).channel());
      case kVersionIndexCombinedV1AndV2:
        return zx::unowned_channel(std::get<kVersionIndexCombinedV1AndV2>(server_end).channel());
    }
    ZX_PANIC("unreachable");
  }
};
template <typename T>
struct GetUnownedChannelImpl<
    T, std::enable_if_t<
           std::is_same_v<TokenServerEndV1, T> || std::is_same_v<TokenServerEndV2, T> ||
           std::is_same_v<TokenServerEndCombinedV1AndV2, T> ||
           std::is_same_v<CollectionServerEndV1, T> || std::is_same_v<CollectionServerEndV2, T> ||
           std::is_same_v<GroupServerEndV1, T> || std::is_same_v<GroupServerEndV2, T>>> {
  static zx::unowned_channel get_unowned_channel(const T& server_end) {
    return zx::unowned_channel(server_end.channel());
  }
};
template <typename T>
struct GetUnownedChannelImpl<T, std::enable_if_t<std::is_same_v<NodeServerEnd, T>>> {
  static zx::unowned_channel get_unowned_channel(const T& server_end) {
    switch (server_end.index()) {
      case kVersionIndexV1:
        return zx::unowned_channel(std::get<kVersionIndexV1>(server_end));
      case kVersionIndexV2:
        return zx::unowned_channel(std::get<kVersionIndexV2>(server_end));
      case kVersionIndexCombinedV1AndV2:
        return zx::unowned_channel(std::get<kVersionIndexCombinedV1AndV2>(server_end));
    }
    ZX_PANIC("unreachable");
  }
};

template <typename T, typename Enable = void>
struct TakeChannelImpl {
  // intentionally no get_unowned_channel() here
};
template <typename T>
struct TakeChannelImpl<T, std::enable_if_t<std::is_same_v<TokenServerEnd, T> ||
                                           std::is_same_v<CollectionServerEnd, T> ||
                                           std::is_same_v<GroupServerEnd, T>>> {
  static zx::channel take_channel(const T& server_end) {
    switch (server_end.index()) {
      case kVersionIndexV1:
        return std::move(std::get<kVersionIndexV1>(server_end).TakeChannel());
      case kVersionIndexV2:
        return std::move(std::get<kVersionIndexV2>(server_end).TakeChannel());
      case kVersionIndexCombinedV1AndV2:
        return std::move(std::get<kVersionIndexCombinedV1AndV2>(server_end).TakeChannel());
    }
    ZX_PANIC("unreachable");
  }
};
template <typename T>
struct TakeChannelImpl<
    T, std::enable_if_t<
           std::is_same_v<TokenServerEndV1, T> || std::is_same_v<TokenServerEndV2, T> ||
           std::is_same_v<TokenServerEndCombinedV1AndV2, T> ||
           std::is_same_v<CollectionServerEndV1, T> || std::is_same_v<CollectionServerEndV2, T> ||
           std::is_same_v<GroupServerEndV1, T> || std::is_same_v<GroupServerEndV2, T>>> {
  static zx::channel take_channel(T server_end) { return server_end.TakeChannel(); }
};
template <typename T>
struct TakeChannelImpl<T, std::enable_if_t<std::is_same_v<NodeServerEnd, T>>> {
  static zx::channel take_channel(T server_end) {
    switch (server_end.index()) {
      case kVersionIndexV1:
        return std::move(std::get<kVersionIndexV1>(server_end));
      case kVersionIndexV2:
        return std::move(std::get<kVersionIndexV2>(server_end));
      case kVersionIndexCombinedV1AndV2:
        return std::move(std::get<kVersionIndexCombinedV1AndV2>(server_end));
    }
    ZX_PANIC("unreachable");
  }
};

template <typename T, typename Enable = void>
struct TakeNodeServerEndImpl {
  // no take_nod_server_end() here
};
template <typename T>
struct TakeNodeServerEndImpl<T, typename std::enable_if_t<std::is_same_v<TokenServerEnd, T> ||
                                                          std::is_same_v<CollectionServerEnd, T> ||
                                                          std::is_same_v<GroupServerEnd, T>>> {
  static NodeServerEnd take_node_server_end(T server_end) {
    std::optional<NodeServerEnd> node_server_end;
    switch (server_end.index()) {
      case kVersionIndexV1:
        node_server_end.emplace(std::in_place_index<kVersionIndexV1>,
                                std::move(std::get<kVersionIndexV1>(server_end).TakeChannel()));
        break;
      case kVersionIndexV2:
        node_server_end.emplace(std::in_place_index<kVersionIndexV2>,
                                std::move(std::get<kVersionIndexV2>(server_end).TakeChannel()));
        break;
      case kVersionIndexCombinedV1AndV2:
        node_server_end.emplace(
            std::in_place_index<kVersionIndexCombinedV1AndV2>,
            std::move(std::get<kVersionIndexCombinedV1AndV2>(server_end).TakeChannel()));
        break;
    }
    return std::move(node_server_end.value());
  }
};

}  // namespace internal

template <typename T>
zx::unowned_channel GetUnownedChannel(const T& server_end) {
  return internal::GetUnownedChannelImpl<T>::get_unowned_channel(server_end);
}

template <typename T>
zx::channel TakeChannel(T server_end) {
  return internal::GetUnownedChannelImpl<T>::take_channel(std::move(server_end));
}

template <typename T>
NodeServerEnd TakeNodeServerEnd(T server_end) {
  return internal::TakeNodeServerEndImpl<T>::take_node_server_end(std::move(server_end));
}

}  // namespace sysmem_driver

#endif  // SRC_DEVICES_SYSMEM_DRIVERS_SYSMEM_VERSIONS_H_
