wasmy_abi/
types.rs

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/// Default WasmContext implementation.
14#[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}