sql_dialect_fmt_wasm/
lib.rs1use std::{cell::RefCell, mem, ptr, slice, str};
9
10use sql_dialect_fmt_formatter::{format, Dialect, FormatOptions};
11
12thread_local! {
13 static LAST_RESULT: RefCell<Option<Box<[u8]>>> = const { RefCell::new(None) };
14}
15
16#[no_mangle]
21pub extern "C" fn sql_dialect_fmt_alloc(len: u32) -> u32 {
22 let mut buffer = Vec::<u8>::with_capacity(len as usize);
23 let ptr = buffer.as_mut_ptr();
24 mem::forget(buffer);
25 ptr as u32
26}
27
28#[no_mangle]
35pub unsafe extern "C" fn sql_dialect_fmt_dealloc(ptr: u32, capacity: u32) {
36 if ptr == 0 || capacity == 0 {
37 return;
38 }
39 drop(Vec::from_raw_parts(ptr as *mut u8, 0, capacity as usize));
40}
41
42#[no_mangle]
52pub unsafe extern "C" fn sql_dialect_fmt_format(
53 ptr: u32,
54 len: u32,
55 line_width: u32,
56 indent_width: u32,
57 uppercase_keywords: u32,
58) -> u32 {
59 sql_dialect_fmt_format_with_dialect(ptr, len, line_width, indent_width, uppercase_keywords, 0)
60}
61
62#[no_mangle]
74pub unsafe extern "C" fn sql_dialect_fmt_format_with_dialect(
75 ptr: u32,
76 len: u32,
77 line_width: u32,
78 indent_width: u32,
79 uppercase_keywords: u32,
80 dialect: u32,
81) -> u32 {
82 clear_last_result();
83
84 let bytes = slice::from_raw_parts(ptr as *const u8, len as usize);
85 let Ok(source) = str::from_utf8(bytes) else {
86 return 1;
87 };
88
89 let options = FormatOptions::default()
90 .with_line_width(line_width.max(1) as usize)
91 .with_indent_width(indent_width.clamp(1, 16) as usize)
92 .with_uppercase_keywords(uppercase_keywords != 0)
93 .with_dialect(dialect_from_u32(dialect));
94
95 store_last_result(format(source, &options).into_bytes().into_boxed_slice());
96 0
97}
98
99fn dialect_from_u32(dialect: u32) -> Dialect {
100 match dialect {
101 1 => Dialect::Databricks,
102 _ => Dialect::Snowflake,
103 }
104}
105
106#[no_mangle]
113pub unsafe extern "C" fn sql_dialect_fmt_result_ptr() -> u32 {
114 last_result_ptr() as u32
115}
116
117#[no_mangle]
124pub unsafe extern "C" fn sql_dialect_fmt_result_len() -> u32 {
125 last_result_len() as u32
126}
127
128#[no_mangle]
134pub unsafe extern "C" fn sql_dialect_fmt_clear_result() {
135 clear_last_result();
136}
137
138fn clear_last_result() {
139 LAST_RESULT.with(|last_result| {
140 last_result.borrow_mut().take();
141 });
142}
143
144fn store_last_result(result: Box<[u8]>) {
145 LAST_RESULT.with(|last_result| {
146 *last_result.borrow_mut() = Some(result);
147 });
148}
149
150fn last_result_ptr() -> *const u8 {
151 LAST_RESULT.with(|last_result| {
152 last_result
153 .borrow()
154 .as_deref()
155 .map_or(ptr::null(), |result| result.as_ptr())
156 })
157}
158
159fn last_result_len() -> usize {
160 LAST_RESULT.with(|last_result| last_result.borrow().as_deref().map_or(0, <[u8]>::len))
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 fn last_result_bytes() -> Vec<u8> {
168 let ptr = last_result_ptr();
169 let len = last_result_len();
170
171 if len == 0 {
172 return Vec::new();
173 }
174
175 assert!(!ptr.is_null());
176 unsafe { slice::from_raw_parts(ptr, len).to_vec() }
177 }
178
179 #[test]
180 fn stores_result_bytes() {
181 clear_last_result();
182
183 store_last_result(b"select 1".to_vec().into_boxed_slice());
184
185 assert_eq!(last_result_len(), 8);
186 assert_eq!(last_result_bytes(), b"select 1");
187
188 clear_last_result();
189 }
190
191 #[test]
192 fn replacing_result_exposes_only_new_bytes() {
193 clear_last_result();
194
195 store_last_result(b"old result".to_vec().into_boxed_slice());
196 store_last_result(b"new".to_vec().into_boxed_slice());
197
198 assert_eq!(last_result_len(), 3);
199 assert_eq!(last_result_bytes(), b"new");
200
201 clear_last_result();
202 }
203
204 #[test]
205 fn clear_result_removes_state_and_is_idempotent() {
206 clear_last_result();
207 store_last_result(b"temporary".to_vec().into_boxed_slice());
208
209 clear_last_result();
210 assert!(last_result_ptr().is_null());
211 assert_eq!(last_result_len(), 0);
212 assert_eq!(last_result_bytes(), b"");
213
214 clear_last_result();
215 assert!(last_result_ptr().is_null());
216 assert_eq!(last_result_len(), 0);
217 }
218}