1#![deny(missing_docs)]
5
6extern crate serde;
7extern crate serde_json;
8extern crate wabt_sys;
9#[macro_use]
10extern crate serde_derive;
11
12use std::collections::HashMap;
13use std::error;
14use std::ffi::{CStr, CString, NulError};
15use std::fmt;
16use std::os::raw::{c_int, c_void};
17use std::ptr;
18use std::slice;
19
20use wabt_sys as ffi;
21
22pub mod script;
23
24#[derive(Debug, PartialEq, Eq)]
26pub struct Error(ErrorKind);
27
28impl Error {
29 pub fn kind(&self) -> &ErrorKind {
31 &self.0
32 }
33}
34
35impl fmt::Display for Error {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 write!(f, "error: {:?}", self)
39 }
40}
41
42impl error::Error for Error {
43 fn description(&self) -> &str {
44 match self.0 {
45 ErrorKind::Nul => "string contained nul-byte",
46 ErrorKind::Deserialize(_) => "failed to deserialize",
47 ErrorKind::Parse(_) => "failed to parse",
48 ErrorKind::WriteText => "failed to write text",
49 ErrorKind::NonUtf8Result => "result is not a valid utf8",
50 ErrorKind::WriteBinary => "failed to write binary",
51 ErrorKind::ResolveNames(_) => "failed to resolve names",
52 ErrorKind::Validate(_) => "failed to validate",
53 }
54 }
55}
56
57#[derive(Debug, PartialEq, Eq)]
60pub enum ErrorKind {
61 Nul,
63 Deserialize(String),
65 Parse(String),
67 WriteText,
69 NonUtf8Result,
71 WriteBinary,
73 ResolveNames(String),
75 Validate(String),
77}
78
79impl From<NulError> for Error {
80 fn from(_e: NulError) -> Error {
81 Error(ErrorKind::Nul)
82 }
83}
84
85struct Lexer {
86 _filename: CString,
87 _buffer: Vec<u8>,
88 raw_lexer: *mut ffi::WastLexer,
89}
90
91impl Lexer {
92 fn new(filename: &str, buffer: &[u8]) -> Result<Lexer, Error> {
93 let filename = CString::new(filename)?;
95 let buffer = buffer.to_owned();
96 let lexer = unsafe {
97 ffi::wabt_new_wast_buffer_lexer(
98 filename.as_ptr(),
99 buffer.as_ptr() as *const c_void,
100 buffer.len(),
101 )
102 };
103
104 Ok(Lexer {
105 _filename: filename,
106 _buffer: buffer,
107 raw_lexer: lexer,
108 })
109 }
110}
111
112impl Drop for Lexer {
113 fn drop(&mut self) {
114 unsafe {
115 ffi::wabt_destroy_wast_lexer(self.raw_lexer);
116 }
117 }
118}
119
120struct Errors {
121 raw: *mut ffi::Errors,
122}
123
124impl Errors {
125 fn new() -> Errors {
126 Errors {
127 raw: unsafe { ffi::wabt_new_errors() },
128 }
129 }
130
131 fn format_text(&self, lexer: &Lexer) -> WabtBuf {
132 unsafe {
133 let raw_buffer = ffi::wabt_format_text_errors(self.raw, lexer.raw_lexer);
134 WabtBuf { raw_buffer }
135 }
136 }
137
138 fn format_binary(&self) -> WabtBuf {
139 unsafe {
140 let raw_buffer = ffi::wabt_format_binary_errors(self.raw);
141 WabtBuf { raw_buffer }
142 }
143 }
144}
145
146impl Drop for Errors {
147 fn drop(&mut self) {
148 unsafe { ffi::wabt_destroy_errors(self.raw) }
149 }
150}
151
152pub struct Features {
154 raw: *mut ffi::Features,
155}
156
157impl Clone for Features {
158 fn clone(&self) -> Self {
159 let mut new = Features::new();
160 new.set_exceptions_enabled(self.exceptions_enabled());
161 new.set_mutable_globals_enabled(self.mutable_globals_enabled());
162 new.set_sat_float_to_int_enabled(self.sat_float_to_int_enabled());
163 new.set_sign_extension_enabled(self.sign_extension_enabled());
164 new.set_simd_enabled(self.simd_enabled());
165 new.set_threads_enabled(self.threads_enabled());
166 new.set_multi_value_enabled(self.multi_value_enabled());
167 new.set_tail_call_enabled(self.tail_call_enabled());
168 new.set_bulk_memory_enabled(self.bulk_memory_enabled());
169 new.set_reference_types_enabled(self.reference_types_enabled());
170 new.set_annotations_enabled(self.annotations_enabled());
171 new
172 }
173}
174
175impl Features {
176 #![allow(missing_docs)]
177 pub fn new() -> Features {
178 let raw = unsafe { ffi::wabt_new_features() };
179 Features { raw }
180 }
181
182 pub fn enable_all(&mut self) {
183 self.enable_exceptions();
184 self.enable_mutable_globals();
185 self.enable_sat_float_to_int();
186 self.enable_sign_extension();
187 self.enable_simd();
188 self.enable_threads();
189 self.enable_multi_value();
190 self.enable_tail_call();
191 self.enable_bulk_memory();
192 self.enable_reference_types();
193 self.enable_annotations();
194 }
195
196 pub fn exceptions_enabled(&self) -> bool {
197 unsafe { ffi::wabt_exceptions_enabled(self.raw) }
198 }
199 pub fn enable_exceptions(&mut self) {
200 self.set_exceptions_enabled(true);
201 }
202 pub fn disable_exceptions(&mut self) {
203 self.set_exceptions_enabled(false);
204 }
205 pub fn set_exceptions_enabled(&mut self, value: bool) {
206 unsafe {
207 ffi::wabt_set_exceptions_enabled(self.raw, value.into());
208 }
209 }
210
211 pub fn mutable_globals_enabled(&self) -> bool {
212 unsafe { ffi::wabt_mutable_globals_enabled(self.raw) }
213 }
214 pub fn enable_mutable_globals(&mut self) {
215 self.set_mutable_globals_enabled(true);
216 }
217 pub fn disable_mutable_globals(&mut self) {
218 self.set_mutable_globals_enabled(false);
219 }
220 pub fn set_mutable_globals_enabled(&mut self, value: bool) {
221 unsafe {
222 ffi::wabt_set_mutable_globals_enabled(self.raw, value.into());
223 }
224 }
225
226 pub fn sat_float_to_int_enabled(&self) -> bool {
227 unsafe { ffi::wabt_sat_float_to_int_enabled(self.raw) }
228 }
229 pub fn enable_sat_float_to_int(&mut self) {
230 self.set_sat_float_to_int_enabled(true);
231 }
232 pub fn disable_sat_float_to_int(&mut self) {
233 self.set_sat_float_to_int_enabled(false);
234 }
235 pub fn set_sat_float_to_int_enabled(&mut self, value: bool) {
236 unsafe {
237 ffi::wabt_set_sat_float_to_int_enabled(self.raw, value.into());
238 }
239 }
240
241 pub fn sign_extension_enabled(&self) -> bool {
242 unsafe { ffi::wabt_sign_extension_enabled(self.raw) }
243 }
244 pub fn enable_sign_extension(&mut self) {
245 self.set_sign_extension_enabled(true);
246 }
247 pub fn disable_sign_extension(&mut self) {
248 self.set_sign_extension_enabled(false);
249 }
250 pub fn set_sign_extension_enabled(&mut self, value: bool) {
251 unsafe {
252 ffi::wabt_set_sign_extension_enabled(self.raw, value.into());
253 }
254 }
255
256 pub fn simd_enabled(&self) -> bool {
257 unsafe { ffi::wabt_simd_enabled(self.raw) }
258 }
259 pub fn enable_simd(&mut self) {
260 self.set_simd_enabled(true);
261 }
262 pub fn disable_simd(&mut self) {
263 self.set_simd_enabled(false);
264 }
265 pub fn set_simd_enabled(&mut self, value: bool) {
266 unsafe {
267 ffi::wabt_set_simd_enabled(self.raw, value.into());
268 }
269 }
270
271 pub fn threads_enabled(&self) -> bool {
272 unsafe { ffi::wabt_threads_enabled(self.raw) }
273 }
274 pub fn enable_threads(&mut self) {
275 self.set_threads_enabled(true);
276 }
277 pub fn disable_threads(&mut self) {
278 self.set_threads_enabled(false);
279 }
280 pub fn set_threads_enabled(&mut self, value: bool) {
281 unsafe {
282 ffi::wabt_set_threads_enabled(self.raw, value.into());
283 }
284 }
285
286 pub fn multi_value_enabled(&self) -> bool {
287 unsafe { ffi::wabt_multi_value_enabled(self.raw) }
288 }
289 pub fn enable_multi_value(&mut self) {
290 self.set_multi_value_enabled(true);
291 }
292 pub fn disable_multi_value(&mut self) {
293 self.set_multi_value_enabled(false);
294 }
295 pub fn set_multi_value_enabled(&mut self, value: bool) {
296 unsafe {
297 ffi::wabt_set_multi_value_enabled(self.raw, value.into());
298 }
299 }
300
301 pub fn tail_call_enabled(&self) -> bool {
302 unsafe { ffi::wabt_tail_call_enabled(self.raw) }
303 }
304 pub fn enable_tail_call(&mut self) {
305 self.set_tail_call_enabled(true);
306 }
307 pub fn disable_tail_call(&mut self) {
308 self.set_tail_call_enabled(false);
309 }
310 pub fn set_tail_call_enabled(&mut self, value: bool) {
311 unsafe {
312 ffi::wabt_set_tail_call_enabled(self.raw, value.into());
313 }
314 }
315
316 pub fn bulk_memory_enabled(&self) -> bool {
317 unsafe { ffi::wabt_bulk_memory_enabled(self.raw) }
318 }
319 pub fn enable_bulk_memory(&mut self) {
320 self.set_bulk_memory_enabled(true);
321 }
322 pub fn disable_bulk_memory(&mut self) {
323 self.set_bulk_memory_enabled(false);
324 }
325 pub fn set_bulk_memory_enabled(&mut self, value: bool) {
326 unsafe {
327 ffi::wabt_set_bulk_memory_enabled(self.raw, value.into());
328 }
329 }
330
331 pub fn reference_types_enabled(&self) -> bool {
332 unsafe { ffi::wabt_reference_types_enabled(self.raw) }
333 }
334 pub fn enable_reference_types(&mut self) {
335 self.set_reference_types_enabled(true);
336 }
337 pub fn disable_reference_types(&mut self) {
338 self.set_reference_types_enabled(false);
339 }
340 pub fn set_reference_types_enabled(&mut self, value: bool) {
341 unsafe {
342 ffi::wabt_set_reference_types_enabled(self.raw, value.into());
343 }
344 }
345
346 pub fn annotations_enabled(&self) -> bool {
347 unsafe { ffi::wabt_annotations_enabled(self.raw) }
348 }
349 pub fn enable_annotations(&mut self) {
350 self.set_annotations_enabled(true);
351 }
352 pub fn disable_annotations(&mut self) {
353 self.set_annotations_enabled(false);
354 }
355 pub fn set_annotations_enabled(&mut self, value: bool) {
356 unsafe {
357 ffi::wabt_set_annotations_enabled(self.raw, value.into());
358 }
359 }
360}
361
362impl Drop for Features {
363 fn drop(&mut self) {
364 unsafe { ffi::wabt_destroy_features(self.raw) }
365 }
366}
367
368struct ParseWatResult {
369 raw_result: *mut ffi::WabtParseWatResult,
370}
371
372impl ParseWatResult {
373 fn is_ok(&self) -> bool {
374 unsafe { ffi::wabt_parse_wat_result_get_result(self.raw_result) == ffi::Result::Ok }
375 }
376
377 fn take_module(self) -> Result<*mut ffi::WasmModule, ()> {
378 if self.is_ok() {
379 unsafe { Ok(ffi::wabt_parse_wat_result_release_module(self.raw_result)) }
380 } else {
381 Err(())
382 }
383 }
384}
385
386impl Drop for ParseWatResult {
387 fn drop(&mut self) {
388 unsafe {
389 ffi::wabt_destroy_parse_wat_result(self.raw_result);
390 }
391 }
392}
393
394fn parse_wat(lexer: &Lexer, features: &Features, errors: &Errors) -> ParseWatResult {
395 let raw_result = unsafe { ffi::wabt_parse_wat(lexer.raw_lexer, features.raw, errors.raw) };
396 ParseWatResult { raw_result }
397}
398
399struct ReadBinaryResult {
400 raw_result: *mut ffi::WabtReadBinaryResult,
401}
402
403impl ReadBinaryResult {
404 fn is_ok(&self) -> bool {
405 unsafe { ffi::wabt_read_binary_result_get_result(self.raw_result) == ffi::Result::Ok }
406 }
407
408 fn take_module(self) -> Result<*mut ffi::WasmModule, ()> {
409 if self.is_ok() {
410 unsafe { Ok(ffi::wabt_read_binary_result_release_module(self.raw_result)) }
411 } else {
412 Err(())
413 }
414 }
415}
416
417impl Drop for ReadBinaryResult {
418 fn drop(&mut self) {
419 unsafe {
420 ffi::wabt_destroy_read_binary_result(self.raw_result);
421 }
422 }
423}
424
425pub struct WabtBuf {
446 raw_buffer: *mut ffi::OutputBuffer,
447}
448
449impl AsRef<[u8]> for WabtBuf {
450 fn as_ref(&self) -> &[u8] {
451 unsafe {
452 let size = ffi::wabt_output_buffer_get_size(self.raw_buffer);
453 if size == 0 {
454 return &[];
455 }
456
457 let data = ffi::wabt_output_buffer_get_data(self.raw_buffer) as *const u8;
458
459 slice::from_raw_parts(data, size)
460 }
461 }
462}
463
464impl Drop for WabtBuf {
465 fn drop(&mut self) {
466 unsafe {
467 ffi::wabt_destroy_output_buffer(self.raw_buffer);
468 }
469 }
470}
471
472struct WriteModuleResult {
473 raw_result: *mut ffi::WabtWriteModuleResult,
474}
475
476impl WriteModuleResult {
477 fn is_ok(&self) -> bool {
478 unsafe { ffi::wabt_write_module_result_get_result(self.raw_result) == ffi::Result::Ok }
479 }
480
481 fn take_wabt_buf(self) -> Result<WabtBuf, ()> {
482 if self.is_ok() {
483 let raw_buffer =
484 unsafe { ffi::wabt_write_module_result_release_output_buffer(self.raw_result) };
485 Ok(WabtBuf { raw_buffer })
486 } else {
487 Err(())
488 }
489 }
490}
491
492impl Drop for WriteModuleResult {
493 fn drop(&mut self) {
494 unsafe { ffi::wabt_destroy_write_module_result(self.raw_result) }
495 }
496}
497
498struct WriteBinaryOptions {
499 log: bool,
500 canonicalize_lebs: bool,
501 relocatable: bool,
502 write_debug_names: bool,
503}
504
505impl Default for WriteBinaryOptions {
506 fn default() -> WriteBinaryOptions {
507 WriteBinaryOptions {
508 log: false,
509 canonicalize_lebs: true,
510 relocatable: false,
511 write_debug_names: false,
512 }
513 }
514}
515
516struct WriteTextOptions {
517 fold_exprs: bool,
518 inline_export: bool,
519}
520
521impl Default for WriteTextOptions {
522 fn default() -> WriteTextOptions {
523 WriteTextOptions {
524 fold_exprs: false,
525 inline_export: false,
526 }
527 }
528}
529
530pub struct ReadBinaryOptions {
532 features: Features,
533 read_debug_names: bool,
534}
535
536impl Default for ReadBinaryOptions {
537 fn default() -> ReadBinaryOptions {
538 ReadBinaryOptions {
539 features: Features::new(),
540 read_debug_names: false,
541 }
542 }
543}
544
545struct ParseWastResult {
546 raw_result: *mut ffi::WabtParseWastResult,
547}
548
549impl ParseWastResult {
550 fn is_ok(&self) -> bool {
551 unsafe { ffi::wabt_parse_wast_result_get_result(self.raw_result) == ffi::Result::Ok }
552 }
553
554 fn take_script(self) -> Result<*mut ffi::Script, ()> {
555 if self.is_ok() {
556 unsafe { Ok(ffi::wabt_parse_wast_result_release_module(self.raw_result)) }
557 } else {
558 Err(())
559 }
560 }
561}
562
563impl Drop for ParseWastResult {
564 fn drop(&mut self) {
565 unsafe {
566 ffi::wabt_destroy_parse_wast_result(self.raw_result);
567 }
568 }
569}
570
571fn parse_wast(lexer: &Lexer, features: &Features, errors: &Errors) -> ParseWastResult {
572 let raw_result = unsafe { ffi::wabt_parse_wast(lexer.raw_lexer, features.raw, errors.raw) };
573 ParseWastResult { raw_result }
574}
575
576struct Script {
577 raw_script: *mut ffi::Script,
578 lexer: Lexer,
579 features: Features,
580}
581
582impl Script {
583 fn parse<S: AsRef<[u8]>>(
584 filename: &str,
585 source: S,
586 features: Features,
587 ) -> Result<Script, Error> {
588 let lexer = Lexer::new(filename, source.as_ref())?;
589 let errors = Errors::new();
590 match parse_wast(&lexer, &features, &errors).take_script() {
591 Ok(raw_script) => Ok(Script {
592 raw_script,
593 features,
594 lexer,
595 }),
596 Err(()) => {
597 let msg = String::from_utf8_lossy(errors.format_text(&lexer).as_ref()).to_string();
598 Err(Error(ErrorKind::Parse(msg)))
599 }
600 }
601 }
602
603 fn resolve_names(&self) -> Result<(), Error> {
604 let errors = Errors::new();
605 unsafe {
606 let result = ffi::wabt_resolve_names_script(self.raw_script, errors.raw);
607 if result == ffi::Result::Error {
608 let msg =
609 String::from_utf8_lossy(errors.format_text(&self.lexer).as_ref()).to_string();
610 return Err(Error(ErrorKind::ResolveNames(msg)));
611 }
612 }
613 Ok(())
614 }
615
616 fn validate(&self) -> Result<(), Error> {
617 let errors = Errors::new();
618 unsafe {
619 let result = ffi::wabt_validate_script(self.raw_script, self.features.raw, errors.raw);
620 if result == ffi::Result::Error {
621 let msg =
622 String::from_utf8_lossy(errors.format_text(&self.lexer).as_ref()).to_string();
623 return Err(Error(ErrorKind::Validate(msg)));
624 }
625 }
626 Ok(())
627 }
628
629 fn write_binaries(&self, source: &str) -> Result<WabtWriteScriptResult, Error> {
630 let source_cstr = CString::new(source)?;
631
632 unsafe {
633 let raw_script_result = ffi::wabt_write_binary_spec_script(
634 self.raw_script,
635 source_cstr.as_ptr(),
636 ptr::null(),
637 0,
638 1,
639 0,
640 0,
641 );
642 Ok(WabtWriteScriptResult { raw_script_result })
643 }
644 }
645}
646
647pub struct Module {
649 raw_module: *mut ffi::WasmModule,
650 lexer: Option<Lexer>,
651 features: Features,
652}
653
654impl Module {
655 pub fn parse_wat<S: AsRef<[u8]>>(
657 filename: &str,
658 source: S,
659 features: Features,
660 ) -> Result<Module, Error> {
661 let lexer = Lexer::new(filename, source.as_ref())?;
662 let errors = Errors::new();
663 match parse_wat(&lexer, &features, &errors).take_module() {
664 Ok(module) => Ok(Module {
665 raw_module: module,
666 features,
667 lexer: Some(lexer),
668 }),
669 Err(()) => {
670 let msg = String::from_utf8_lossy(errors.format_text(&lexer).as_ref()).to_string();
671 Err(Error(ErrorKind::Parse(msg)))
672 }
673 }
674 }
675
676 pub fn read_binary<S: AsRef<[u8]>>(
683 wasm: S,
684 options: &ReadBinaryOptions,
685 ) -> Result<Module, Error> {
686 let errors = Errors::new();
687 let result = {
688 let wasm = wasm.as_ref();
689 let raw_result = unsafe {
690 ffi::wabt_read_binary(
691 wasm.as_ptr(),
692 wasm.len(),
693 options.read_debug_names as c_int,
694 options.features.raw,
695 errors.raw,
696 )
697 };
698 ReadBinaryResult { raw_result }
699 };
700 match result.take_module() {
701 Ok(module) => Ok(Module {
702 raw_module: module,
703 features: options.features.clone(),
704 lexer: None,
705 }),
706 Err(()) => {
707 let msg = String::from_utf8_lossy(errors.format_binary().as_ref()).to_string();
708 Err(Error(ErrorKind::Deserialize(msg)))
709 }
710 }
711 }
712
713 fn resolve_names(&mut self) -> Result<(), Error> {
714 let errors = Errors::new();
715 unsafe {
716 let result = ffi::wabt_resolve_names_module(self.raw_module, errors.raw);
717 if result == ffi::Result::Error {
718 let buf = if let Some(ref lexer) = self.lexer {
719 errors.format_text(lexer)
720 } else {
721 errors.format_binary()
722 };
723 let msg = String::from_utf8_lossy(buf.as_ref()).to_string();
724 return Err(Error(ErrorKind::ResolveNames(msg)));
725 }
726 }
727 Ok(())
728 }
729
730 pub fn validate(&self) -> Result<(), Error> {
732 let errors = Errors::new();
733 unsafe {
734 let result = ffi::wabt_validate_module(self.raw_module, self.features.raw, errors.raw);
735 if result == ffi::Result::Error {
736 let buf = if let Some(ref lexer) = self.lexer {
737 errors.format_text(lexer)
738 } else {
739 errors.format_binary()
740 };
741 let msg = String::from_utf8_lossy(buf.as_ref()).to_string();
742 return Err(Error(ErrorKind::Validate(msg)));
743 }
744 }
745 Ok(())
746 }
747
748 fn write_binary(&self, options: &WriteBinaryOptions) -> Result<WabtBuf, Error> {
749 let result = unsafe {
750 let raw_result = ffi::wabt_write_binary_module(
751 self.raw_module,
752 options.log as c_int,
753 options.canonicalize_lebs as c_int,
754 options.relocatable as c_int,
755 options.write_debug_names as c_int,
756 );
757 WriteModuleResult { raw_result }
758 };
759 result
760 .take_wabt_buf()
761 .map_err(|_| Error(ErrorKind::WriteBinary))
762 }
763
764 fn write_text(&self, options: &WriteTextOptions) -> Result<WabtBuf, Error> {
765 let result = unsafe {
766 let raw_result = ffi::wabt_write_text_module(
767 self.raw_module,
768 options.fold_exprs as c_int,
769 options.inline_export as c_int,
770 );
771 WriteModuleResult { raw_result }
772 };
773 result
774 .take_wabt_buf()
775 .map_err(|_| Error(ErrorKind::WriteText))
776 }
777}
778
779impl Drop for Module {
780 fn drop(&mut self) {
781 unsafe {
782 ffi::wabt_destroy_module(self.raw_module);
783 }
784 }
785}
786
787pub struct Wat2Wasm {
821 validate: bool,
822 write_binary_options: WriteBinaryOptions,
823 features: Features,
824}
825
826impl Wat2Wasm {
827 pub fn new() -> Wat2Wasm {
829 Wat2Wasm {
830 write_binary_options: WriteBinaryOptions::default(),
831 validate: true,
832 features: Features::new(),
833 }
834 }
835
836 pub fn canonicalize_lebs(&mut self, canonicalize_lebs: bool) -> &mut Wat2Wasm {
841 self.write_binary_options.canonicalize_lebs = canonicalize_lebs;
842 self
843 }
844
845 pub fn relocatable(&mut self, relocatable: bool) -> &mut Wat2Wasm {
850 self.write_binary_options.relocatable = relocatable;
851 self
852 }
853
854 pub fn write_debug_names(&mut self, write_debug_names: bool) -> &mut Wat2Wasm {
858 self.write_binary_options.write_debug_names = write_debug_names;
859 self
860 }
861
862 pub fn validate(&mut self, validate: bool) -> &mut Wat2Wasm {
866 self.validate = validate;
867 self
868 }
869
870 pub fn convert<S: AsRef<[u8]>>(&self, source: S) -> Result<WabtBuf, Error> {
874 let mut module = Module::parse_wat("test.wast", source, self.features.clone())?;
875 module.resolve_names()?;
876
877 if self.validate {
878 module.validate()?;
879 }
880
881 let result = module.write_binary(&self.write_binary_options)?;
882 Ok(result)
883 }
884}
885
886pub struct Wasm2Wat {
910 read_binary_options: ReadBinaryOptions,
911 write_text_options: WriteTextOptions,
912}
913
914impl Wasm2Wat {
915 pub fn new() -> Wasm2Wat {
917 Wasm2Wat {
918 read_binary_options: ReadBinaryOptions::default(),
919 write_text_options: WriteTextOptions::default(),
920 }
921 }
922
923 pub fn features(&mut self, features: Features) -> &mut Wasm2Wat {
925 self.read_binary_options.features = features;
926 self
927 }
928
929 pub fn read_debug_names(&mut self, read_debug_names: bool) -> &mut Wasm2Wat {
933 self.read_binary_options.read_debug_names = read_debug_names;
934 self
935 }
936
937 pub fn fold_exprs(&mut self, fold_exprs: bool) -> &mut Wasm2Wat {
966 self.write_text_options.fold_exprs = fold_exprs;
967 self
968 }
969
970 pub fn inline_export(&mut self, inline_export: bool) -> &mut Wasm2Wat {
995 self.write_text_options.inline_export = inline_export;
996 self
997 }
998
999 pub fn convert<S: AsRef<[u8]>>(&self, wasm: S) -> Result<WabtBuf, Error> {
1001 let module = Module::read_binary(wasm, &self.read_binary_options)?;
1002 let output_buffer = module.write_text(&self.write_text_options)?;
1003 Ok(output_buffer)
1004 }
1005}
1006
1007pub fn wat2wasm<S: AsRef<[u8]>>(source: S) -> Result<Vec<u8>, Error> {
1039 let result_buf = Wat2Wasm::new().convert(source)?;
1040 Ok(result_buf.as_ref().to_vec())
1041}
1042
1043pub fn wat2wasm_with_features<S: AsRef<[u8]>>(
1077 source: S,
1078 features: Features,
1079) -> Result<Vec<u8>, Error> {
1080 let mut wat2wasm = Wat2Wasm::new();
1081 wat2wasm.features = features;
1082 let result_buf = wat2wasm.convert(source)?;
1083 Ok(result_buf.as_ref().to_vec())
1084}
1085
1086pub fn wasm2wat<S: AsRef<[u8]>>(wasm: S) -> Result<String, Error> {
1106 wasm2wat_with_features(wasm, Features::new())
1107}
1108
1109pub fn wasm2wat_with_features<S: AsRef<[u8]>>(
1131 wasm: S,
1132 features: Features,
1133) -> Result<String, Error> {
1134 let result_buf = Wasm2Wat::new().features(features).convert(wasm)?;
1135 let text = String::from_utf8(result_buf.as_ref().to_vec())
1136 .map_err(|_| Error(ErrorKind::NonUtf8Result))?;
1137 Ok(text)
1138}
1139
1140struct WabtWriteScriptResult {
1141 raw_script_result: *mut ffi::WabtWriteScriptResult,
1142}
1143
1144struct WabtWriteScriptResultRelease {
1145 json_output_buffer: WabtBuf,
1146 _log_output_buffer: WabtBuf,
1147 module_output_buffers: HashMap<CString, WabtBuf>,
1148}
1149
1150impl WabtWriteScriptResult {
1151 fn is_ok(&self) -> bool {
1152 unsafe {
1153 ffi::wabt_write_script_result_get_result(self.raw_script_result) == ffi::Result::Ok
1154 }
1155 }
1156
1157 fn module_count(&self) -> usize {
1158 unsafe { ffi::wabt_write_script_result_get_module_count(self.raw_script_result) }
1159 }
1160
1161 fn module_filename(&self, index: usize) -> &CStr {
1162 assert!(index < self.module_count());
1163 unsafe {
1164 let s =
1165 ffi::wabt_write_script_result_get_module_filename(self.raw_script_result, index);
1166 CStr::from_ptr(s)
1167 }
1168 }
1169
1170 fn take_all(self) -> Result<WabtWriteScriptResultRelease, ()> {
1171 if self.is_ok() {
1172 let json_output_buffer;
1173 let log_output_buffer;
1174 let mut module_output_buffers = HashMap::new();
1175 unsafe {
1176 json_output_buffer = ffi::wabt_write_script_result_release_json_output_buffer(
1177 self.raw_script_result,
1178 );
1179 log_output_buffer =
1180 ffi::wabt_write_script_result_release_log_output_buffer(self.raw_script_result);
1181 }
1182 for i in 0..self.module_count() {
1183 let module_output_buffer = unsafe {
1184 ffi::wabt_write_script_result_release_module_output_buffer(
1185 self.raw_script_result,
1186 i,
1187 )
1188 };
1189 let name = self.module_filename(i);
1190 module_output_buffers.insert(
1191 name.to_owned(),
1192 WabtBuf {
1193 raw_buffer: module_output_buffer,
1194 },
1195 );
1196 }
1197 Ok(WabtWriteScriptResultRelease {
1198 json_output_buffer: WabtBuf {
1199 raw_buffer: json_output_buffer,
1200 },
1201 _log_output_buffer: WabtBuf {
1202 raw_buffer: log_output_buffer,
1203 },
1204 module_output_buffers,
1205 })
1206 } else {
1207 Err(())
1208 }
1209 }
1210}
1211
1212impl Drop for WabtWriteScriptResult {
1213 fn drop(&mut self) {
1214 unsafe {
1215 ffi::wabt_destroy_write_script_result(self.raw_script_result);
1216 }
1217 }
1218}
1219
1220#[test]
1221fn features() {
1222 let example_wat = r#"
1223(module
1224 (func $simd (result v128)
1225 (v128.const i8x16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16)
1226 return)
1227)"#;
1228
1229 assert!(wat2wasm(example_wat).is_err());
1230
1231 let mut features = Features::new();
1232 features.enable_simd();
1233 assert!(wat2wasm_with_features(example_wat, features).is_ok());
1234}
1235
1236#[test]
1237fn module() {
1238 let binary_module = wat2wasm(
1239 r#"
1240(module
1241 (import "foo" "bar" (func (param f32)))
1242 (memory (data "hi"))
1243 (type (func (param i32) (result i32)))
1244 (start 1)
1245 (table 0 1 anyfunc)
1246 (func)
1247 (func (type 1)
1248 i32.const 42
1249 drop)
1250 (export "e" (func 1)))
1251"#,
1252 )
1253 .unwrap();
1254
1255 let mut module = Module::read_binary(&binary_module, &ReadBinaryOptions::default()).unwrap();
1256 module.resolve_names().unwrap();
1257 module.validate().unwrap();
1258}
1259
1260#[test]
1261fn test_wat2wasm() {
1262 assert_eq!(
1263 wat2wasm("(module)").unwrap(),
1264 &[0, 97, 115, 109, 1, 0, 0, 0]
1265 );
1266
1267 assert_eq!(
1268 wat2wasm(
1269 r#"
1270 (module
1271 )"#
1272 )
1273 .unwrap(),
1274 &[0, 97, 115, 109, 1, 0, 0, 0]
1275 );
1276
1277 assert_eq!(
1278 wat2wasm("(modu"),
1279 Err(Error(ErrorKind::Parse(
1280 r#"test.wast:1:2: error: unexpected token "modu", expected a module field or a module.
1281(modu
1282 ^^^^
1283"#
1284 .to_string()
1285 )))
1286 );
1287}
1288
1289#[test]
1290fn test_wasm2wat() {
1291 assert_eq!(
1292 wasm2wat(&[
1293 0, 97, 115, 109, 1, 0, 0, 0 ]),
1296 Ok("(module)\n".to_owned()),
1297 );
1298
1299 assert_eq!(
1300 wasm2wat(&[
1301 0, 97, 115, 109, ]),
1303 Err(Error(ErrorKind::Deserialize(
1304 "0000004: error: unable to read uint32_t: version\n".to_owned()
1305 ))),
1306 );
1307}
1308
1309#[test]
1310#[cfg_attr(rustfmt, rustfmt_skip)]
1311fn roundtrip() {
1312 #[cfg_attr(rustfmt, rustfmt_skip)]
1313 let factorial: &[u8] = &[
1314 0, 97, 115, 109, 1, 0, 0, 0, 1, 6, 1, 96, 1, 124, 1, 124, 3, 2, 1, 0, 7, 7,
1315 1, 3, 102, 97, 99, 0, 0, 10, 46, 1, 44, 0, 32, 0, 68, 0, 0, 0, 0, 0, 0, 240,
1316 63, 99, 4, 124, 68, 0, 0, 0, 0, 0, 0, 240, 63, 5, 32, 0, 32, 0, 68, 0, 0, 0,
1317 0, 0, 0, 240, 63, 161, 16, 0, 162, 11, 11
1318 ];
1319
1320 let text = wasm2wat(&factorial).unwrap();
1321 let binary = wat2wasm(&text).unwrap();
1322
1323 assert_eq!(&*factorial, &*binary);
1324}