as_ffi_bindings/
any_ptr.rs1use super::{Env, Memory, Read, Write};
2use crate::{BufferPtr, StringPtr};
3use std::convert::{TryFrom, TryInto};
4use wasmer::{Array, FromToNativeWasmType, Value, WasmPtr};
5
6use crate::tools::export_asr;
7
8#[derive(Clone, Copy)]
10pub struct AnyPtr(WasmPtr<u8, Array>);
11pub struct AnyPtrExported {
12 pub id: u32,
13 pub content: Vec<u8>,
14}
15
16impl AnyPtrExported {
17 pub fn serialize(self) -> Vec<u8> {
18 let ret = self.id.to_be_bytes().to_vec();
19 [ret, self.content].concat()
20 }
21
22 pub fn deserialize(b: &[u8]) -> anyhow::Result<Self> {
23 if b.len() < 4 {
24 anyhow::bail!("any pointer to small")
25 }
26 Ok(Self {
27 id: u32::from_be_bytes(b[..4].try_into()?),
28 content: b[4..].to_vec(),
29 })
30 }
31}
32
33pub enum Type {
34 String(Box<StringPtr>),
35 Buffer(Box<BufferPtr>),
36 Any(Box<AnyPtr>),
37}
38
39impl Type {
40 pub fn offset(&self) -> u32 {
41 match self {
42 Type::String(ptr) => ptr.offset(),
43 Type::Buffer(ptr) => ptr.offset(),
44 Type::Any(ptr) => ptr.offset(),
45 }
46 }
47}
48
49impl AnyPtr {
50 pub fn new(offset: u32) -> Self {
51 Self(WasmPtr::new(offset))
52 }
53 pub fn to_type(self, memory: &Memory) -> anyhow::Result<Type> {
54 let t = ptr_id(self.offset(), memory)?;
55 if t == 0 {
56 Ok(Type::Buffer(Box::new(BufferPtr::new(self.offset()))))
57 } else if t == 1 {
58 Ok(Type::String(Box::new(StringPtr::new(self.offset()))))
59 } else {
60 Ok(Type::Any(Box::new(self)))
61 }
62 }
63 pub fn offset(&self) -> u32 {
65 self.0.offset()
66 }
67 pub fn export(&self, memory: &Memory) -> anyhow::Result<AnyPtrExported> {
68 let content = self.read(memory)?;
69 let id = ptr_id(self.offset(), memory)?;
70 Ok(AnyPtrExported { content, id })
71 }
72 pub fn import(ptr_exported: &AnyPtrExported, env: &Env) -> anyhow::Result<Type> {
75 if ptr_exported.id == 0 {
76 Ok(Type::Buffer(BufferPtr::alloc(&ptr_exported.content, env)?))
77 } else if ptr_exported.id == 1 {
78 let utf16_vec = unsafe {
79 let len = ptr_exported.content.len();
80 if len % 2 != 0 {
81 anyhow::bail!("Cannot cast u8 slice into u16")
82 }
83 let c = ptr_exported.content.as_ptr().cast::<u16>();
84 let a = std::slice::from_raw_parts(c, len / 2);
85 a.to_vec()
86 };
87 Ok(Type::String(StringPtr::alloc(
88 &String::from_utf16_lossy(&utf16_vec),
89 env,
90 )?))
91 } else {
92 let ptr = AnyPtr::alloc(&ptr_exported.content, env)?;
94 set_id(ptr.offset(), ptr_exported.id, env)?;
95 Ok(Type::Any(ptr))
96 }
97 }
98}
99
100unsafe impl FromToNativeWasmType for AnyPtr {
101 type Native = i32;
102 fn to_native(self) -> Self::Native {
103 self.offset() as i32
104 }
105 fn from_native(n: Self::Native) -> Self {
106 Self::new(n as u32)
107 }
108}
109
110impl Read<Vec<u8>> for AnyPtr {
111 fn read(&self, memory: &Memory) -> anyhow::Result<Vec<u8>> {
112 let size = self.size(memory)?;
113 if let Some(buf) = self.0.deref(memory, 0, size * 2) {
114 Ok(buf.iter().map(|b| b.get()).collect())
115 } else {
116 anyhow::bail!("Wrong offset: can't read any object")
117 }
118 }
119
120 fn size(&self, memory: &Memory) -> anyhow::Result<u32> {
121 size(self.0.offset(), memory)
122 }
123}
124
125impl Write<Vec<u8>> for AnyPtr {
126 fn alloc(value: &Vec<u8>, env: &Env) -> anyhow::Result<Box<AnyPtr>> {
127 let new = export_asr!(fn_new, env);
128 let size = i32::try_from(value.len())?;
129 let offset = u32::try_from(
130 if let Some(value) = new.call(&[Value::I32(size), Value::I32(0)])?.get(0) {
131 match value.i32() {
132 Some(offset) => offset,
133 _ => anyhow::bail!("Unable to allocate value"),
134 }
135 } else {
136 anyhow::bail!("Unable to allocate value")
137 },
138 )?;
139 write_buffer(offset, value, env)?;
140 Ok(Box::new(AnyPtr::new(offset)))
141 }
142
143 fn write(&mut self, value: &Vec<u8>, env: &Env) -> anyhow::Result<Box<Self>> {
144 let memory = match env.memory.get_ref() {
145 Some(mem) => mem,
146 _ => anyhow::bail!("Cannot get memory"),
147 };
148 let prev_size = size(self.offset(), memory)?;
149 let new_size = u32::try_from(value.len())?;
150 if prev_size == new_size {
151 write_buffer(self.offset(), value, env)?;
152 Ok(Box::new(*self))
153 } else {
154 let unpin = export_asr!(fn_pin, env);
156 unpin.call(&[Value::I32(self.offset().try_into()?)])?;
157
158 let collect = export_asr!(fn_collect, env);
160 collect.call(&[])?;
161
162 AnyPtr::alloc(value, env)
164 }
165 }
166
167 fn free(self, _env: &Env) -> anyhow::Result<()> {
168 todo!("Release the memory from this string")
169 }
170}
171
172fn write_buffer(offset: u32, value: &[u8], env: &Env) -> anyhow::Result<()> {
173 let view = match env.memory.get_ref() {
174 Some(mem) => mem.view::<u8>(),
175 _ => anyhow::bail!("Uninitialized memory"),
176 };
177 let from = usize::try_from(offset)?;
179 for (bytes, cell) in value.iter().zip(view[from..from + value.len()].iter()) {
180 cell.set(*bytes);
181 }
182 Ok(())
183}
184
185fn size(offset: u32, memory: &Memory) -> anyhow::Result<u32> {
186 if offset < 8 {
187 anyhow::bail!("Wrong offset: less than 8")
188 }
189 if let Some(cell) = memory.view::<u32>().get(offset as usize / (32 / 8) - 1) {
192 Ok(cell.get() / 2)
193 } else {
194 anyhow::bail!("Wrong offset: can't read size")
195 }
196}
197
198fn ptr_id(offset: u32, memory: &Memory) -> anyhow::Result<u32> {
199 if offset < 8 {
200 anyhow::bail!("Wrong offset: less than 8")
201 }
202 if let Some(cell) = memory.view::<u32>().get(offset as usize / (32 / 8) - 2) {
205 Ok(cell.get())
206 } else {
207 anyhow::bail!("Wrong offset: can't read type")
208 }
209}
210
211fn set_id(offset: u32, id: u32, env: &Env) -> anyhow::Result<()> {
212 if offset < 8 {
213 anyhow::bail!("Wrong offset: less than 8")
214 }
215 let memory = match env.memory.get_ref() {
216 Some(mem) => mem,
217 _ => anyhow::bail!("Uninitialized memory"),
218 };
219 if let Some(cell) = memory.view::<u32>().get((offset as usize / (32 / 8)) - 2) {
222 cell.set(id);
223 } else {
224 anyhow::bail!("Wrong offset: can't read type")
225 }
226
227 Ok(())
228}