Skip to content

Commit 0f0f78a

Browse files
committed
Enable JS test decoder and encoder
This is a first step toward https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API The encoding crate will be required to implement the following missing features: - Misc encodings - BOM handling - Substitute malformed data with a replacement character Signed-off-by: Didier Wenzek <[email protected]>
1 parent c727316 commit 0f0f78a

File tree

6 files changed

+128
-0
lines changed

6 files changed

+128
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod text_decoder;
2+
pub mod text_encoder;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use rquickjs::class::Trace;
2+
use rquickjs::Class;
3+
use rquickjs::Ctx;
4+
use rquickjs::Exception;
5+
use rquickjs::JsLifetime;
6+
use rquickjs::Result;
7+
use rquickjs::TypedArray;
8+
9+
#[derive(Clone, Trace, JsLifetime)]
10+
#[rquickjs::class(frozen)]
11+
struct TextDecoder {}
12+
13+
pub fn init(ctx: &Ctx<'_>) {
14+
let globals = ctx.globals();
15+
let _ = Class::<TextDecoder>::define(&globals);
16+
}
17+
18+
#[rquickjs::methods]
19+
impl<'js> TextDecoder {
20+
#[qjs(constructor)]
21+
fn new() -> TextDecoder {
22+
TextDecoder {}
23+
}
24+
25+
#[qjs(get)]
26+
fn encoding(&self) -> &str {
27+
"utf-8"
28+
}
29+
30+
pub fn decode(&self, ctx: Ctx<'js>, bytes: TypedArray<'js, u8>) -> Result<String> {
31+
let bytes = bytes
32+
.as_bytes()
33+
.ok_or(Exception::throw_message(&ctx, "ArrayBuffer is detached"))?;
34+
let text = std::str::from_utf8(bytes)
35+
.map_err(|err| Exception::throw_message(&ctx, &err.to_string()))?;
36+
37+
Ok(text.to_owned())
38+
}
39+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use rquickjs::class::Trace;
2+
use rquickjs::Class;
3+
use rquickjs::Ctx;
4+
use rquickjs::JsLifetime;
5+
use rquickjs::Result;
6+
use rquickjs::TypedArray;
7+
use rquickjs::Value;
8+
9+
#[derive(Clone, Trace, JsLifetime)]
10+
#[rquickjs::class(frozen)]
11+
struct TextEncoder {}
12+
13+
pub fn init(ctx: &Ctx<'_>) {
14+
let globals = ctx.globals();
15+
let _ = Class::<TextEncoder>::define(&globals);
16+
}
17+
18+
#[rquickjs::methods]
19+
impl<'js> TextEncoder {
20+
#[qjs(constructor)]
21+
fn new() -> TextEncoder {
22+
TextEncoder {}
23+
}
24+
25+
#[qjs(get)]
26+
fn encoding(&self) -> &str {
27+
"utf-8"
28+
}
29+
30+
pub fn encode(&self, ctx: Ctx<'js>, text: Value<'js>) -> Result<TypedArray<'js, u8>> {
31+
let string = match text.as_string() {
32+
None => "".to_string(),
33+
Some(js_string) => js_string.to_string()?,
34+
};
35+
TypedArray::new(ctx.clone(), string.as_bytes())
36+
}
37+
}

crates/extensions/tedge_flows/src/js_runtime.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::js_lib;
12
use crate::js_script::JsScript;
23
use crate::js_script::JsonValue;
34
use crate::LoadError;
@@ -175,6 +176,8 @@ impl JsWorker {
175176
async fn run(mut self) {
176177
rquickjs::async_with!(self.context => |ctx| {
177178
console::init(&ctx);
179+
js_lib::text_decoder::init(&ctx);
180+
js_lib::text_encoder::init(&ctx);
178181
let mut modules = JsModules::new();
179182
while let Some(request) = self.requests.recv().await {
180183
match request {

crates/extensions/tedge_flows/src/js_script.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,52 @@ export function onMessage(message) {
514514
.contains("Maximum call stack size exceeded"));
515515
}
516516

517+
#[tokio::test]
518+
async fn using_text_decoder() {
519+
let js = r#"
520+
export async function onMessage(message, config) {
521+
const utf8decoder = new TextDecoder();
522+
const encodedText = new Uint8Array([240, 159, 146, 150]);
523+
return [{topic:"decoded", payload: utf8decoder.decode(encodedText)}];
524+
}
525+
"#;
526+
let (runtime, script) = runtime_with(js).await;
527+
528+
let input = Message::new("encoded", "content");
529+
let mut output = Message::new("decoded", "💖");
530+
output.timestamp = None;
531+
assert_eq!(
532+
script
533+
.on_message(&runtime, &DateTime::now(), &input)
534+
.await
535+
.unwrap(),
536+
vec![output]
537+
);
538+
}
539+
540+
#[tokio::test]
541+
async fn using_text_encoder() {
542+
let js = r#"
543+
export async function onMessage(message, config) {
544+
const utf8encoder = new TextEncoder();
545+
const encodedText = utf8encoder.encode(message.payload);
546+
return [{topic:"encoded", payload: `[${encodedText}]`}];
547+
}
548+
"#;
549+
let (runtime, script) = runtime_with(js).await;
550+
551+
let input = Message::new("decoded", "💖");
552+
let mut output = Message::new("encoded", "[240,159,146,150]");
553+
output.timestamp = None;
554+
assert_eq!(
555+
script
556+
.on_message(&runtime, &DateTime::now(), &input)
557+
.await
558+
.unwrap(),
559+
vec![output]
560+
);
561+
}
562+
517563
async fn runtime_with(js: &str) -> (JsRuntime, JsScript) {
518564
let mut runtime = JsRuntime::try_new().await.unwrap();
519565
let mut script = JsScript::new("toml".into(), 1, "js".into());

crates/extensions/tedge_flows/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod actor;
22
mod config;
33
pub mod flow;
4+
mod js_lib;
45
mod js_runtime;
56
mod js_script;
67
mod runtime;

0 commit comments

Comments
 (0)