mechtron_host/
lib.rs

1#![allow(warnings)]
2pub mod err;
3
4#[macro_use]
5extern crate lazy_static;
6
7use crate::err::{DefaultHostErr, HostErr};
8use cosmic_space::artifact::asynch::{ArtifactApi, ReadArtifactFetcher};
9use cosmic_space::artifact::ArtRef;
10use cosmic_space::config::mechtron::MechtronConfig;
11use cosmic_space::err::SpaceErr;
12use cosmic_space::loc::{Layer, ToSurface};
13use cosmic_space::particle::{Details, Property};
14use cosmic_space::substance::Bin;
15use cosmic_space::wave::DirectedWave;
16use cosmic_space::wave::{DirectedKind, UltraWave, WaveKind};
17
18use wasmer::Function;
19use wasmer_compiler_singlepass::Singlepass;
20
21use cosmic_space::hyper::{HostCmd, HyperSubstance};
22use cosmic_space::log::{LogSource, PointLogger, RootLogger, StdOutAppender};
23use cosmic_space::substance::Substance;
24use cosmic_space::wasm::Timestamp;
25use cosmic_space::wave::core::hyp::HypMethod;
26use cosmic_space::wave::{Agent, DirectedProto};
27use cosmic_space::{loc, VERSION};
28
29use cosmic_space::wave::core::cmd::CmdMethod;
30use cosmic_space::wave::core::Method;
31use cosmic_space::wave::exchange::asynch::ProtoTransmitter;
32use cosmic_space::wave::exchange::asynch::ProtoTransmitterBuilder;
33use cosmic_space::wave::exchange::SetStrategy;
34use std::collections::HashMap;
35use std::str::FromStr;
36use std::sync::{Arc, Mutex, RwLock};
37use std::{sync, thread};
38use threadpool::ThreadPool;
39use tokio::runtime::Handle;
40use tokio::sync::mpsc;
41use wasmer::{Array, imports, Instance, Module, Store, Value, WasmerEnv, WasmPtr};
42use cosmic_space::point::Point;
43
44#[derive(Clone)]
45pub struct HostsApi {
46    tx: tokio::sync::mpsc::Sender<HostsCall>,
47}
48
49impl HostsApi {
50    pub async fn get_via_wasm(&self, wasm: &Point) -> Result<WasmHostApi, SpaceErr> {
51        let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
52        self.tx
53            .send(HostsCall::GetViaWasm {
54                wasm: wasm.clone(),
55                rtn,
56            })
57            .await?;
58        rtn_rx.await?
59    }
60
61    pub async fn get_via_point(&self, point: &Point) -> Result<WasmHostApi, SpaceErr> {
62        let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
63        self.tx
64            .send(HostsCall::GetViaPoint {
65                point: point.clone(),
66                rtn,
67            })
68            .await?;
69        rtn_rx.await?
70    }
71
72    pub async fn create(&self, details: Details, wasm: Point) -> Result<WasmHostApi, SpaceErr> {
73        let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
74        self.tx
75            .send(HostsCall::Create { details, wasm, rtn })
76            .await?;
77        rtn_rx.await?
78    }
79}
80
81pub enum HostsCall {
82    GetViaWasm {
83        wasm: Point,
84        rtn: tokio::sync::oneshot::Sender<Result<WasmHostApi, SpaceErr>>,
85    },
86    GetViaPoint {
87        point: Point,
88        rtn: tokio::sync::oneshot::Sender<Result<WasmHostApi, SpaceErr>>,
89    },
90    Create {
91        details: Details,
92        wasm: Point,
93        rtn: tokio::sync::oneshot::Sender<Result<WasmHostApi, SpaceErr>>,
94    },
95}
96
97pub struct HostsRunner {
98    store: Store,
99    artifacts: ArtifactApi,
100    wasm_to_host: HashMap<Point, WasmHostApi>,
101    point_to_host: HashMap<Point, WasmHostApi>,
102    mechtron_to_host: HashMap<Point, Point>,
103    transmitter: ProtoTransmitterBuilder,
104    logger: RootLogger,
105    rx: tokio::sync::mpsc::Receiver<HostsCall>,
106}
107
108impl HostsRunner {
109    pub fn new(
110        artifacts: ArtifactApi,
111        transmitter: ProtoTransmitterBuilder,
112        logger: RootLogger,
113    ) -> HostsApi {
114        let (tx, rx) = mpsc::channel(1024);
115        let runner = Self {
116            rx,
117            store: Store::default(),
118            artifacts,
119            wasm_to_host: Default::default(),
120            point_to_host: Default::default(),
121            mechtron_to_host: Default::default(),
122            transmitter,
123            logger,
124        };
125        tokio::spawn(async move {
126            runner.start().await;
127        });
128        HostsApi { tx }
129    }
130
131    async fn start(mut self) {
132        while let Some(call) = self.rx.recv().await {
133            match call {
134                HostsCall::Create { details, wasm, rtn } => {
135                    rtn.send(
136                        self.create_host(details, wasm, self.transmitter.clone())
137                            .await,
138                    )
139                    .unwrap_or_default();
140                }
141                HostsCall::GetViaWasm { wasm, rtn } => {
142                    rtn.send(self.wasm_to_host.get(&wasm).cloned().ok_or(
143                        format!("could not get host via wasm: {}", wasm.to_string()).into(),
144                    ));
145                }
146                HostsCall::GetViaPoint { point, rtn } => {
147                    rtn.send(self.point_to_host.get(&point).cloned().ok_or(
148                        format!("could not get host via point: {}", point.to_string()).into(),
149                    ));
150                }
151            }
152        }
153    }
154
155    async fn create_host(
156        &mut self,
157        details: Details,
158        wasm: Point,
159        mut transmitter: ProtoTransmitterBuilder,
160    ) -> Result<WasmHostApi, SpaceErr> {
161        transmitter.via = SetStrategy::Override(details.stub.point.to_surface());
162        let transmitter = transmitter.build();
163
164        let logger = self.logger.point(details.stub.point.clone());
165        let bin = self.artifacts.wasm(&wasm).await?;
166        let host = WasmHostRunner::new(details.clone(), &mut self.store, bin, transmitter, logger)
167            .map_err(|e| e.to_space_err())?;
168        self.wasm_to_host.insert(wasm.clone(), host.clone());
169        self.point_to_host.insert(details.stub.point, host.clone());
170
171        host.init().await;
172
173        Ok(host)
174    }
175
176    pub fn get(&self, point: &Point) -> Result<WasmHostApi, SpaceErr> {
177        self.point_to_host
178            .get(point)
179            .cloned()
180            .ok_or(format!("cannot find host: {}", point.to_string()).into())
181    }
182}
183
184pub struct WasmHostSkel {
185    pool: Arc<ThreadPool>,
186}
187
188#[derive(Debug)]
189pub enum WasmHostCall {
190    Init(tokio::sync::oneshot::Sender<Result<(), DefaultHostErr>>),
191    Point(tokio::sync::oneshot::Sender<Point>),
192    HostCmd {
193        cmd: HostCmd,
194        rtn: tokio::sync::oneshot::Sender<Result<(), DefaultHostErr>>,
195    },
196    WriteString {
197        string: String,
198        rtn: tokio::sync::oneshot::Sender<Result<i32, DefaultHostErr>>,
199    },
200    WriteBuffer {
201        buffer: Vec<u8>,
202        rtn: tokio::sync::oneshot::Sender<Result<i32, DefaultHostErr>>,
203    },
204    SerializeWaveToGuest {
205        wave: UltraWave,
206        rtn: tokio::sync::oneshot::Sender<Result<i32, DefaultHostErr>>,
207    },
208    DeSerializeWaveToHost {
209        wave: i32,
210        rtn: tokio::sync::oneshot::Sender<Result<UltraWave, DefaultHostErr>>,
211    },
212    WaveToHost {
213        wave: UltraWave,
214        rtn: tokio::sync::oneshot::Sender<Result<Option<UltraWave>, DefaultHostErr>>,
215    },
216    GuestConsumeWave {
217        wave: i32,
218        rtn: tokio::sync::oneshot::Sender<Result<Option<UltraWave>, DefaultHostErr>>,
219    },
220    ConsumeString {
221        buffer_id: i32,
222        rtn: tokio::sync::oneshot::Sender<Result<String, DefaultHostErr>>,
223    },
224    ConsumeBuffer {
225        buffer_id: i32,
226        rtn: tokio::sync::oneshot::Sender<Result<Vec<u8>, DefaultHostErr>>,
227    },
228}
229
230#[derive(WasmerEnv, Clone)]
231pub struct WasmHostApi {
232    tx: mpsc::Sender<WasmHostCall>,
233}
234
235impl WasmHostApi {
236    pub fn new(tx: mpsc::Sender<WasmHostCall>) -> Self {
237        Self { tx }
238    }
239
240    pub async fn point(&self) -> Result<Point, DefaultHostErr> {
241        let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
242        self.tx.send(WasmHostCall::Point(rtn)).await?;
243        Ok(rtn_rx.await?)
244    }
245
246    pub async fn init(&self) -> Result<(), DefaultHostErr> {
247        let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
248        self.tx.send(WasmHostCall::Init(rtn)).await?;
249        let rtn = rtn_rx.await?;
250
251        rtn
252    }
253
254    pub async fn create_mechtron(&self, cmd: HostCmd) -> Result<(), DefaultHostErr> {
255        let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
256        self.tx.send(WasmHostCall::HostCmd { cmd, rtn }).await?;
257        rtn_rx.await?
258    }
259
260    pub fn write_string<S: ToString>(&self, string: S) -> Result<i32, DefaultHostErr> {
261        tokio::task::block_in_place(move || {
262            Handle::current().block_on(async move {
263                let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
264                self.tx
265                    .send(WasmHostCall::WriteString {
266                        string: string.to_string(),
267                        rtn,
268                    })
269                    .await?;
270                rtn_rx.await?
271            })
272        })
273    }
274
275    pub fn consume_string(&self, buffer_id: i32) -> Result<String, DefaultHostErr> {
276        let api = self.clone();
277        tokio::task::block_in_place(move || {
278            Handle::current().block_on(async move {
279                let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
280                api.tx
281                    .send(WasmHostCall::ConsumeString { buffer_id, rtn })
282                    .await
283                    .unwrap();
284                rtn_rx.await?
285            })
286        })
287    }
288
289    pub fn write_buffer(&self, buffer: Vec<u8>) -> Result<i32, DefaultHostErr> {
290        let api = self.clone();
291        tokio::task::block_in_place(move || {
292            Handle::current().block_on(async move {
293                let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
294                api.tx
295                    .send(WasmHostCall::WriteBuffer { buffer, rtn })
296                    .await?;
297                rtn_rx.await?
298            })
299        })
300    }
301
302    pub fn consume_buffer(&self, buffer_id: i32) -> Result<Vec<u8>, DefaultHostErr> {
303        let api = self.clone();
304        tokio::task::block_in_place(move || {
305            Handle::current().block_on(async move {
306                let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
307                api.tx
308                    .send(WasmHostCall::ConsumeBuffer { buffer_id, rtn })
309                    .await?;
310                rtn_rx.await?
311            })
312        })
313    }
314
315    pub fn wave_to_host(&self, buffer_id: i32) -> Result<Option<UltraWave>, DefaultHostErr> {
316        let api = self.clone();
317        tokio::task::block_in_place(move || {
318            Handle::current().block_on(async move {
319                let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
320                let wave = self.consume_buffer(buffer_id)?;
321                let wave: UltraWave = bincode::deserialize(wave.as_slice())?;
322
323                api.tx.send(WasmHostCall::WaveToHost { wave, rtn }).await?;
324                rtn_rx.await?
325            })
326        })
327    }
328
329    pub fn serialize_wave_to_guest(&self, wave: UltraWave) -> Result<i32, DefaultHostErr> {
330        let api = self.clone();
331        tokio::task::block_in_place(move || {
332            Handle::current().block_on(async move {
333                let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
334                api.tx
335                    .send(WasmHostCall::SerializeWaveToGuest { wave, rtn })
336                    .await?;
337                rtn_rx.await?
338            })
339        })
340    }
341
342    pub fn guest_consume_wave(&self, wave: i32) -> Result<Option<UltraWave>, DefaultHostErr> {
343        let api = self.clone();
344        tokio::task::block_in_place(move || {
345            Handle::current().block_on(async move {
346                let (rtn, mut rtn_rx) = tokio::sync::oneshot::channel();
347                api.tx
348                    .send(WasmHostCall::GuestConsumeWave { wave, rtn })
349                    .await?;
350                rtn_rx.await?
351            })
352        })
353    }
354
355    pub fn transmit_to_guest(&self, wave: UltraWave) -> Result<Option<UltraWave>, DefaultHostErr> {
356        let wave_id = self.serialize_wave_to_guest(wave)?;
357        let rtn = self.guest_consume_wave(wave_id)?;
358        Ok(rtn)
359    }
360
361    pub fn host_mechtron(&self, cmd: HostCmd) {}
362}
363
364pub struct WasmHostRunner {
365    pub rx: mpsc::Receiver<WasmHostCall>,
366    pub host: WasmHost,
367}
368
369impl WasmHostRunner {
370    pub fn new(
371        details: Details,
372        store: &mut Store,
373        wasm: ArtRef<Bin>,
374        transmitter: ProtoTransmitter,
375        logger: PointLogger,
376    ) -> Result<WasmHostApi, DefaultHostErr> {
377        let module = Module::new(store, wasm.as_slice())?;
378
379        let (tx, rx) = mpsc::channel(1024);
380
381        let handle = Handle::current();
382
383        let api = WasmHostApi::new(tx);
384
385        let imports = imports! {
386
387        "env"=>{
388             "mechtron_timestamp"=>Function::new_native_with_env(module.store(),api.clone(),|env:&WasmHostApi| {
389                    chrono::Utc::now().timestamp_millis()
390            }),
391
392        "mechtron_uuid"=>Function::new_native_with_env(module.store(),api.clone(),|env:&WasmHostApi | -> i32 {
393              env.write_string(uuid::Uuid::new_v4().to_string().as_str()).unwrap()
394            }),
395
396        "mechtron_host_panic"=>Function::new_native_with_env(module.store(),api.clone(),|env:&WasmHostApi,buffer_id:i32| {
397              let panic_message = env.consume_string(buffer_id).unwrap();
398               println!("WASM PANIC: {}",panic_message);
399          }),
400
401
402        "mechtron_frame_to_host"=>Function::new_native_with_env(module.store(),api.clone(),|env:&WasmHostApi,buffer_id:i32| -> i32 {
403                    match env.wave_to_host(buffer_id).unwrap() {
404                        Some( wave ) => {
405                           let rtn = env.serialize_wave_to_guest(wave).unwrap();
406                            rtn
407                        }
408                        None => 0
409                    }
410            }),
411
412        } };
413        let instance = Some(Instance::new(&module, &imports)?);
414
415        let host = WasmHost {
416            details,
417            instance,
418            transmitter,
419            handle,
420            logger,
421        };
422
423        tokio::spawn(async move {
424            Self { host, rx }.start().await;
425        });
426
427        Ok(api)
428    }
429
430    pub async fn start(mut self) {
431        let handle = Handle::current();
432        while let Some(call) = self.rx.recv().await {
433            let host = self.host.clone();
434            handle.spawn_blocking(move || match call {
435                WasmHostCall::Init(rtn) => {
436                    rtn.send(host.init());
437                }
438                WasmHostCall::Point(rtn) => {
439                    rtn.send(host.details.stub.point.clone());
440                }
441                WasmHostCall::WriteString { string, rtn } => {
442                    rtn.send(host.write_string(string));
443                }
444                WasmHostCall::WriteBuffer { buffer, rtn } => {
445                    rtn.send(host.write_buffer(&buffer));
446                }
447                WasmHostCall::ConsumeString { buffer_id, rtn } => {
448                    rtn.send(host.consume_string(buffer_id));
449                }
450                WasmHostCall::ConsumeBuffer { buffer_id, rtn } => {
451                    rtn.send(host.consume_buffer(buffer_id));
452                }
453                WasmHostCall::DeSerializeWaveToHost { wave, rtn } => {
454                    rtn.send(host.deserialize_wave_to_host(wave));
455                }
456                WasmHostCall::SerializeWaveToGuest { wave, rtn } => {
457                    rtn.send(host.serialize_wave_to_guest(wave));
458                }
459                WasmHostCall::WaveToHost { wave, rtn } => {
460                    rtn.send(host.wave_to_host(wave));
461                }
462                WasmHostCall::HostCmd { cmd, rtn } => {
463                    rtn.send(host.create_mechtron(cmd));
464                }
465                WasmHostCall::GuestConsumeWave { wave, rtn } => {
466                    let frame = host.mechtron_frame_to_guest(wave).unwrap();
467                    if frame > 0 {
468                        rtn.send(Ok(Some(host.deserialize_wave_to_host(frame).unwrap())));
469                    } else {
470                        rtn.send(Ok(None));
471                    }
472                }
473            });
474        }
475    }
476}
477
478#[derive(Clone)]
479pub struct WasmHost {
480    details: Details,
481    instance: Option<Instance>,
482    pub transmitter: ProtoTransmitter,
483    handle: Handle,
484    logger: PointLogger,
485}
486
487impl WasmHost {
488    pub fn init(&self) -> Result<(), DefaultHostErr> {
489        let mut pass = true;
490        match self.instance.as_ref().unwrap().exports.get_memory("memory") {
491            Ok(_) => {
492                self.logger.info("verified: memory");
493            }
494            Err(_) => {
495                self.logger.info( "failed: memory. could not access wasm memory. (expecting the memory module named 'memory')");
496                pass = false
497            }
498        }
499
500        match self
501            .instance
502            .as_ref()
503            .unwrap()
504            .exports
505            .get_native_function::<i32, i32>("mechtron_guest_alloc_buffer")
506        {
507            Ok(_) => {
508                self.logger
509                    .info("verified: mechtron_guest_alloc_buffer( i32 ) -> i32");
510            }
511            Err(_) => {
512                self.logger
513                    .info("failed: mechtron_guest_alloc_buffer( i32 ) -> i32");
514                pass = false
515            }
516        }
517
518        match self
519            .instance
520            .as_ref()
521            .unwrap()
522            .exports
523            .get_native_function::<i32, WasmPtr<u8, Array>>("mechtron_guest_get_buffer_ptr")
524        {
525            Ok(_) => {
526                self.logger
527                    .info("verified: mechtron_guest_get_buffer_ptr( i32 ) -> *const u8");
528            }
529            Err(_) => {
530                self.logger
531                    .info("failed: mechtron_guest_get_buffer_ptr( i32 ) -> *const u8");
532                pass = false
533            }
534        }
535
536        match self
537            .instance
538            .as_ref()
539            .unwrap()
540            .exports
541            .get_native_function::<i32, i32>("mechtron_guest_get_buffer_len")
542        {
543            Ok(_) => {
544                self.logger
545                    .info("verified: mechtron_guest_get_buffer_len( i32 ) -> i32");
546            }
547            Err(_) => {
548                self.logger
549                    .info("failed: mechtron_guest_get_buffer_len( i32 ) -> i32");
550                pass = false
551            }
552        }
553        match self
554            .instance
555            .as_ref()
556            .unwrap()
557            .exports
558            .get_native_function::<i32, ()>("mechtron_guest_dealloc_buffer")
559        {
560            Ok(_) => {
561                self.logger
562                    .info("verified: mechtron_guest_dealloc_buffer( i32 )");
563            }
564            Err(_) => {
565                self.logger
566                    .info("failed: mechtron_guest_dealloc_buffer( i32 )");
567                pass = false
568            }
569        }
570
571        match self
572            .instance
573            .as_ref()
574            .unwrap()
575            .exports
576            .get_native_function::<(i32, i32), i32>("mechtron_guest_init")
577        {
578            Ok(func) => {
579                self.logger.info("verified: mechtron_guest_init()");
580            }
581            Err(_) => {
582                self.logger
583                    .info("failed: mechtron_guest_init() [NOT REQUIRED]");
584            }
585        }
586
587        {
588            let test = "Test write string";
589            match self.write_string(test) {
590                Ok(_) => {
591                    self.logger.info("passed: write_string()");
592                }
593                Err(e) => {
594                    self.logger
595                        .error(format!("failed: write_string() mem {:?}", e).as_str());
596                    pass = false;
597                }
598            };
599        }
600
601        match pass {
602            true => {
603                let version = self.write_string(VERSION.to_string())?;
604                let details: Vec<u8> = bincode::serialize(&self.details)?;
605                let details = self.write_buffer(&details)?;
606                let ok = self
607                    .instance
608                    .as_ref()
609                    .unwrap()
610                    .exports
611                    .get_native_function::<(i32, i32), i32>("mechtron_guest_init")
612                    .unwrap()
613                    .call(version, details)?;
614                if ok == 0 {
615                    Ok(())
616                } else {
617                    Err(format!("Mechtron init error {} ", ok).into())
618                }
619            }
620            false => Err("init failed".into()),
621        }
622    }
623
624    pub fn wave_to_host(&self, wave: UltraWave) -> Result<Option<UltraWave>, DefaultHostErr> {
625        let transmitter = self.transmitter.clone();
626        let (tx, mut rx): (
627            oneshot::Sender<Result<Option<UltraWave>, DefaultHostErr>>,
628            oneshot::Receiver<Result<Option<UltraWave>, DefaultHostErr>>,
629        ) = oneshot::channel();
630        let logger = self.logger.clone();
631        self.handle.spawn(async move {
632            if wave.is_directed() {
633                let wave = wave.to_directed().unwrap();
634
635                if let Method::Cmd(CmdMethod::Log) = wave.core().method {
636                    if let Substance::Log(log) = wave.core().body.clone() {
637                        if wave.to().is_single() {
638                            let to = wave.to().clone().to_single().unwrap();
639                            if to.point == Point::global_logger() {
640                                logger.handle(log);
641                                tx.send(Ok(None));
642                                return;
643                            }
644                        }
645                    }
646                }
647
648                match wave.directed_kind() {
649                    DirectedKind::Ping => {
650                        let wave: DirectedProto = wave.into();
651                        let pong = transmitter.ping(wave).await.unwrap();
652                        tx.send(Ok(Some(pong.to_ultra()))).unwrap_or_default();
653                    }
654                    DirectedKind::Ripple => {
655                        unimplemented!()
656                    }
657                    DirectedKind::Signal => {
658                        let wave: DirectedProto = wave.into();
659                        transmitter.signal(wave).await.unwrap_or_default();
660                        tx.send(Ok(None));
661                    }
662                }
663            } else {
664                transmitter.route(wave).await;
665                tx.send(Ok(None));
666            }
667        });
668
669        rx.recv()?
670    }
671
672    pub fn deserialize_wave_to_host(&self, wave: i32) -> Result<UltraWave, DefaultHostErr> {
673        let buffer = self.read_buffer(wave).unwrap();
674        let wave: UltraWave = bincode::deserialize(buffer.as_slice())?;
675        Ok(wave)
676    }
677
678    pub fn serialize_wave_to_guest(&self, wave: UltraWave) -> Result<i32, DefaultHostErr> {
679        let wave: Vec<u8> = bincode::serialize(&wave)?;
680        Ok(self.write_buffer(&wave)?)
681    }
682
683    pub fn route(&self, wave: UltraWave) -> Result<i32, DefaultHostErr> {
684        let wave = self.serialize_wave_to_guest(wave)?;
685
686        let reflect = self
687            .instance
688            .as_ref()
689            .unwrap()
690            .exports
691            .get_native_function::<i32, i32>("mechtron_frame_to_guest")
692            .unwrap()
693            .call(wave)?;
694
695        Ok(reflect)
696    }
697
698    pub fn write_string<S: ToString>(&self, string: S) -> Result<i32, DefaultHostErr> {
699        let string = string.to_string();
700        let string = string.as_bytes();
701        let memory = self
702            .instance
703            .as_ref()
704            .unwrap()
705            .exports
706            .get_memory("memory")?;
707        let buffer_id = self.alloc_buffer(string.len() as _)?;
708        let buffer_ptr = self.get_buffer_ptr(buffer_id)?;
709        let values = buffer_ptr.deref(memory, 0, string.len() as u32).unwrap();
710        for i in 0..string.len() {
711            values[i].set(string[i]);
712        }
713
714        Ok(buffer_id)
715    }
716
717    pub fn write_buffer(&self, bytes: &Vec<u8>) -> Result<i32, DefaultHostErr> {
718        let memory = self
719            .instance
720            .as_ref()
721            .unwrap()
722            .exports
723            .get_memory("memory")?;
724        let buffer_id = self.alloc_buffer(bytes.len() as _)?;
725        let buffer_ptr = self.get_buffer_ptr(buffer_id)?;
726        let values = buffer_ptr.deref(memory, 0, bytes.len() as u32).unwrap();
727        for i in 0..bytes.len() {
728            values[i].set(bytes[i]);
729        }
730
731        Ok(buffer_id)
732    }
733
734    fn alloc_buffer(&self, len: i32) -> Result<i32, DefaultHostErr> {
735        let buffer_id = self
736            .instance
737            .as_ref()
738            .unwrap()
739            .exports
740            .get_native_function::<i32, i32>("mechtron_guest_alloc_buffer")
741            .unwrap()
742            .call(len.clone())?;
743        Ok(buffer_id)
744    }
745
746    fn get_buffer_ptr(&self, buffer_id: i32) -> Result<WasmPtr<u8, Array>, DefaultHostErr> {
747        Ok(self
748            .instance
749            .as_ref()
750            .unwrap()
751            .exports
752            .get_native_function::<i32, WasmPtr<u8, Array>>("mechtron_guest_get_buffer_ptr")
753            .unwrap()
754            .call(buffer_id)?)
755    }
756
757    pub fn read_buffer(&self, buffer_id: i32) -> Result<Vec<u8>, DefaultHostErr> {
758        let instance = self.instance.as_ref().unwrap();
759        let ptr = instance
760            .exports
761            .get_native_function::<i32, WasmPtr<u8, Array>>("mechtron_guest_get_buffer_ptr")
762            .unwrap()
763            .call(buffer_id)?;
764        let len = instance
765            .exports
766            .get_native_function::<i32, i32>("mechtron_guest_get_buffer_len")
767            .unwrap()
768            .call(buffer_id)?;
769        let memory = instance.exports.get_memory("memory")?;
770        let values = ptr.deref(memory, 0, len as u32).unwrap();
771        let mut rtn = vec![];
772        for i in 0..values.len() {
773            rtn.push(values[i].get())
774        }
775
776        Ok(rtn)
777    }
778
779    pub fn read_string(&self, buffer_id: i32) -> Result<String, DefaultHostErr> {
780        let raw = self.read_buffer(buffer_id)?;
781        let rtn = String::from_utf8(raw)?;
782
783        Ok(rtn)
784    }
785
786    pub fn consume_string(&self, buffer_id: i32) -> Result<String, DefaultHostErr> {
787        let raw = self.read_buffer(buffer_id)?;
788        let rtn = String::from_utf8(raw)?;
789        self.mechtron_guest_dealloc_buffer(buffer_id)?;
790        Ok(rtn)
791    }
792
793    pub fn consume_buffer(&self, buffer_id: i32) -> Result<Vec<u8>, DefaultHostErr> {
794        let raw = self.read_buffer(buffer_id)?;
795        self.mechtron_guest_dealloc_buffer(buffer_id)?;
796        Ok(raw)
797    }
798
799    fn mechtron_guest_dealloc_buffer(&self, buffer_id: i32) -> Result<(), DefaultHostErr> {
800        self.instance
801            .as_ref()
802            .unwrap()
803            .exports
804            .get_native_function::<i32, ()>("mechtron_guest_dealloc_buffer")?
805            .call(buffer_id.clone())?;
806        Ok(())
807    }
808
809    fn mechtron_frame_to_guest(&self, buffer_id: i32) -> Result<i32, DefaultHostErr> {
810        let rtn = self
811            .instance
812            .as_ref()
813            .unwrap()
814            .exports
815            .get_native_function::<i32, i32>("mechtron_frame_to_guest")?
816            .call(buffer_id.clone())?;
817        Ok(rtn)
818    }
819
820    fn create_mechtron(&self, host_cmd: HostCmd) -> Result<(), DefaultHostErr> {
821        let mut wave = DirectedProto::ping();
822        wave.to(self.details.stub.point.to_surface().with_layer(Layer::Core));
823        wave.from(self.details.stub.point.to_surface().with_layer(Layer::Host));
824        wave.method(HypMethod::Host);
825        wave.body(Substance::Hyper(HyperSubstance::Host(host_cmd)));
826        let wave = self.logger.result(wave.build())?;
827        let wave = wave.to_ultra();
828        self.logger.result(self.route(wave))?;
829        Ok(())
830    }
831}
832
833#[cfg(test)]
834pub mod test {
835    use crate::HostsRunner;
836    use cosmic_space::artifact::asynch::MapFetcher;
837    use cosmic_space::point::Point;
838    use cosmic_space::particle::Details;
839    use std::fs;
840    use std::str::FromStr;
841    use std::sync::Arc;
842
843    #[tokio::test]
844    pub async fn test() {}
845}