blob: 383e964be66cd75404d28e1168f0ab12405b42bf [file] [log] [blame]
// 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_