1use serde::de::DeserializeOwned;
2use wasmrs_runtime::ConditionallySend;
3
4use crate::{Error, Packet, PacketError, PacketExt, PacketPayload};
5
6#[derive(Debug)]
7pub struct VPacket<T>
8where
9 T: ConditionallySend,
10{
11 pub(crate) packet: Option<Result<Packet, anyhow::Error>>,
12 pub(crate) value: Option<T>,
13}
14
15impl<T> VPacket<T>
16where
17 T: ConditionallySend,
18{
19 pub fn new(packet: Packet) -> Self
20 where
21 T: DeserializeOwned,
22 {
23 Self {
24 value: Default::default(),
25 packet: Some(Ok(packet)),
26 }
27 }
28
29 pub fn from_result(packet: Result<Packet, anyhow::Error>) -> Self
30 where
31 T: DeserializeOwned + ConditionallySend,
32 {
33 Self {
34 value: Default::default(),
35 packet: Some(packet),
36 }
37 }
38
39 pub const fn from_value(value: T) -> Self {
40 VPacket {
41 packet: None,
42 value: Some(value),
43 }
44 }
45
46 pub fn decode(self) -> Result<T, Error>
47 where
48 T: DeserializeOwned + ConditionallySend,
49 {
50 match self.value {
51 Some(value) => Ok(value),
52 None => match self.packet {
53 Some(Ok(packet)) => packet.decode::<T>(),
54 Some(Err(e)) => Err(Error::Component(e.to_string())),
55 None => unreachable!("tried to decode VPacket that had no packet or value"),
56 },
57 }
58 }
59}
60
61impl<T> From<Result<Packet, anyhow::Error>> for VPacket<T>
62where
63 T: DeserializeOwned + ConditionallySend,
64{
65 fn from(packet: Result<Packet, anyhow::Error>) -> Self {
66 Self::from_result(packet)
67 }
68}
69
70impl<T> From<VPacket<T>> for PacketPayload
71where
72 T: ConditionallySend + serde::Serialize,
73{
74 fn from(packet: VPacket<T>) -> Self {
75 match packet.packet {
76 Some(Ok(p)) => p.payload,
77 Some(Err(e)) => PacketPayload::Err(PacketError::new(e.to_string())),
78 None => packet.value.map_or_else(
79 || unreachable!("tried to convert VPacket that had no packet or value"),
80 |v| PacketPayload::encode(v),
81 ),
82 }
83 }
84}
85
86impl<T> PacketExt for VPacket<T>
87where
88 T: ConditionallySend,
89{
90 fn has_data(&self) -> bool {
91 match self.value {
92 Some(_) => true,
93 None => self
94 .packet
95 .as_ref()
96 .map_or(false, |p| p.as_ref().map_or(false, |p| p.has_data())),
97 }
98 }
99
100 fn port(&self) -> &str {
101 self.packet.as_ref().map_or_else(
102 || panic!("tried to query port for VPacket created manually"),
103 |p| p.as_ref().map_or(Packet::FATAL_ERROR, |p| p.port()),
104 )
105 }
106
107 fn flags(&self) -> u8 {
108 match self.value {
109 Some(_) => 0,
110 None => self.packet.as_ref().map_or(0, |p| p.as_ref().map_or(0, |p| p.flags())),
111 }
112 }
113}