suon_protocol 0.1.0

Binary protocol encoding and decoding for the Suon MMORPG framework
Documentation
//! Client market-accept-offer packet.

use std::time::{Duration, SystemTime, UNIX_EPOCH};

use crate::packets::decoder::Decoder;

use super::prelude::*;

/// Packet sent by the client to accept an existing market offer.
///
/// # Examples
/// ```
/// use std::time::UNIX_EPOCH;
/// use suon_protocol::packets::client::{Decodable, prelude::AcceptMarketOfferPacket};
///
/// let mut payload: &[u8] = &[0x78, 0x56, 0x34, 0x12, 0x34, 0x12, 0x05, 0x00];
/// let packet = AcceptMarketOfferPacket::decode(&mut payload).unwrap();
///
/// assert_eq!(
///     packet.timestamp.duration_since(UNIX_EPOCH).unwrap().as_secs(),
///     0x12345678
/// );
/// assert_eq!(packet.offer_counter, 0x1234);
/// assert_eq!(packet.amount, 5);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AcceptMarketOfferPacket {
    /// Timestamp that identifies the offer.
    pub timestamp: SystemTime,

    /// Counter paired with the timestamp to identify the offer.
    pub offer_counter: u16,

    /// Amount accepted from the market offer.
    pub amount: u16,
}

impl Decodable for AcceptMarketOfferPacket {
    const KIND: PacketKind = PacketKind::AcceptMarketOffer;

    fn decode(mut bytes: &mut &[u8]) -> Result<Self, DecodableError> {
        Ok(Self {
            timestamp: UNIX_EPOCH + Duration::from_secs(u64::from(bytes.get_u32()?)),
            offer_counter: bytes.get_u16()?,
            amount: bytes.get_u16()?,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn should_decode_accept_market_offer() {
        let mut payload: &[u8] = &[0x78, 0x56, 0x34, 0x12, 0x34, 0x12, 0x05, 0x00];

        let packet = AcceptMarketOfferPacket::decode(&mut payload)
            .expect("AcceptMarketOffer packets should decode timestamp, counter, and amount");

        assert_eq!(
            packet
                .timestamp
                .duration_since(UNIX_EPOCH)
                .unwrap()
                .as_secs(),
            0x12345678
        );
        assert_eq!(packet.offer_counter, 0x1234);
        assert_eq!(packet.amount, 5);
        assert!(
            payload.is_empty(),
            "AcceptMarketOffer decoding should consume the whole payload"
        );
    }

    #[test]
    fn should_expose_accept_market_offer_kind_constant() {
        assert_eq!(
            AcceptMarketOfferPacket::KIND,
            PacketKind::AcceptMarketOffer,
            "AcceptMarketOffer packets should advertise the correct packet kind"
        );
    }
}