use serde::Serialize;
use super::common::OrderType;
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateOrder {
pub item_id: String,
#[serde(rename = "type")]
pub order_type: OrderType,
pub platinum: u32,
pub quantity: u32,
pub visible: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub per_trade: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rank: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub charges: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub subtype: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub amber_stars: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cyan_stars: Option<u8>,
}
impl CreateOrder {
pub fn sell(item_id: impl Into<String>, platinum: u32, quantity: u32) -> Self {
debug_assert!(platinum > 0, "platinum must be greater than 0");
debug_assert!(quantity > 0, "quantity must be greater than 0");
Self {
item_id: item_id.into(),
order_type: OrderType::Sell,
platinum,
quantity,
visible: true,
per_trade: None,
rank: None,
charges: None,
subtype: None,
amber_stars: None,
cyan_stars: None,
}
}
pub fn buy(item_id: impl Into<String>, platinum: u32, quantity: u32) -> Self {
debug_assert!(platinum > 0, "platinum must be greater than 0");
debug_assert!(quantity > 0, "quantity must be greater than 0");
Self {
item_id: item_id.into(),
order_type: OrderType::Buy,
platinum,
quantity,
visible: true,
per_trade: None,
rank: None,
charges: None,
subtype: None,
amber_stars: None,
cyan_stars: None,
}
}
pub fn with_mod_rank(mut self, rank: u8) -> Self {
self.rank = Some(rank);
self
}
pub fn with_charges(mut self, charges: u8) -> Self {
self.charges = Some(charges);
self
}
pub fn with_subtype(mut self, subtype: impl Into<String>) -> Self {
self.subtype = Some(subtype.into());
self
}
pub fn with_sculpture_stars(mut self, amber: u8, cyan: u8) -> Self {
self.amber_stars = Some(amber);
self.cyan_stars = Some(cyan);
self
}
pub fn with_per_trade(mut self, per_trade: u32) -> Self {
self.per_trade = Some(per_trade);
self
}
pub fn hidden(mut self) -> Self {
self.visible = false;
self
}
pub fn visible(mut self) -> Self {
self.visible = true;
self
}
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateOrder {
#[serde(skip_serializing_if = "Option::is_none")]
pub platinum: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quantity: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visible: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub per_trade: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rank: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub charges: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub amber_stars: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cyan_stars: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub subtype: Option<String>,
}
impl UpdateOrder {
pub fn new() -> Self {
Self::default()
}
pub fn platinum(mut self, platinum: u32) -> Self {
debug_assert!(platinum > 0, "platinum must be greater than 0");
self.platinum = Some(platinum);
self
}
pub fn quantity(mut self, quantity: u32) -> Self {
debug_assert!(quantity > 0, "quantity must be greater than 0");
self.quantity = Some(quantity);
self
}
pub fn visible(mut self, visible: bool) -> Self {
self.visible = Some(visible);
self
}
pub fn per_trade(mut self, per_trade: u32) -> Self {
self.per_trade = Some(per_trade);
self
}
pub fn rank(mut self, rank: u8) -> Self {
self.rank = Some(rank);
self
}
pub fn charges(mut self, charges: u8) -> Self {
self.charges = Some(charges);
self
}
pub fn amber_stars(mut self, stars: u8) -> Self {
self.amber_stars = Some(stars);
self
}
pub fn cyan_stars(mut self, stars: u8) -> Self {
self.cyan_stars = Some(stars);
self
}
pub fn subtype(mut self, subtype: impl Into<String>) -> Self {
self.subtype = Some(subtype.into());
self
}
pub fn is_empty(&self) -> bool {
self.platinum.is_none()
&& self.quantity.is_none()
&& self.visible.is_none()
&& self.per_trade.is_none()
&& self.rank.is_none()
&& self.charges.is_none()
&& self.amber_stars.is_none()
&& self.cyan_stars.is_none()
&& self.subtype.is_none()
}
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TopOrderFilters {
#[serde(skip_serializing_if = "Option::is_none")]
pub rank: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rank_lt: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub charges: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub charges_lt: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub amber_stars: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub amber_stars_lt: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cyan_stars: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cyan_stars_lt: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub subtype: Option<String>,
}
impl TopOrderFilters {
pub fn new() -> Self {
Self::default()
}
pub fn rank(mut self, rank: u8) -> Self {
self.rank = Some(rank);
self
}
pub fn rank_lt(mut self, rank: u8) -> Self {
debug_assert!(rank > 0, "rank_lt must be greater than 0");
self.rank_lt = Some(rank);
self
}
pub fn charges(mut self, charges: u8) -> Self {
self.charges = Some(charges);
self
}
pub fn charges_lt(mut self, charges: u8) -> Self {
debug_assert!(charges > 0, "charges_lt must be greater than 0");
self.charges_lt = Some(charges);
self
}
pub fn amber_stars(mut self, stars: u8) -> Self {
self.amber_stars = Some(stars);
self
}
pub fn amber_stars_lt(mut self, stars: u8) -> Self {
debug_assert!(stars > 0, "amber_stars_lt must be greater than 0");
self.amber_stars_lt = Some(stars);
self
}
pub fn cyan_stars(mut self, stars: u8) -> Self {
self.cyan_stars = Some(stars);
self
}
pub fn cyan_stars_lt(mut self, stars: u8) -> Self {
debug_assert!(stars > 0, "cyan_stars_lt must be greater than 0");
self.cyan_stars_lt = Some(stars);
self
}
pub fn subtype(mut self, subtype: impl Into<String>) -> Self {
self.subtype = Some(subtype.into());
self
}
pub fn is_empty(&self) -> bool {
self.rank.is_none()
&& self.rank_lt.is_none()
&& self.charges.is_none()
&& self.charges_lt.is_none()
&& self.amber_stars.is_none()
&& self.amber_stars_lt.is_none()
&& self.cyan_stars.is_none()
&& self.cyan_stars_lt.is_none()
&& self.subtype.is_none()
}
pub(crate) fn to_query_string(&self) -> String {
let mut params = Vec::new();
if let Some(v) = self.rank {
params.push(format!("rank={}", v));
}
if let Some(v) = self.rank_lt {
params.push(format!("rankLt={}", v));
}
if let Some(v) = self.charges {
params.push(format!("charges={}", v));
}
if let Some(v) = self.charges_lt {
params.push(format!("chargesLt={}", v));
}
if let Some(v) = self.amber_stars {
params.push(format!("amberStars={}", v));
}
if let Some(v) = self.amber_stars_lt {
params.push(format!("amberStarsLt={}", v));
}
if let Some(v) = self.cyan_stars {
params.push(format!("cyanStars={}", v));
}
if let Some(v) = self.cyan_stars_lt {
params.push(format!("cyanStarsLt={}", v));
}
if let Some(ref v) = self.subtype {
params.push(format!("subtype={}", urlencoding::encode(v)));
}
if params.is_empty() {
String::new()
} else {
format!("?{}", params.join("&"))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_sell_order() {
let order = CreateOrder::sell("test-item", 100, 5);
assert_eq!(order.item_id, "test-item");
assert!(matches!(order.order_type, OrderType::Sell));
assert_eq!(order.platinum, 100);
assert_eq!(order.quantity, 5);
assert!(order.visible);
}
#[test]
fn test_create_buy_order() {
let order = CreateOrder::buy("test-item", 50, 10);
assert!(matches!(order.order_type, OrderType::Buy));
assert_eq!(order.platinum, 50);
}
#[test]
fn test_order_builder_chain() {
let order = CreateOrder::sell("mod-item", 100, 1)
.with_mod_rank(10)
.hidden();
assert_eq!(order.rank, Some(10));
assert!(!order.visible);
}
#[test]
fn test_update_order() {
let update = UpdateOrder::new().platinum(90).quantity(5);
assert_eq!(update.platinum, Some(90));
assert_eq!(update.quantity, Some(5));
assert!(!update.is_empty());
}
#[test]
fn test_update_order_empty() {
let update = UpdateOrder::new();
assert!(update.is_empty());
}
#[test]
fn test_serialization() {
let order = CreateOrder::sell("item", 100, 1).with_mod_rank(5);
let json = serde_json::to_string(&order).unwrap();
assert!(json.contains("\"rank\":5"));
assert!(!json.contains("charges")); }
}