// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2022 Ivan Baidakou

#pragma once

#include "definitions.hpp"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <limits>
#include <tuple>
#include <type_traits>

namespace rotor_light {

struct ActorBase;
struct SupervisorBase;

/** \struct Message
 *  \brief base class for all rotor-light messages */
struct Message {
  Message() : to{0} {}

  /** records destination */
  Message(ActorId to_) : to{to_} {}

  Message(const Message &) = delete;
  Message(Message &&) = delete;

  /** message type, to be filled by queue upon message construction */
  MessageTypeId type;

private:
  friend struct ActorBase;
  friend struct SupervisorBase;
  ActorId to;
};

namespace traits {

template <size_t... Items>
auto constexpr max =
    [] { return std::max(std::initializer_list<size_t>{Items...}); };

/** \struct MessageStorage
 *  \brief properly allocated & sized space for any user-defined
 *  message type
 */
template <typename... Ts> struct MessageStorage {
  /** calculates maximum size of all messages */
  static constexpr size_t item_size = max<sizeof(Ts)...>();

  /** calculates maximum alignment of all messages */
  static constexpr size_t item_alignment = max<alignof(Ts)...>();

  /** aliases aligned_storage to store max size and max alignment */
  using Item = std::aligned_storage_t<item_size, item_alignment>;
};

} // namespace traits

} // namespace rotor_light
