Move net encode/decode into serde builtin instead

This commit is contained in:
Filip Tibell 2023-03-21 16:48:28 +01:00
parent 1f887cef07
commit 9e6cd4b0af
No known key found for this signature in database
12 changed files with 128 additions and 54 deletions

View file

@ -14,16 +14,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `require` has been reimplemented and overhauled in several ways:
- Builtin modules such as `fs`, `net` and others can now be imported using `require("@lune/fs")`, `require("@lune/net")` ... <br />
This is the first step towards moving away from adding each library as a global, and allowing Lune to have more built-in libraries.
- Globals such as `fs`, `net` and others can now be imported using `require("@lune/fs")`, `require("@lune/net")` ...
All new built-ins will be added using this syntax and new built-ins will no longer be available in the global scope, and current globals will stay available as globals until proper editor and LSP support is available to ensure Lune users have a good development experience. This is the first step towards moving away from adding each library as a global, and allowing Lune to have more built-in libraries in general.
- Requiring a script is now completely asynchronous and will not block lua threads other than the caller.
- Requiring a script will no longer error when using async APIs in the main body of the required script.
Behavior otherwise stays the same, and requires are still relative to file unless the special `@` prefix is used.
- Added a `serde` built-in
This built-in contains previously available functions `encode` and `decode` from the `net` global. <br />
Note that this is **_only_** available using the new `require` syntax, and is not available as a global.
### Removed
- Removed experimental `net.encode` and `net.decode` functions, since they are now available using `require("@lune/serde")`
- Removed option to preserve default Luau require behavior
## `0.5.6` - March 11th, 2023

View file

@ -162,8 +162,6 @@ declare fs: {
type NetMethod = "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH"
type NetEncodeDecodeFormat = "json" | "yaml" | "toml"
--[=[
@type NetFetchParams
@within Net
@ -369,14 +367,17 @@ declare net: {
@return The decoded lua value
]=]
jsonDecode: (encoded: string) -> any,
}
-- TODO: Somehow link this up to require("@lune/serde")
type SerdeEncodeDecodeFormat = "json" | "yaml" | "toml"
type Serde = {
--[=[
@within Net
@within Serde
@must_use
***WARNING:** Unstable API*
*This API is unstable and may change or be removed in the next major version of Lune.*
Encodes the given value using the given format.
@param format The format to use
@ -384,22 +385,18 @@ declare net: {
@param pretty If the encoded string should be human-readable, including things such as newlines and spaces. Only supported for json and toml formats, and defaults to false
@return The encoded string
]=]
encode: (format: NetEncodeDecodeFormat, value: any, pretty: boolean?) -> string,
encode: (format: SerdeEncodeDecodeFormat, value: any, pretty: boolean?) -> string,
--[=[
@within Net
@within Serde
@must_use
***WARNING:** Unstable API*
*This API is unstable and may change or be removed in the next major version of Lune.*
Decodes the given string using the given format into a lua value.
@param format The format to use
@param encoded The JSON string to decode
@param encoded The string to decode
@return The decoded lua value
]=]
decode: (format: NetEncodeDecodeFormat, encoded: string) -> any,
decode: (format: SerdeEncodeDecodeFormat, encoded: string) -> any,
}
type ProcessSpawnOptionsStdio = "inherit" | "default"

View file

@ -4,24 +4,30 @@ mod fs;
mod net;
mod process;
mod require;
mod serde;
mod stdio;
mod task;
mod top_level;
const BUILTINS_AS_GLOBALS: &[&str] = &["fs", "net", "process", "stdio", "task"];
pub fn create(lua: &'static Lua, args: Vec<String>) -> LuaResult<()> {
// Create all builtins
let builtins = vec![
("fs", fs::create(lua)?),
("net", net::create(lua)?),
("process", process::create(lua, args)?),
("serde", self::serde::create(lua)?),
("stdio", stdio::create(lua)?),
("task", task::create(lua)?),
];
// TODO: Remove this when we have proper LSP support for custom require types
// TODO: Remove this when we have proper LSP support for custom
// require types and no longer need to have builtins as globals
let lua_globals = lua.globals();
for (name, builtin) in &builtins {
lua_globals.set(*name, builtin.clone())?;
for name in BUILTINS_AS_GLOBALS {
let builtin = builtins.iter().find(|(gname, _)| gname == name).unwrap();
lua_globals.set(*name, builtin.1.clone())?;
}
// Create our importer (require) with builtins

View file

@ -25,8 +25,6 @@ pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
lua.set_named_registry_value("net.client", client)?;
// Create the global table for net
TableBuilder::new(lua)?
.with_function("encode", net_encode)?
.with_function("decode", net_decode)?
.with_function("jsonEncode", net_json_encode)?
.with_function("jsonDecode", net_json_decode)?
.with_async_function("request", net_request)?
@ -43,22 +41,6 @@ fn create_user_agent_header() -> String {
format!("{github_owner}-{github_repo}-cli")
}
fn net_encode<'a>(
lua: &'static Lua,
(format, val, pretty): (EncodeDecodeFormat, LuaValue<'a>, Option<bool>),
) -> LuaResult<LuaString<'a>> {
let config = EncodeDecodeConfig::from((format, pretty.unwrap_or_default()));
config.serialize_to_string(lua, val)
}
fn net_decode<'a>(
lua: &'static Lua,
(format, str): (EncodeDecodeFormat, LuaString<'a>),
) -> LuaResult<LuaValue<'a>> {
let config = EncodeDecodeConfig::from(format);
config.deserialize_from_string(lua, str)
}
fn net_json_encode<'a>(
lua: &'static Lua,
(val, pretty): (LuaValue<'a>, Option<bool>),

View file

@ -0,0 +1,29 @@
use mlua::prelude::*;
use crate::lua::{
net::{EncodeDecodeConfig, EncodeDecodeFormat},
table::TableBuilder,
};
pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
TableBuilder::new(lua)?
.with_function("encode", serde_encode)?
.with_function("decode", serde_decode)?
.build_readonly()
}
fn serde_encode<'a>(
lua: &'static Lua,
(format, val, pretty): (EncodeDecodeFormat, LuaValue<'a>, Option<bool>),
) -> LuaResult<LuaString<'a>> {
let config = EncodeDecodeConfig::from((format, pretty.unwrap_or_default()));
config.serialize_to_string(lua, val)
}
fn serde_decode<'a>(
lua: &'static Lua,
(format, str): (EncodeDecodeFormat, LuaString<'a>),
) -> LuaResult<LuaValue<'a>> {
let config = EncodeDecodeConfig::from(format);
config.deserialize_from_string(lua, str)
}

