1use std::{convert::Infallible, fmt::Formatter, marker::PhantomData, mem, ops::FromResidual};
2
3pub use protobuf::{well_known_types::Any, CodedOutputStream, Message, ProtobufEnum};
4
5use crate::abi::*;
6
7pub type Method = i32;
8pub type WasmMethod = Method;
9pub type VmMethod = Method;
10pub type CtxId = i32;
11pub type Result<T> = std::result::Result<T, CodeMsg>;
12
13#[derive(Debug, Clone)]
15pub struct WasmCtx<C: Message = Empty> {
16 pub(crate) size: usize,
17 pub(crate) _priv: PhantomData<C>,
18}
19
20#[derive(Debug, Clone)]
21pub struct CodeMsg {
22 pub code: i32,
23 pub msg: String,
24}
25
26impl CodeMsg {
27 pub fn new<S: ToString>(code: i32, msg: S) -> CodeMsg {
28 CodeMsg { code, msg: msg.to_string() }
29 }
30 #[inline]
31 pub fn result<T, S: ToString>(code: i32, msg: S) -> Result<T> {
32 Err(Self::new(code, msg))
33 }
34 pub fn into_result<T>(self) -> Result<T> {
35 Err(self)
36 }
37}
38
39pub type RetCode = i32;
40
41pub const CODE_UNKNOWN: RetCode = -1;
42pub const CODE_EXPORTS: RetCode = -2;
43pub const CODE_WASI: RetCode = -3;
44pub const CODE_COMPILE: RetCode = -4;
45pub const CODE_INSTANTIATION: RetCode = -5;
46pub const CODE_RUNTIME: RetCode = -6;
47pub const CODE_PROTO: RetCode = -7;
48pub const CODE_NONE: RetCode = -8;
49pub const CODE_MEM: RetCode = -9;
50
51impl std::fmt::Display for CodeMsg {
52 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
53 write!(f, "code={}, msg={})", self.code, self.msg)
54 }
55}
56
57impl From<anyhow::Error> for CodeMsg {
58 fn from(e: anyhow::Error) -> Self {
59 if e.is::<CodeMsg>() { e.downcast().unwrap() } else { CodeMsg::new(CODE_UNKNOWN, e) }
60 }
61}
62
63impl From<CodeMsg> for anyhow::Error {
64 fn from(e: CodeMsg) -> Self {
65 anyhow::Error::msg(e)
66 }
67}
68
69impl From<std::io::Error> for CodeMsg {
70 fn from(e: std::io::Error) -> Self {
71 CodeMsg::new(CODE_UNKNOWN, format!("io: {}", e))
72 }
73}
74
75impl From<protobuf::ProtobufError> for CodeMsg {
76 fn from(e: protobuf::ProtobufError) -> Self {
77 CodeMsg::new(CODE_PROTO, format!("protobuf: {}", e))
78 }
79}
80
81impl<R: Message> From<OutRets> for Result<R> {
82 fn from(out_rets: OutRets) -> Self {
83 if out_rets.get_code() != 0 {
84 return CodeMsg::result(out_rets.get_code(), out_rets.get_msg());
85 }
86 out_rets.get_data().unpack::<R>()?.map_or_else(
87 || {
88 CodeMsg::result(
89 CODE_PROTO,
90 "protobuf: the message type does not match the out_rets",
91 )
92 },
93 |data| Ok(data),
94 )
95 }
96}
97
98impl InArgs {
99 pub fn try_new<M: Message>(method: Method, data: M) -> Result<InArgs> {
100 let mut args = InArgs::new();
101 args.set_method(method);
102 args.set_data(pack_any(data)?);
103 Ok(args)
104 }
105 pub fn get_args<R: Message>(&self) -> Result<R> {
106 self.get_data().unpack::<R>()?.map_or_else(
107 || CodeMsg::result(CODE_PROTO, "protobuf: the message type does not match the in_args"),
108 |data| Ok(data),
109 )
110 }
111}
112
113pub fn unpack_any<R: Message>(data: &Any) -> Result<R> {
114 data.unpack::<R>()?.map_or_else(
115 || CodeMsg::result(CODE_PROTO, "protobuf: the message type does not match the data"),
116 |r| Ok(r),
117 )
118}
119
120pub fn pack_any<R: Message>(mut data: R) -> Result<Any> {
121 if data.as_any().is::<Any>() {
122 Ok(unsafe { mem::take(&mut *(&mut data as *mut dyn core::any::Any as *mut Any)) })
123 } else {
124 Ok(Any::pack(&data)?)
125 }
126}
127
128pub fn pack_empty() -> Result<Any> {
129 Ok(Any::pack(&Empty::new())?)
130}
131
132impl From<CodeMsg> for OutRets {
133 fn from(v: CodeMsg) -> Self {
134 let mut res = OutRets::new();
135 res.set_code(v.code);
136 res.set_msg(v.msg);
137 res
138 }
139}
140
141impl From<Any> for OutRets {
142 fn from(v: Any) -> Self {
143 let mut res = OutRets::new();
144 res.set_data(v);
145 res
146 }
147}
148
149impl<R: Message> From<Result<R>> for OutRets {
150 fn from(v: Result<R>) -> Self {
151 match v {
152 Ok(data) => {
153 let mut res = OutRets::new();
154 match pack_any(data) {
155 Ok(data) => {
156 res.set_data(data);
157 }
158 Err(err) => {
159 res.set_code(CODE_PROTO);
160 res.set_msg(err.to_string());
161 }
162 }
163 res
164 }
165 Err(e) => e.into(),
166 }
167 }
168}
169
170impl FromResidual<Option<Infallible>> for OutRets {
171 fn from_residual(_residual: Option<Infallible>) -> Self {
172 CodeMsg::new(CODE_NONE, "not found").into()
173 }
174}
175
176impl FromResidual<Result<Infallible>> for OutRets {
177 fn from_residual(residual: Result<Infallible>) -> Self {
178 match residual {
179 Err(e) => e.into(),
180 _ => {
181 unreachable!()
182 }
183 }
184 }
185}
186
187#[cfg(not(target_family = "wasm"))]
188impl From<wasmer::InstantiationError> for CodeMsg {
189 fn from(v: wasmer::InstantiationError) -> Self {
190 CodeMsg::new(CODE_COMPILE, v)
191 }
192}
193
194#[cfg(not(target_family = "wasm"))]
195impl From<wasmer::CompileError> for CodeMsg {
196 fn from(v: wasmer::CompileError) -> Self {
197 CodeMsg::new(CODE_COMPILE, v)
198 }
199}
200
201#[cfg(not(target_family = "wasm"))]
202impl From<wasmer_wasi::WasiStateCreationError> for CodeMsg {
203 fn from(v: wasmer_wasi::WasiStateCreationError) -> Self {
204 CodeMsg::new(CODE_WASI, v)
205 }
206}
207
208#[cfg(not(target_family = "wasm"))]
209impl From<wasmer_wasi::WasiError> for CodeMsg {
210 fn from(v: wasmer_wasi::WasiError) -> Self {
211 CodeMsg::new(CODE_WASI, v)
212 }
213}
214
215#[cfg(not(target_family = "wasm"))]
216impl From<wasmer::RuntimeError> for CodeMsg {
217 fn from(v: wasmer::RuntimeError) -> Self {
218 CodeMsg::new(CODE_RUNTIME, format!("{:?}", v))
219 }
220}