Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display error messages in the wasm demo #31

Merged
merged 3 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ jobs:
-o ./wasm/uroborosql-fmt.js
-s ALLOW_MEMORY_GROWTH=1
-s STACK_SIZE=5MB
-s EXPORTED_FUNCTIONS=['_format_sql','_free_format_string']
-s EXPORTED_FUNCTIONS=['_format_sql','_get_result_address','_get_error_msg_address']
tanzaku marked this conversation as resolved.
Show resolved Hide resolved
-s EXPORTED_RUNTIME_METHODS=ccall

- name: Upload artifact
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export EMCC_CFLAGS="-O3
-o ./wasm/uroborosql-fmt.js
-s ALLOW_MEMORY_GROWTH=1
-s STACK_SIZE=5MB
-s EXPORTED_FUNCTIONS=['_format_sql','_free_format_string']
-s EXPORTED_FUNCTIONS=['_format_sql','_get_result_address','_get_error_msg_address']
-s EXPORTED_RUNTIME_METHODS=ccall"
# 全体のビルドを実行
cargo build --package uroborosql-fmt-wasm --target wasm32-unknown-emscripten --release
1 change: 1 addition & 0 deletions crates/uroborosql-fmt-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ repository.workspace = true
crate-type = ["cdylib"]

[dependencies]
once_cell = "1.18.0"
uroborosql-fmt = { workspace = true }
58 changes: 37 additions & 21 deletions crates/uroborosql-fmt-wasm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,34 @@
use std::ffi::{c_char, CStr, CString};
use once_cell::sync::Lazy;
use std::{
ffi::{c_char, CStr, CString},
sync::Mutex,
};

static RESULT: Lazy<Mutex<CString>> = Lazy::new(|| Mutex::new(CString::new("").unwrap()));
static ERROR_MSG: Lazy<Mutex<CString>> = Lazy::new(|| Mutex::new(CString::new("").unwrap()));

use uroborosql_fmt::{config::Config, format_sql_with_config};

/// Returns the address of the result string.
///
/// # Safety
///
/// This is unsafe because it returns a raw pointer.
#[no_mangle]
pub unsafe extern "C" fn get_result_address() -> *const c_char {
RESULT.lock().unwrap().as_c_str().as_ptr()
}

/// Returns the address of the error message string.
///
/// # Safety
///
/// This is unsafe because it returns a raw pointer.
#[no_mangle]
pub unsafe extern "C" fn get_error_msg_address() -> *const c_char {
ERROR_MSG.lock().unwrap().as_c_str().as_ptr()
}

/// Formats SQL code given as char pointer `src` by WASM (JavaScript).
///
/// # Safety
Expand All @@ -10,31 +37,20 @@ use uroborosql_fmt::{config::Config, format_sql_with_config};
/// [`CStr::from_ptr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#method.from_ptr).
#[export_name = "format_sql"]
#[no_mangle]
pub unsafe extern "C" fn format_sql_for_wasm(
src: *mut c_char,
config_json_str: *mut c_char,
) -> *mut c_char {
pub unsafe extern "C" fn format_sql_for_wasm(src: *const c_char, config_json_str: *const c_char) {
// Clear previous format result
*RESULT.lock().unwrap() = CString::new("").unwrap();
*ERROR_MSG.lock().unwrap() = CString::new("").unwrap();

let src = CStr::from_ptr(src).to_str().unwrap().to_owned();

let config_json_str = CStr::from_ptr(config_json_str).to_str().unwrap();
let config = Config::from_json_str(config_json_str).unwrap();

// TODO: error handling
let result = format_sql_with_config(&src, config).unwrap();

CString::new(result).unwrap().into_raw()
}
let result = format_sql_with_config(&src, config);

/// Free the string `s` allocated by Rust.
///
/// # Safety
///
/// This is unsafe because it uses the unsafe function
/// [`CString::from_war()`](https://doc.rust-lang.org/std/ffi/struct.CString.html#method.from_raw).
#[no_mangle]
pub unsafe extern "C" fn free_format_string(s: *mut c_char) {
if s.is_null() {
return;
match result {
Ok(result) => *RESULT.lock().unwrap() = CString::new(result).unwrap(),
Err(err) => *ERROR_MSG.lock().unwrap() = CString::new(err.to_string()).unwrap(),
}
let _ = CString::from_raw(s);
}
2 changes: 2 additions & 0 deletions wasm/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ <h2>Japanese<h2>
</div>
</div>

<div id="error_msg" style="color: red;"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.43.0/min/vs/loader.min.js"></script>
<script src="main.js"></script>
<script async src="uroborosql-fmt.js"></script>
Expand Down
2 changes: 2 additions & 0 deletions wasm/ja.html
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ <h2>English<h2>
</div>
</div>

<div id="error_msg" style="color: red;"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.43.0/min/vs/loader.min.js"></script>
<script src="main.js"></script>
<script async src="uroborosql-fmt.js"></script>
Expand Down
15 changes: 9 additions & 6 deletions wasm/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,9 @@ function initialize() {
// タイマースタート
const startTime = performance.now();

const ptr = ccall(
ccall(
"format_sql",
"number",
null,
["string", "string"],
[target, config_str]
);
Expand All @@ -233,13 +233,16 @@ function initialize() {
// 何ミリ秒かかったかを表示する
console.log("format complete: " + (endTime - startTime) + "ms");

// Module.UTF8ToString() でポインタを js の string に変換
const res = UTF8ToString(ptr);
// Rust側で確保したメモリのポインタを取得
const result_ptr = ccall("get_result_address", "number", [], []);
const error_ptr = ccall("get_error_msg_address", "number", [], []);

// Rust 側で確保したフォーマット文字列の所有権を返す
ccall("free_format_string", null, ["number"], [ptr]);
// Module.UTF8ToString() でポインタを js の string に変換
const res = UTF8ToString(result_ptr);
const err = UTF8ToString(error_ptr);

dst_editor.setValue(res);
document.getElementById("error_msg").innerText = err;

src_editor.updateOptions({ tabSize: tab_size });
dst_editor.updateOptions({ tabSize: tab_size });
Expand Down
Loading