use crate::packets::decoder::Decoder;
use super::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MarketOfferKind {
Buy = 0,
Sell = 1,
}
impl TryFrom<u8> for MarketOfferKind {
type Error = DecodableError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Buy),
1 => Ok(Self::Sell),
_ => Err(DecodableError::InvalidFieldValue {
field: "offer_kind",
value,
}),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CreateMarketOfferPacket {
pub offer_kind: MarketOfferKind,
pub item_id: u16,
pub item_tier: Option<u8>,
pub amount: u16,
pub price: u64,
pub is_anonymous: bool,
}
impl Decodable for CreateMarketOfferPacket {
const KIND: PacketKind = PacketKind::CreateMarketOffer;
fn decode(mut bytes: &mut &[u8]) -> Result<Self, DecodableError> {
let offer_kind = MarketOfferKind::try_from(bytes.get_u8()?)?;
let item_id = bytes.get_u16()?;
let item_tier = match bytes.len() {
12 => Some(bytes.get_u8()?),
_ => None,
};
let amount = bytes.get_u16()?;
let price = bytes.get_u64()?;
let is_anonymous = bytes.get_bool()?;
Ok(Self {
offer_kind,
item_id,
item_tier,
amount,
price,
is_anonymous,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_decode_create_market_offer_without_item_tier() {
let mut payload: &[u8] = &[1, 0x2A, 0x00, 5, 0, 0x15, 0xCD, 0x5B, 0x07, 0, 0, 0, 0, 1];
let packet = CreateMarketOfferPacket::decode(&mut payload)
.expect("CreateMarketOffer packets should decode payloads without item tiers");
assert_eq!(packet.offer_kind, MarketOfferKind::Sell);
assert_eq!(packet.item_id, 42);
assert_eq!(packet.item_tier, None);
assert_eq!(packet.amount, 5);
assert_eq!(packet.price, 123_456_789);
assert!(packet.is_anonymous);
assert!(
payload.is_empty(),
"Tierless create-market-offer packets should consume the whole payload"
);
}
#[test]
fn should_decode_create_market_offer_with_item_tier() {
let mut payload: &[u8] = &[
1, 0x2A, 0x00, 10, 5, 0, 0x15, 0xCD, 0x5B, 0x07, 0, 0, 0, 0, 0,
];
let packet = CreateMarketOfferPacket::decode(&mut payload)
.expect("CreateMarketOffer packets should decode payloads with item tiers");
assert_eq!(packet.offer_kind, MarketOfferKind::Sell);
assert_eq!(packet.item_id, 42);
assert_eq!(packet.item_tier, Some(10));
assert_eq!(packet.amount, 5);
assert_eq!(packet.price, 123_456_789);
assert!(!packet.is_anonymous);
assert!(
payload.is_empty(),
"Tiered create-market-offer packets should consume the whole payload"
);
}
#[test]
fn should_expose_create_market_offer_kind_constant() {
assert_eq!(
CreateMarketOfferPacket::KIND,
PacketKind::CreateMarketOffer,
"CreateMarketOffer packets should advertise the correct packet kind"
);
}
#[test]
fn should_reject_unknown_market_offer_kind() {
let mut payload: &[u8] = &[9, 0x2A, 0x00, 5, 0, 0x15, 0xCD, 0x5B, 0x07, 0, 0, 0, 0, 1];
let error = CreateMarketOfferPacket::decode(&mut payload)
.expect_err("CreateMarketOffer packets should reject unknown offer kinds");
assert!(
matches!(
error,
DecodableError::InvalidFieldValue {
field: "offer_kind",
value: 9
}
),
"Unknown market-offer kinds should surface a typed decoding error"
);
}
}