blob: d297c41214f388be69e1bbafbbcc50cf287279b2 [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.
// Definitions to provide a Writer interface for FXT. We want a userspace
// writer and a kernel writer that may have different implementations, but
// don't need to dynamically switch between them, so we enforce the required
// methods through type traits, rather than, say, an abstract class.
#ifndef SRC_PERFORMANCE_LIB_FXT_INCLUDE_LIB_FXT_WRITER_INTERNAL_H_
#define SRC_PERFORMANCE_LIB_FXT_INCLUDE_LIB_FXT_WRITER_INTERNAL_H_
#include <lib/zx/status.h>
#include <cstddef>
#include <cstdint>
#include <type_traits>
namespace fxt::internal {
enum class Method {
Reserve,
WriteWord,
WriteBytes,
Commit,
};
// Traits type to match valid method signatures. Base type evaluates to
// false-like.
template <Method M, typename Signature>
struct MethodTraits : std::false_type {};
// Specialization matching the required signature for Writer::Reserve. Provides
// an alias of the reservation return value type for convenience.
//
// Create a Reservation that will have `header` written to as it first 8 bytes.
template <typename Class, typename ReservationImpl>
struct MethodTraits<Method::Reserve, zx::status<ReservationImpl> (Class::*)(uint64_t header)>
: std::true_type {
using Reservation = ReservationImpl;
};
// Specialization matching the required signature for Reservation::WriteWord.
//
// Write a 64bit `word` into the buffer
template <typename Class>
struct MethodTraits<Method::WriteWord, void (Class::*)(uint64_t word)> : std::true_type {};
// Specialization matching the required signature for Reservation::WriteBytes.
//
// Write the `num_bytes` bytes starting at `bytes` into the buffer. If
// num_bytes is not a multiple of 8 bytes, follow with 0 padding to an 8 bytes
// boundary.
template <typename Class>
struct MethodTraits<Method::WriteBytes, void (Class::*)(const void* bytes, size_t num_bytes)>
: std::true_type {};
// Specialization matching the required signature for Reservation::Commit.
//
// Implementation defined. The serializer calls this method when it is done
// writing into the reservation.
template <typename Class>
struct MethodTraits<Method::Commit, void (Class::*)()> : std::true_type {};
// Alias to reference MethodTraits<...>::Reservation
template <typename W>
using ReservationType = typename MethodTraits<Method::Reserve, decltype(&W::Reserve)>::Reservation;
// Detects whether the type W conforms to the requirements of a Writer type.
//
// Inherits from std::true_type when all the required Writer methods are
// present with correct signatures
template <typename W>
using WriterIsValid =
std::conjunction<MethodTraits<Method::Reserve, decltype(&W::Reserve)>,
MethodTraits<Method::WriteWord, decltype(&ReservationType<W>::WriteWord)>,
MethodTraits<Method::WriteBytes, decltype(&ReservationType<W>::WriteBytes)>,
MethodTraits<Method::Commit, decltype(&ReservationType<W>::Commit)>>;
// Utility that evaluates to true-like if W conforms to the Writer protocol,
// false-like otherwise.
template <typename W, typename = void>
struct WriterTraits : std::false_type {};
// Specialization that is selected only when WriterIsValid<W> is well-formed.
// Evaluates to true-like when WriterIsValid<W> is true-like.
// Provides an alias of the Reservation type returned by zx::status<Reservation>
// W::Reserve(uint64_t).
template <typename W>
struct WriterTraits<W, std::void_t<WriterIsValid<W>>> : WriterIsValid<W> {
using Reservation = ReservationType<W>;
};
// Enable if W is a valid Writer.
//
// To be a value writer, a type must implement the following:
//
// Have some type "Reservation" which supports:
//
// Write a 64bit `word` into the buffer
// > void Reservation::WriteWord(uint64_t word);
//
// Write the `num_bytes` bytes starting at `bytes` into the buffer. If
// num_bytes is not a multiple of 8 bytes, the writer must follow with 0
// padding to an 8 byte boundary.
// > void Reservation::WriteBytes(const void* bytes, size_t num_bytes);
//
// Implementation defined. The serializer calls this method when it is done
// writing into the reservation.
// > void Reservation::Commit();
//
// As well as some "Writer" which supports handing out the type:
//
// Create a Reservation that will have `header` written to as it first 8 bytes.
// > Reservation Reserve(uint64_t header);
template <typename W>
using EnableIfWriter = std::enable_if_t<WriterTraits<W>::value, int>;
} // namespace fxt::internal
#endif // SRC_PERFORMANCE_LIB_FXT_INCLUDE_LIB_FXT_WRITER_INTERNAL_H_