Skip to main content

wowlab_wasm/dto/
parcel.rs

1//! DTO wrappers for parcel codec types crossing the wasm boundary, adding camelCase serde renames.
2
3use serde::{Deserialize, Serialize};
4use tsify::Tsify;
5use wowlab_parsers::parcel::{
6    DEFAULT_MAX_DECODED_BODY, DEFAULT_MAX_ENCODED_LEN, DEFAULT_MAX_PAYLOAD_BYTES, DecodeMeta,
7    ExportKind, ResultExport, ResultItem,
8};
9
10#[derive(Clone, Debug, Deserialize, Serialize, Tsify)]
11#[tsify(into_wasm_abi, from_wasm_abi)]
12#[serde(rename_all = "camelCase")]
13pub struct ParcelConfigDto {
14    pub prefix: String,
15    #[serde(default)]
16    pub content_types: Vec<String>,
17    #[serde(default)]
18    pub default_content_type: Option<String>,
19    #[serde(default)]
20    pub max_encoded_len: Option<u32>,
21    #[serde(default)]
22    pub max_decoded_body: Option<u32>,
23    #[serde(default)]
24    pub max_payload_bytes: Option<u32>,
25}
26
27impl ParcelConfigDto {
28    pub(crate) fn into_codec_config(self) -> wowlab_parsers::parcel::CodecConfig {
29        wowlab_parsers::parcel::CodecConfig {
30            prefix: self.prefix,
31            content_types: self.content_types,
32            default_content_type: self.default_content_type,
33            max_encoded_len: self.max_encoded_len.map(|v| v as usize),
34            max_decoded_body: self.max_decoded_body.map(|v| v as usize),
35            max_payload_bytes: self.max_payload_bytes.map(|v| v as usize),
36        }
37    }
38}
39
40#[derive(Clone, Debug, Deserialize, Serialize, Tsify)]
41#[tsify(into_wasm_abi, from_wasm_abi)]
42#[serde(rename_all = "camelCase")]
43pub struct ParcelDecodeMetaDto {
44    pub prefix: String,
45    pub content_type: String,
46    pub checksum: String,
47    pub encoded_bytes: u32,
48    pub decoded_body_bytes: u32,
49    pub payload_bytes: u32,
50}
51
52impl From<DecodeMeta> for ParcelDecodeMetaDto {
53    fn from(value: DecodeMeta) -> Self {
54        Self {
55            prefix: value.prefix,
56            content_type: value.content_type,
57            checksum: value.checksum,
58            encoded_bytes: wowlab_types::numeric::usize_to_u32_saturating(value.encoded_bytes),
59            decoded_body_bytes: wowlab_types::numeric::usize_to_u32_saturating(
60                value.decoded_body_bytes,
61            ),
62            payload_bytes: wowlab_types::numeric::usize_to_u32_saturating(value.payload_bytes),
63        }
64    }
65}
66
67#[derive(Clone, Debug, Deserialize, Serialize, Tsify)]
68#[tsify(into_wasm_abi, from_wasm_abi)]
69#[serde(rename_all = "camelCase")]
70pub struct ParcelDecodedDto {
71    pub payload: Vec<u8>,
72    pub meta: ParcelDecodeMetaDto,
73}
74
75#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, Tsify)]
76#[tsify(into_wasm_abi, from_wasm_abi)]
77#[serde(rename_all = "snake_case")]
78#[non_exhaustive]
79pub enum ExportKindDto {
80    Bib,
81    Drops,
82}
83
84impl From<ExportKind> for ExportKindDto {
85    fn from(value: ExportKind) -> Self {
86        match value {
87            ExportKind::Drops => Self::Drops,
88            _ => Self::Bib,
89        }
90    }
91}
92
93impl From<ExportKindDto> for ExportKind {
94    fn from(value: ExportKindDto) -> Self {
95        match value {
96            ExportKindDto::Bib => Self::Bib,
97            ExportKindDto::Drops => Self::Drops,
98        }
99    }
100}
101
102#[derive(Clone, Debug, Deserialize, Serialize, Tsify)]
103#[tsify(into_wasm_abi, from_wasm_abi)]
104#[serde(rename_all = "camelCase")]
105// #t(rust_similar_structs) wasm DTO owns JavaScript ABI derives while the parser keeps the canonical parcel model
106pub struct ResultItemDto {
107    pub slot: String,
108    pub item_id: u32,
109    #[serde(default)]
110    pub bonus_ids: Vec<u32>,
111    #[serde(default)]
112    pub gem_ids: Vec<u32>,
113    #[serde(default)]
114    pub gem_bonus_ids: Vec<u32>,
115    #[serde(default)]
116    pub enchant_id: Option<u32>,
117    #[serde(default)]
118    pub crafted_stats: Vec<u32>,
119    #[serde(default)]
120    pub crafting_quality: Option<u8>,
121    #[serde(default)]
122    pub drop_level: Option<u32>,
123    #[serde(default)]
124    pub suffix: Option<i32>,
125    #[serde(default)]
126    pub item_level: Option<u32>,
127    pub mean_dps: f64,
128    pub dps_delta_vs_baseline: f64,
129    #[serde(default)]
130    pub ci95_half: Option<f64>,
131    pub rank: u32,
132    #[serde(default)]
133    pub win_rate: Option<f64>,
134    #[serde(default)]
135    pub source_label: Option<String>,
136}
137
138impl From<ResultItem> for ResultItemDto {
139    fn from(v: ResultItem) -> Self {
140        Self {
141            slot: v.slot,
142            item_id: v.item_id,
143            bonus_ids: v.bonus_ids,
144            gem_ids: v.gem_ids,
145            gem_bonus_ids: v.gem_bonus_ids,
146            enchant_id: v.enchant_id,
147            crafted_stats: v.crafted_stats,
148            crafting_quality: v.crafting_quality,
149            drop_level: v.drop_level,
150            suffix: v.suffix,
151            item_level: v.item_level,
152            mean_dps: v.mean_dps,
153            dps_delta_vs_baseline: v.dps_delta_vs_baseline,
154            ci95_half: v.ci95_half,
155            rank: v.rank,
156            win_rate: v.win_rate,
157            source_label: v.source_label,
158        }
159    }
160}
161
162impl From<ResultItemDto> for ResultItem {
163    fn from(v: ResultItemDto) -> Self {
164        Self {
165            slot: v.slot,
166            item_id: v.item_id,
167            bonus_ids: v.bonus_ids,
168            gem_ids: v.gem_ids,
169            gem_bonus_ids: v.gem_bonus_ids,
170            enchant_id: v.enchant_id,
171            crafted_stats: v.crafted_stats,
172            crafting_quality: v.crafting_quality,
173            drop_level: v.drop_level,
174            suffix: v.suffix,
175            item_level: v.item_level,
176            mean_dps: v.mean_dps,
177            dps_delta_vs_baseline: v.dps_delta_vs_baseline,
178            ci95_half: v.ci95_half,
179            rank: v.rank,
180            win_rate: v.win_rate,
181            source_label: v.source_label,
182        }
183    }
184}
185
186#[derive(Clone, Debug, Deserialize, Serialize, Tsify)]
187#[tsify(into_wasm_abi, from_wasm_abi)]
188#[serde(rename_all = "camelCase")]
189pub struct ResultExportDto {
190    pub v: u32,
191    pub kind: ExportKindDto,
192    pub spec: String,
193    #[serde(default)]
194    pub job_id: Option<String>,
195    pub generated_at_ms: f64,
196    pub baseline_dps: f64,
197    pub winner_dps: f64,
198    pub items: Vec<ResultItemDto>,
199    #[serde(default)]
200    pub note: Option<String>,
201}
202
203impl From<ResultExport> for ResultExportDto {
204    fn from(v: ResultExport) -> Self {
205        Self {
206            v: v.v,
207            kind: v.kind.into(),
208            spec: v.spec,
209            job_id: v.job_id,
210            generated_at_ms: crate::numeric::u64_to_js_number(v.generated_at_ms),
211            baseline_dps: v.baseline_dps,
212            winner_dps: v.winner_dps,
213            items: v.items.into_iter().map(ResultItemDto::from).collect(),
214            note: v.note,
215        }
216    }
217}
218
219impl From<ResultExportDto> for ResultExport {
220    fn from(v: ResultExportDto) -> Self {
221        Self {
222            v: v.v,
223            kind: v.kind.into(),
224            spec: v.spec,
225            job_id: v.job_id,
226            generated_at_ms: crate::numeric::js_number_to_u64(v.generated_at_ms),
227            baseline_dps: v.baseline_dps,
228            winner_dps: v.winner_dps,
229            items: v.items.into_iter().map(ResultItem::from).collect(),
230            note: v.note,
231        }
232    }
233}
234
235#[derive(Clone, Debug, Deserialize, Serialize, Tsify)]
236#[tsify(into_wasm_abi, from_wasm_abi)]
237#[serde(rename_all = "camelCase")]
238pub struct ParcelLimitsDto {
239    pub max_encoded_len: u32,
240    pub max_decoded_body: u32,
241    pub max_payload_bytes: u32,
242}
243
244impl ParcelLimitsDto {
245    pub(crate) fn defaults() -> Self {
246        Self {
247            max_encoded_len: wowlab_types::numeric::usize_to_u32_saturating(
248                DEFAULT_MAX_ENCODED_LEN,
249            ),
250            max_decoded_body: wowlab_types::numeric::usize_to_u32_saturating(
251                DEFAULT_MAX_DECODED_BODY,
252            ),
253            max_payload_bytes: wowlab_types::numeric::usize_to_u32_saturating(
254                DEFAULT_MAX_PAYLOAD_BYTES,
255            ),
256        }
257    }
258}