use serde to serialize the things
This commit is contained in:
parent
9f9f59b33b
commit
c6709bb2e8
|
@ -18,3 +18,4 @@ serde = {version = "1.0", features = ["derive"]}
|
|||
serde_json = "1.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
struct_scalpel = "0.1.1"
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
|
|
12
pkg/ludus.js
12
pkg/ludus.js
|
@ -32,10 +32,18 @@ async function handle_messages (e) {
|
|||
outbox = []
|
||||
break
|
||||
}
|
||||
case "Error": {
|
||||
console.log("Main: ludus errored with => ", msg.data)
|
||||
running = false
|
||||
ready = false
|
||||
outbox = []
|
||||
break
|
||||
}
|
||||
// TODO: do more than report these
|
||||
case "Console": {
|
||||
console.log("Main: ludus says => ", msg.data)
|
||||
ludus_console = ludus_console + msg.data
|
||||
let new_lines = msg.data.join("\n");
|
||||
console.log("Main: ludus says => ", new_lines)
|
||||
ludus_console = ludus_console + new_lines
|
||||
break
|
||||
}
|
||||
case "Commands": {
|
||||
|
|
4
pkg/rudus.d.ts
vendored
4
pkg/rudus.d.ts
vendored
|
@ -14,8 +14,8 @@ export interface InitOutput {
|
|||
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
||||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
readonly __wbindgen_export_6: WebAssembly.Table;
|
||||
readonly closure347_externref_shim: (a: number, b: number, c: any) => void;
|
||||
readonly closure371_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
readonly closure305_externref_shim: (a: number, b: number, c: any) => void;
|
||||
readonly closure329_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
readonly __wbindgen_start: () => void;
|
||||
}
|
||||
|
||||
|
|
|
@ -240,13 +240,13 @@ function _assertNum(n) {
|
|||
function __wbg_adapter_20(arg0, arg1, arg2) {
|
||||
_assertNum(arg0);
|
||||
_assertNum(arg1);
|
||||
wasm.closure347_externref_shim(arg0, arg1, arg2);
|
||||
wasm.closure305_externref_shim(arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
function __wbg_adapter_50(arg0, arg1, arg2, arg3) {
|
||||
_assertNum(arg0);
|
||||
_assertNum(arg1);
|
||||
wasm.closure371_externref_shim(arg0, arg1, arg2, arg3);
|
||||
wasm.closure329_externref_shim(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
async function __wbg_load(module, imports) {
|
||||
|
@ -425,8 +425,8 @@ function __wbg_get_imports() {
|
|||
_assertBoolean(ret);
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper7945 = function() { return logError(function (arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 348, __wbg_adapter_20);
|
||||
imports.wbg.__wbindgen_closure_wrapper7885 = function() { return logError(function (arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 306, __wbg_adapter_20);
|
||||
return ret;
|
||||
}, arguments) };
|
||||
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
|
||||
|
|
Binary file not shown.
4
pkg/rudus_bg.wasm.d.ts
vendored
4
pkg/rudus_bg.wasm.d.ts
vendored
|
@ -9,6 +9,6 @@ export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
|||
export const __wbindgen_malloc: (a: number, b: number) => number;
|
||||
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
export const __wbindgen_export_6: WebAssembly.Table;
|
||||
export const closure347_externref_shim: (a: number, b: number, c: any) => void;
|
||||
export const closure371_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
export const closure305_externref_shim: (a: number, b: number, c: any) => void;
|
||||
export const closure329_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
export const __wbindgen_start: () => void;
|
||||
|
|
98
src/io.rs
98
src/io.rs
|
@ -18,62 +18,54 @@ extern "C" {
|
|||
fn log(s: String);
|
||||
}
|
||||
|
||||
type Commands = Value; // expect a list of values
|
||||
type Url = Value; // expect a string representing a URL
|
||||
type FinalValue = Result<Value, Panic>;
|
||||
type Url = Value; // expect a string
|
||||
type Commands = Value; // expect a list of command tuples
|
||||
|
||||
fn make_json_payload(verb: &'static str, data: String) -> String {
|
||||
format!("{{\"verb\":\"{verb}\",\"data\":{data}}}")
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
#[serde(tag = "verb", content = "data")]
|
||||
pub enum MsgOut {
|
||||
Console(Value),
|
||||
Commands(Commands),
|
||||
Fetch(Url),
|
||||
Complete(FinalValue),
|
||||
Complete(Value),
|
||||
Error(String),
|
||||
Ready
|
||||
}
|
||||
|
||||
impl std::fmt::Display for MsgOut {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}", self.to_json())
|
||||
}
|
||||
}
|
||||
|
||||
impl MsgOut {
|
||||
pub fn to_json(&self) -> String {
|
||||
match self {
|
||||
MsgOut::Complete(value) => match value {
|
||||
Ok(value) => {
|
||||
make_json_payload("Complete", serde_json::to_string(&value.show()).unwrap())
|
||||
},
|
||||
Err(_) => make_json_payload("Complete", "\"null\"".to_string())
|
||||
},
|
||||
MsgOut::Commands(commands) => {
|
||||
let commands = commands.as_list();
|
||||
let vals_json = commands.iter().map(|v| v.to_json().unwrap()).collect::<Vec<_>>().join(",");
|
||||
let vals_json = format!("[{vals_json}]");
|
||||
make_json_payload("Commands", vals_json)
|
||||
}
|
||||
MsgOut::Fetch(value) => {
|
||||
// TODO: do parsing here?
|
||||
// Right now, defer to fetch
|
||||
let url = value.to_json().unwrap();
|
||||
make_json_payload("Fetch", url)
|
||||
}
|
||||
MsgOut::Console(lines) => {
|
||||
let lines = lines.as_list();
|
||||
let json_lines = lines.iter().map(|line| line.to_json().unwrap()).collect::<Vec<_>>().join("\\n");
|
||||
let json_lines = format!("\"{json_lines}\"");
|
||||
make_json_payload("Console", json_lines)
|
||||
}
|
||||
MsgOut::Ready => {
|
||||
make_json_payload("Ready", "\"null\"".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl MsgOut {
|
||||
// pub fn to_json(&self) -> String {
|
||||
// match self {
|
||||
// MsgOut::Complete(value) => match value {
|
||||
// Ok(value) => {
|
||||
// make_json_payload("Complete", serde_json::to_string(&value.show()).unwrap())
|
||||
// },
|
||||
// Err(_) => make_json_payload("Complete", "\"null\"".to_string())
|
||||
// },
|
||||
// MsgOut::Commands(commands) => {
|
||||
// let commands = commands.as_list();
|
||||
// let vals_json = commands.iter().map(|v| v.to_json().unwrap()).collect::<Vec<_>>().join(",");
|
||||
// let vals_json = format!("[{vals_json}]");
|
||||
// make_json_payload("Commands", vals_json)
|
||||
// }
|
||||
// MsgOut::Fetch(value) => {
|
||||
// // TODO: do parsing here?
|
||||
// // Right now, defer to fetch
|
||||
// let url = value.to_json().unwrap();
|
||||
// make_json_payload("Fetch", url)
|
||||
// }
|
||||
// MsgOut::Console(lines) => {
|
||||
// let lines = lines.as_list();
|
||||
// let json_lines = lines.iter().map(|line| line.to_json().unwrap()).collect::<Vec<_>>().join("\\n");
|
||||
// let json_lines = format!("\"{json_lines}\"");
|
||||
// make_json_payload("Console", json_lines)
|
||||
// }
|
||||
// MsgOut::Ready => {
|
||||
// make_json_payload("Ready", "\"null\"".to_string())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(tag = "verb", content = "data")]
|
||||
|
@ -124,18 +116,12 @@ impl MsgIn {
|
|||
|
||||
pub async fn send_err_to_ludus_console(msg: String) {
|
||||
log(msg.clone());
|
||||
let console_msg = Value::string(msg);
|
||||
let mut console_vector = Vector::new();
|
||||
console_vector.push_back(console_msg);
|
||||
let console_list = Value::list(console_vector);
|
||||
let console = MsgOut::Console(console_list);
|
||||
let completion = MsgOut::Complete(Err(Panic::Str("")));
|
||||
do_io(vec![MsgOut::Ready, console, completion]).await;
|
||||
do_io(vec![MsgOut::Ready, MsgOut::Error(msg)]).await;
|
||||
}
|
||||
|
||||
pub async fn do_io (msgs: Vec<MsgOut>) -> Vec<MsgIn> {
|
||||
let outbox = format!("[{}]", msgs.iter().map(|msg| msg.to_json()).collect::<Vec<_>>().join(","));
|
||||
let inbox = io (outbox).await;
|
||||
let json = serde_json::to_string(&msgs).unwrap();
|
||||
let inbox = io (json).await;
|
||||
// if our request dies, make sure we return back to the event loop
|
||||
let inbox = match inbox {
|
||||
Ok(msgs) => msgs,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use rudus::value::Value;
|
||||
use std::env;
|
||||
use struct_scalpel::print_dissection_info;
|
||||
|
||||
pub fn main() {
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
print_dissection_info::<Value>();
|
||||
}
|
||||
|
|
179
src/value.rs
179
src/value.rs
|
@ -1,9 +1,10 @@
|
|||
use crate::base::BaseFn;
|
||||
use crate::chunk::Chunk;
|
||||
use imbl::{HashMap, Vector};
|
||||
use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use struct_scalpel::Dissectible;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum LFn {
|
||||
|
@ -130,6 +131,19 @@ impl std::fmt::Display for Key {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for Key {
|
||||
fn serialize<S>(&self, srlzr: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
Key::Keyword(s) => srlzr.serialize_str(s),
|
||||
Key::Interned(s) => srlzr.serialize_str(s),
|
||||
Key::String(s) => srlzr.serialize_str(s.as_str()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Key {
|
||||
pub fn to_value(&self) -> Value {
|
||||
match self {
|
||||
|
@ -149,7 +163,7 @@ impl Key {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Dissectible)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Value {
|
||||
Nothing,
|
||||
Nil,
|
||||
|
@ -247,6 +261,51 @@ impl std::fmt::Display for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serialize for Value {
|
||||
fn serialize<S>(&self, srlzr: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
use Value::*;
|
||||
match self {
|
||||
Nil => srlzr.serialize_none(),
|
||||
True => srlzr.serialize_bool(true),
|
||||
False => srlzr.serialize_bool(false),
|
||||
Number(n) => srlzr.serialize_f64(*n),
|
||||
Interned(s) => srlzr.serialize_str(s),
|
||||
Keyword(k) => srlzr.serialize_str(k),
|
||||
String(s) => srlzr.serialize_str(s.as_str()),
|
||||
Tuple(t) => {
|
||||
let mut seq = srlzr.serialize_seq(Some(t.len()))?;
|
||||
for e in t.iter() {
|
||||
seq.serialize_element(e)?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
List(l) => {
|
||||
let mut seq = srlzr.serialize_seq(Some(l.len()))?;
|
||||
for e in l.iter() {
|
||||
seq.serialize_element(e)?;
|
||||
}
|
||||
seq.end()
|
||||
}
|
||||
Dict(d) => {
|
||||
let mut map = srlzr.serialize_map(Some(d.len()))?;
|
||||
for (k, v) in d.iter() {
|
||||
map.serialize_entry(k, v)?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
Box(b) => {
|
||||
let boxed = b.borrow();
|
||||
(*boxed).serialize(srlzr)
|
||||
}
|
||||
Fn(..) | BaseFn(..) | Partial(..) => unreachable!(),
|
||||
Process | Nothing => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn show(&self) -> String {
|
||||
use Value::*;
|
||||
|
@ -292,57 +351,71 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> Option<String> {
|
||||
use Value::*;
|
||||
match self {
|
||||
True | False | Number(..) => Some(self.show()),
|
||||
String(string) => Some(string.escape_default().to_string()),
|
||||
Interned(str) => Some(str.escape_default().to_string()),
|
||||
Keyword(str) => Some(format!("\"{str}\"")),
|
||||
List(members) => {
|
||||
let mut joined = "".to_string();
|
||||
let mut members = members.iter();
|
||||
if let Some(member) = members.next() {
|
||||
joined = member.to_json()?;
|
||||
}
|
||||
for member in members {
|
||||
let json = member.to_json()?;
|
||||
joined = format!("{joined},{json}");
|
||||
}
|
||||
Some(format!("[{joined}]"))
|
||||
}
|
||||
Tuple(members) => {
|
||||
let mut joined = "".to_string();
|
||||
let mut members = members.iter();
|
||||
if let Some(member) = members.next() {
|
||||
joined = member.to_json()?;
|
||||
}
|
||||
for member in members {
|
||||
let json = member.to_json()?;
|
||||
joined = format!("{joined},{json}");
|
||||
}
|
||||
Some(format!("[{joined}]"))
|
||||
}
|
||||
Dict(members) => {
|
||||
let mut joined = "".to_string();
|
||||
let mut members = members.iter();
|
||||
if let Some((key, value)) = members.next() {
|
||||
let json = value.to_json()?;
|
||||
joined = format!("\"{key}\":{json}")
|
||||
}
|
||||
for (key, value) in members {
|
||||
let json = value.to_json()?;
|
||||
joined = format!("{joined},\"{key}\": {json}");
|
||||
}
|
||||
Some(format!("{{{joined}}}"))
|
||||
}
|
||||
not_serializable => {
|
||||
println!("Cannot convert to json:");
|
||||
dbg!(not_serializable);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
// pub fn to_js(&self) -> JsValue {
|
||||
// use Value::*;
|
||||
// match self {
|
||||
// Nil => JsValue::NULL,
|
||||
// True => JsValue::TRUE,
|
||||
// False => JsValue::FALSE,
|
||||
// Number(n) => JsValue::from_f64(*n),
|
||||
// Interned(s) => JsValue::from_str(s),
|
||||
// String(s) => JsValue::from_str(s.as_str()),
|
||||
// Keyword(k) => JsValue::from_str(k),
|
||||
// _ => todo!(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn to_json(&self) -> Option<String> {
|
||||
// use Value::*;
|
||||
// match self {
|
||||
// True | False | Number(..) => Some(self.show()),
|
||||
// String(string) => Some(string.escape_default().to_string()),
|
||||
// Interned(str) => Some(str.escape_default().to_string()),
|
||||
// Keyword(str) => Some(format!("\"{str}\"")),
|
||||
// List(members) => {
|
||||
// let mut joined = "".to_string();
|
||||
// let mut members = members.iter();
|
||||
// if let Some(member) = members.next() {
|
||||
// joined = member.to_json()?;
|
||||
// }
|
||||
// for member in members {
|
||||
// let json = member.to_json()?;
|
||||
// joined = format!("{joined},{json}");
|
||||
// }
|
||||
// Some(format!("[{joined}]"))
|
||||
// }
|
||||
// Tuple(members) => {
|
||||
// let mut joined = "".to_string();
|
||||
// let mut members = members.iter();
|
||||
// if let Some(member) = members.next() {
|
||||
// joined = member.to_json()?;
|
||||
// }
|
||||
// for member in members {
|
||||
// let json = member.to_json()?;
|
||||
// joined = format!("{joined},{json}");
|
||||
// }
|
||||
// Some(format!("[{joined}]"))
|
||||
// }
|
||||
// Dict(members) => {
|
||||
// let mut joined = "".to_string();
|
||||
// let mut members = members.iter();
|
||||
// if let Some((key, value)) = members.next() {
|
||||
// let json = value.to_json()?;
|
||||
// joined = format!("\"{key}\":{json}")
|
||||
// }
|
||||
// for (key, value) in members {
|
||||
// let json = value.to_json()?;
|
||||
// joined = format!("{joined},\"{key}\": {json}");
|
||||
// }
|
||||
// Some(format!("{{{joined}}}"))
|
||||
// }
|
||||
// not_serializable => {
|
||||
// println!("Cannot convert to json:");
|
||||
// dbg!(not_serializable);
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn stringify(&self) -> String {
|
||||
use Value::*;
|
||||
|
|
|
@ -417,7 +417,11 @@ impl World {
|
|||
// TODO: if we have a panic, actually add the panic message to the console
|
||||
let result = self.active_result().clone().unwrap();
|
||||
self.result = Some(result.clone());
|
||||
outbox.push(MsgOut::Complete(result));
|
||||
let result_msg = match result {
|
||||
Ok(value) => MsgOut::Complete(Value::string(value.show())),
|
||||
Err(_msg) => MsgOut::Error("Ludus panicked!".to_string())
|
||||
};
|
||||
outbox.push(result_msg);
|
||||
outbox
|
||||
}
|
||||
|
||||
|
@ -470,7 +474,7 @@ impl World {
|
|||
self.maybe_do_io().await;
|
||||
if self.kill_signal {
|
||||
let mut outbox = self.flush_buffers();
|
||||
outbox.push(MsgOut::Complete(Err(Panic::Str("ludus killed by user"))));
|
||||
outbox.push(MsgOut::Error("Ludus killed by user".to_string()));
|
||||
do_io(outbox).await;
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user