View file

@ -51,8 +51,6 @@ create_tests! {
net_request_methods: "net/request/methods",
net_request_query: "net/request/query",
net_request_redirect: "net/request/redirect",
net_json_decode: "net/json/decode",
net_json_encode: "net/json/encode",
net_serve_requests: "net/serve/requests",
net_serve_websockets: "net/serve/websockets",
process_args: "process/args",
@ -75,6 +73,10 @@ create_tests! {
global_pcall: "globals/pcall",
global_type: "globals/type",
global_typeof: "globals/typeof",
serde_json_decode: "serde/json/decode",
serde_json_encode: "serde/json/encode",
serde_toml_decode: "serde/toml/decode",
serde_toml_encode: "serde/toml/encode",
stdio_format: "stdio/format",
stdio_color: "stdio/color",
stdio_style: "stdio/style",

View file

@ -1,16 +1,7 @@
local payload = [[{
"Hello": "World",
"Inner": {
"Array": [
1,
2,
3
]
},
"Foo": "Bar"
}]]
local serde = require("@lune/serde") :: any
local source = require("./source")
local decoded = net.jsonDecode(payload)
local decoded = serde.decode("json", source.pretty)
assert(type(decoded) == "table", "Decoded payload was not a table")
assert(decoded.Hello == "World", "Decoded payload Hello was not World")
@ -21,5 +12,8 @@ assert(type(decoded.Inner.Array[2]) == "number", "Decoded payload Inner.Array[2]
assert(type(decoded.Inner.Array[3]) == "number", "Decoded payload Inner.Array[3] was not a number")
assert(decoded.Foo == "Bar", "Decoded payload Foo was not Bar")
local encoded = net.jsonEncode(decoded, true)
assert(encoded == payload, "JSON round-trip did not produce the same result")
local encoded = serde.encode("json", decoded, false)
assert(encoded == source.encoded, "JSON round-trip did not produce the same result")
local encodedPretty = serde.encode("json", decoded, true)
assert(encodedPretty == source.pretty, "JSON round-trip did not produce the same result (pretty)")

View file

@ -0,0 +1,18 @@
local JSON_STRING = [[{"Hello":"World","Inner":{"Array":[1,2,3]},"Foo":"Bar"}]]
local JSON_STRING_PRETTY = [[{
"Hello": "World",
"Inner": {
"Array": [
1,
2,
3
]
},
"Foo": "Bar"
}]]
return {
encoded = JSON_STRING,
pretty = JSON_STRING_PRETTY,
}

View file

@ -0,0 +1,8 @@
local serde = require("@lune/serde") :: any
local source = require("./source")
local toml = serde.decode("toml", source.encoded)
assert(toml.package.name == "my-cool-toml-package")
assert(toml.package.version == "0.1.0")
assert(toml.values.epic == true)

View file

@ -0,0 +1,5 @@
local serde = require("@lune/serde") :: any
local source = require("./source")
local str = serde.encode("toml", source.decoded)
assert(str == source.encoded)

View file

@ -0,0 +1,26 @@
local TOML_LINES = {
"[package]",
'name = "my-cool-toml-package"',
'version = "0.1.0"',
"",
"[values]",
"epic = true",
"",
}
local TOML_STRING = table.concat(TOML_LINES, "\n")
local TOML_TABLE = {
package = {
name = "my-cool-toml-package",
version = "0.1.0",
},
values = {
epic = true,
},
}
return {
encoded = TOML_STRING,
decoded = TOML_TABLE,
}