// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! This module contains types used to describe the REX network.

use std::{fmt, mem::size_of};

use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Serialize};

/// The representation of an epoch ID.
#[derive(
    BorshSerialize,
    BorshDeserialize,
    Clone,
    Copy,
    Debug,
    Default,
    Deserialize,
    Eq,
    Ord,
    PartialEq,
    PartialOrd,
    Serialize,
)]
pub struct EpochId(pub u64);

impl EpochId {
    /// The maximum size used when serializing an [`EpochId`] using [`borsh`].
    pub const BORSH_SERIALIZED_SIZE: usize = size_of::<u64>();
}

impl fmt::Display for EpochId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// Index of a committee in the REX configuration.
#[derive(
    BorshSerialize,
    BorshDeserialize,
    Clone,
    Copy,
    Debug,
    Default,
    Deserialize,
    Eq,
    Ord,
    PartialEq,
    PartialOrd,
    Serialize,
)]
pub struct CommitteeIndex(pub u32);

impl CommitteeIndex {
    /// The maximum size used when serializing a [`CommitteeIndex`] using [`borsh`].
    pub const BORSH_SERIALIZED_SIZE: usize = size_of::<u32>();
}

impl fmt::Display for CommitteeIndex {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// Index of a node within a REX committee.
#[derive(
    BorshSerialize,
    BorshDeserialize,
    Clone,
    Copy,
    Debug,
    Default,
    Deserialize,
    Eq,
    Ord,
    PartialEq,
    PartialOrd,
    Serialize,
)]
pub struct NodeIndex(pub u32);

impl NodeIndex {
    /// The maximum size used when serializing a [`NodeIndex`] using [`borsh`].
    pub const BORSH_SERIALIZED_SIZE: usize = size_of::<u32>();
}

impl fmt::Display for NodeIndex {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// The identifier to locate a REX node in a REX configuration.
#[derive(
    BorshSerialize,
    BorshDeserialize,
    Clone,
    Copy,
    Debug,
    Default,
    Deserialize,
    Eq,
    Ord,
    PartialEq,
    PartialOrd,
    Serialize,
)]
pub struct NodeId {
    pub epoch: EpochId,
    pub committee: CommitteeIndex,
    pub index: NodeIndex,
}

impl NodeId {
    /// The maximum size used when serializing an [`NodeId`] using [`borsh`].
    pub const BORSH_SERIALIZED_SIZE: usize = EpochId::BORSH_SERIALIZED_SIZE
        + CommitteeIndex::BORSH_SERIALIZED_SIZE
        + NodeIndex::BORSH_SERIALIZED_SIZE;
}
