- Sponsor
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Add support for static enum methods via TS namespaces #4258
Draft
RunDevelopment
wants to merge
10
commits into
rustwasm:main
Choose a base branch
from
RunDevelopment:enum-static-method-namespace
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,020
−56
Draft
Changes from 1 commit
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
631c5a7
Add support for static enum methods via TS namespaces
RunDevelopment afd00bb
Terser code gen
RunDevelopment 93e090e
Merge branch 'main' into enum-static-method-namespace
RunDevelopment 04cef11
Updated enum.js
RunDevelopment b6ff56f
Disallow enum constructors and ignore enum methods
RunDevelopment 9fbc52d
Merge branch 'main' into enum-static-method-namespace
RunDevelopment 6b4a16f
Test all export modes
RunDevelopment b0c06a5
Remove IIFE for ESM output
RunDevelopment 9e79902
Merge branch 'main' into enum-static-method-namespace
RunDevelopment 7771e64
Replace errors with warnings
RunDevelopment File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next
Next commit
Add support for static enum methods via TS namespaces
commit 631c5a70d6715043b2f7e9fbf2d4008a1237ba8a
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,6 +61,8 @@ pub struct Context<'a> { | |
|
||
exported_classes: Option<BTreeMap<String, ExportedClass>>, | ||
|
||
exported_namespaces: Option<BTreeMap<String, ExportedNamespace>>, | ||
|
||
/// A map of the name of npm dependencies we've loaded so far to the path | ||
/// they're defined in as well as their version specification. | ||
pub npm_dependencies: HashMap<String, (PathBuf, String)>, | ||
|
@@ -120,6 +122,35 @@ struct FieldAccessor { | |
is_optional: bool, | ||
} | ||
|
||
struct ExportedNamespace { | ||
name: String, | ||
contents: String, | ||
/// The TypeScript for the namespace's methods. | ||
typescript: String, | ||
/// Whether TypeScript for this namespace should be emitted (i.e., `skip_typescript` wasn't specified). | ||
generate_typescript: bool, | ||
} | ||
|
||
enum ClassOrNamespace<'a> { | ||
Class(&'a mut ExportedClass), | ||
Namespace(&'a mut ExportedNamespace), | ||
} | ||
|
||
/// Different JS constructs that can be exported. | ||
enum ExportJs<'a> { | ||
/// A class of the form `class Name {...}`. | ||
Class(&'a str), | ||
/// An anonymous function expression of the form `function(...) {...}`. | ||
/// | ||
/// Note that the function name is not included in the string. | ||
Function(&'a str), | ||
/// An arbitrary JS expression. | ||
Expression(&'a str), | ||
/// A namespace as a function expression for initiating the namespace. The | ||
/// function expression is of the form `(function(Name) {...})`. | ||
Namespace(&'a str), | ||
} | ||
|
||
const INITIAL_HEAP_VALUES: &[&str] = &["undefined", "null", "true", "false"]; | ||
// Must be kept in sync with `src/lib.rs` of the `wasm-bindgen` crate | ||
const INITIAL_HEAP_OFFSET: usize = 128; | ||
|
@@ -143,6 +174,7 @@ impl<'a> Context<'a> { | |
typescript_refs: Default::default(), | ||
used_string_enums: Default::default(), | ||
exported_classes: Some(Default::default()), | ||
exported_namespaces: Some(Default::default()), | ||
config, | ||
threads_enabled: config.threads.is_enabled(module), | ||
module, | ||
|
@@ -163,38 +195,72 @@ impl<'a> Context<'a> { | |
fn export( | ||
&mut self, | ||
export_name: &str, | ||
contents: &str, | ||
export: ExportJs, | ||
comments: Option<&str>, | ||
) -> Result<(), Error> { | ||
let definition_name = self.generate_identifier(export_name); | ||
if contents.starts_with("class") && definition_name != export_name { | ||
// The definition is intended to allow for exports to be renamed to | ||
// avoid conflicts. Since namespaces intentionally have the same name as | ||
// other exports, we must not rename them. | ||
let definition_name = if matches!(export, ExportJs::Namespace(_)) { | ||
export_name.to_owned() | ||
} else { | ||
self.generate_identifier(export_name) | ||
}; | ||
|
||
if matches!(export, ExportJs::Class(_)) && definition_name != export_name { | ||
bail!("cannot shadow already defined class `{}`", export_name); | ||
} | ||
|
||
let contents = contents.trim(); | ||
// write out comments | ||
if let Some(c) = comments { | ||
self.globals.push_str(c); | ||
} | ||
|
||
fn namespace_init_arg(name: &str) -> String { | ||
format!("{name} || ({name} = {{}})", name = name) | ||
} | ||
|
||
let global = match self.config.mode { | ||
OutputMode::Node { module: false } => { | ||
if contents.starts_with("class") { | ||
format!("{}\nmodule.exports.{1} = {1};\n", contents, export_name) | ||
} else { | ||
format!("module.exports.{} = {};\n", export_name, contents) | ||
OutputMode::Node { module: false } => match export { | ||
ExportJs::Class(class) => { | ||
format!("{}\nmodule.exports.{1} = {1};\n", class, export_name) | ||
} | ||
} | ||
OutputMode::NoModules { .. } => { | ||
if contents.starts_with("class") { | ||
format!("{}\n__exports.{1} = {1};\n", contents, export_name) | ||
} else { | ||
format!("__exports.{} = {};\n", export_name, contents) | ||
ExportJs::Function(expr) | ExportJs::Expression(expr) => { | ||
format!("module.exports.{} = {};\n", export_name, expr) | ||
} | ||
} | ||
ExportJs::Namespace(namespace) => { | ||
format!( | ||
"{}({});\n", | ||
namespace, | ||
namespace_init_arg(&format!("module.exports.{}", export_name)) | ||
) | ||
} | ||
}, | ||
OutputMode::NoModules { .. } => match export { | ||
ExportJs::Class(class) => { | ||
format!("{}\n__exports.{1} = {1};\n", class, export_name) | ||
} | ||
ExportJs::Function(expr) | ExportJs::Expression(expr) => { | ||
format!("__exports.{} = {};\n", export_name, expr) | ||
} | ||
ExportJs::Namespace(namespace) => { | ||
format!( | ||
"{}({});\n", | ||
namespace, | ||
namespace_init_arg(&format!("__exports.{}", export_name)) | ||
) | ||
} | ||
}, | ||
OutputMode::Bundler { .. } | ||
| OutputMode::Node { module: true } | ||
| OutputMode::Web | ||
| OutputMode::Deno => { | ||
if let Some(body) = contents.strip_prefix("function") { | ||
| OutputMode::Deno => match export { | ||
ExportJs::Class(class) => { | ||
assert_eq!(export_name, definition_name); | ||
format!("export {}\n", class) | ||
} | ||
ExportJs::Function(function) => { | ||
let body = function.strip_prefix("function").unwrap(); | ||
if export_name == definition_name { | ||
format!("export function {}{}\n", export_name, body) | ||
} else { | ||
|
@@ -203,14 +269,25 @@ impl<'a> Context<'a> { | |
definition_name, body, definition_name, export_name, | ||
) | ||
} | ||
} else if contents.starts_with("class") { | ||
} | ||
ExportJs::Expression(expr) => { | ||
assert_eq!(export_name, definition_name); | ||
format!("export {}\n", contents) | ||
} else { | ||
format!("export const {} = {};\n", export_name, expr) | ||
} | ||
ExportJs::Namespace(namespace) => { | ||
assert_eq!(export_name, definition_name); | ||
format!("export const {} = {};\n", export_name, contents) | ||
|
||
// In some cases (e.g. string enums), a namespace may be | ||
// exported without an existing object of the same name. | ||
// In that case, we need to create the object before | ||
// initializing the namespace. | ||
let mut definition = String::new(); | ||
if !self.defined_identifiers.contains_key(export_name) { | ||
definition = format!("export const {} = {{}};\n", export_name) | ||
} | ||
format!("{}{}({});\n", definition, namespace, export_name) | ||
} | ||
} | ||
}, | ||
}; | ||
self.global(&global); | ||
Ok(()) | ||
|
@@ -225,6 +302,9 @@ impl<'a> Context<'a> { | |
// `__wrap` and such. | ||
self.write_classes()?; | ||
|
||
// Write out generated JS for namespaces. | ||
self.write_namespaces()?; | ||
|
||
// Initialization is just flat out tricky and not something we | ||
// understand super well. To try to handle various issues that have come | ||
// up we always remove the `start` function if one is present. The JS | ||
|
@@ -1005,6 +1085,22 @@ __wbg_set_wasm(wasm);" | |
Ok((js, ts)) | ||
} | ||
|
||
fn require_class_or_namespace(&mut self, name: &str) -> ClassOrNamespace { | ||
if self.aux.enums.contains_key(name) || self.aux.string_enums.contains_key(name) { | ||
ClassOrNamespace::Namespace(self.require_namespace(name)) | ||
} else { | ||
ClassOrNamespace::Class(self.require_class(name)) | ||
} | ||
} | ||
|
||
fn require_class(&mut self, name: &str) -> &'_ mut ExportedClass { | ||
self.exported_classes | ||
.as_mut() | ||
.expect("classes already written") | ||
.entry(name.to_string()) | ||
.or_default() | ||
} | ||
|
||
fn write_classes(&mut self) -> Result<(), Error> { | ||
for (class, exports) in self.exported_classes.take().unwrap() { | ||
self.write_class(&class, &exports)?; | ||
|
@@ -1152,10 +1248,10 @@ __wbg_set_wasm(wasm);" | |
|
||
self.write_class_field_types(class, &mut ts_dst); | ||
|
||
dst.push_str("}\n"); | ||
dst.push('}'); | ||
ts_dst.push_str("}\n"); | ||
|
||
self.export(name, &dst, Some(&class.comments))?; | ||
self.export(name, ExportJs::Class(&dst), Some(&class.comments))?; | ||
|
||
if class.generate_typescript { | ||
self.typescript.push_str(&class.comments); | ||
|
@@ -1283,6 +1379,57 @@ __wbg_set_wasm(wasm);" | |
} | ||
} | ||
|
||
fn require_namespace(&mut self, name: &str) -> &'_ mut ExportedNamespace { | ||
self.exported_namespaces | ||
.as_mut() | ||
.expect("namespaces already written") | ||
.entry(name.to_string()) | ||
.or_insert_with(|| { | ||
let _enum = self.aux.enums.get(name); | ||
let string_enum = self.aux.string_enums.get(name); | ||
|
||
let generate_typescript = _enum.map_or(true, |e| e.generate_typescript) | ||
&& string_enum.map_or(true, |e| e.generate_typescript); | ||
|
||
ExportedNamespace { | ||
name: name.to_string(), | ||
contents: String::new(), | ||
typescript: String::new(), | ||
generate_typescript, | ||
} | ||
}) | ||
} | ||
|
||
fn write_namespaces(&mut self) -> Result<(), Error> { | ||
for (class, namespace) in self.exported_namespaces.take().unwrap() { | ||
self.write_namespace(&class, &namespace)?; | ||
} | ||
Ok(()) | ||
} | ||
|
||
fn write_namespace(&mut self, name: &str, namespace: &ExportedNamespace) -> Result<(), Error> { | ||
if namespace.contents.is_empty() { | ||
// don't emit empty namespaces | ||
return Ok(()); | ||
} | ||
|
||
let dst = format!( | ||
"(function({name}) {{\n{contents}}})", | ||
contents = namespace.contents | ||
); | ||
self.export(name, ExportJs::Namespace(&dst), None)?; | ||
|
||
if namespace.generate_typescript { | ||
let ts_dst = format!( | ||
"export namespace {name} {{\n{ts}}}\n", | ||
ts = namespace.typescript | ||
); | ||
self.typescript.push_str(&ts_dst); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn expose_drop_ref(&mut self) { | ||
if !self.should_write_global("drop_ref") { | ||
return; | ||
|
@@ -2461,11 +2608,11 @@ __wbg_set_wasm(wasm);" | |
} | ||
|
||
fn require_class_wrap(&mut self, name: &str) { | ||
require_class(&mut self.exported_classes, name).wrap_needed = true; | ||
self.require_class(name).wrap_needed = true; | ||
} | ||
|
||
fn require_class_unwrap(&mut self, name: &str) { | ||
require_class(&mut self.exported_classes, name).unwrap_needed = true; | ||
self.require_class(name).unwrap_needed = true; | ||
} | ||
|
||
fn add_module_import(&mut self, module: String, name: &str, actual: &str) { | ||
|
@@ -2831,11 +2978,15 @@ __wbg_set_wasm(wasm);" | |
self.typescript.push_str(";\n"); | ||
} | ||
|
||
self.export(name, &format!("function{}", code), Some(&js_docs))?; | ||
self.export( | ||
name, | ||
ExportJs::Function(&format!("function{}", code)), | ||
Some(&js_docs), | ||
)?; | ||
self.globals.push('\n'); | ||
} | ||
AuxExportKind::Constructor(class) => { | ||
let exported = require_class(&mut self.exported_classes, class); | ||
let exported = self.require_class(class); | ||
|
||
if exported.has_constructor { | ||
bail!("found duplicate constructor for class `{}`", class); | ||
|
@@ -2850,7 +3001,7 @@ __wbg_set_wasm(wasm);" | |
receiver, | ||
kind, | ||
} => { | ||
let exported = require_class(&mut self.exported_classes, class); | ||
let mut exported = self.require_class_or_namespace(class); | ||
|
||
let mut prefix = String::new(); | ||
if receiver.is_static() { | ||
|
@@ -2859,6 +3010,17 @@ __wbg_set_wasm(wasm);" | |
let ts = match kind { | ||
AuxExportedMethodKind::Method => ts_sig, | ||
AuxExportedMethodKind::Getter => { | ||
let class = match exported { | ||
ClassOrNamespace::Class(ref mut class) => class, | ||
ClassOrNamespace::Namespace(_) => { | ||
bail!( | ||
"the getter `{}` is not supported on `{}`. Enums only support static methods on them.", | ||
name, | ||
class | ||
); | ||
} | ||
}; | ||
|
||
prefix += "get "; | ||
// For getters and setters, we generate a separate TypeScript definition. | ||
if export.generate_typescript { | ||
|
@@ -2873,14 +3035,25 @@ __wbg_set_wasm(wasm);" | |
is_optional: false, | ||
}; | ||
|
||
exported.push_accessor_ts(location, accessor, false); | ||
class.push_accessor_ts(location, accessor, false); | ||
} | ||
// Add the getter to the list of readable fields (used to generate `toJSON`) | ||
exported.readable_properties.push(name.clone()); | ||
class.readable_properties.push(name.clone()); | ||
// Ignore the raw signature. | ||
None | ||
} | ||
AuxExportedMethodKind::Setter => { | ||
let class = match exported { | ||
ClassOrNamespace::Class(ref mut class) => class, | ||
ClassOrNamespace::Namespace(_) => { | ||
bail!( | ||
"the setter `{}` is not supported on `{}`. Enums only support static methods on them.", | ||
name, | ||
class | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. |
||
} | ||
}; | ||
|
||
prefix += "set "; | ||
if export.generate_typescript { | ||
let location = FieldLocation { | ||
|
@@ -2893,13 +3066,27 @@ __wbg_set_wasm(wasm);" | |
is_optional: might_be_optional_field, | ||
}; | ||
|
||
exported.push_accessor_ts(location, accessor, true); | ||
class.push_accessor_ts(location, accessor, true); | ||
} | ||
None | ||
} | ||
}; | ||
|
||
exported.push(name, &prefix, &js_docs, &code, &ts_docs, ts); | ||
match exported { | ||
ClassOrNamespace::Class(class) => { | ||
class.push(name, &prefix, &js_docs, &code, &ts_docs, ts); | ||
} | ||
ClassOrNamespace::Namespace(ns) => { | ||
if !receiver.is_static() { | ||
bail!( | ||
"non-static method `{}` on namespace `{}`", | ||
name, | ||
ns.name | ||
); | ||
} | ||
ns.push(name, &js_docs, &code, &ts_docs, ts); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -3957,7 +4144,7 @@ __wbg_set_wasm(wasm);" | |
|
||
self.export( | ||
&enum_.name, | ||
&format!("Object.freeze({{\n{}}})", variants), | ||
ExportJs::Expression(&format!("{{\n{}}}", variants)), | ||
Some(&docs), | ||
)?; | ||
|
||
|
@@ -4008,7 +4195,7 @@ __wbg_set_wasm(wasm);" | |
} | ||
|
||
fn generate_struct(&mut self, struct_: &AuxStruct) -> Result<(), Error> { | ||
let class = require_class(&mut self.exported_classes, &struct_.name); | ||
let class = self.require_class(&struct_.name); | ||
class.comments = format_doc_comments(&struct_.comments, None); | ||
class.is_inspectable = struct_.is_inspectable; | ||
class.generate_typescript = struct_.generate_typescript; | ||
|
@@ -4464,17 +4651,6 @@ fn format_doc_comments(comments: &str, js_doc_comments: Option<String>) -> Strin | |
} | ||
} | ||
|
||
fn require_class<'a>( | ||
exported_classes: &'a mut Option<BTreeMap<String, ExportedClass>>, | ||
name: &str, | ||
) -> &'a mut ExportedClass { | ||
exported_classes | ||
.as_mut() | ||
.expect("classes already written") | ||
.entry(name.to_string()) | ||
.or_default() | ||
} | ||
|
||
/// Returns whether a character has the Unicode `ID_Start` properly. | ||
/// | ||
/// This is only ever-so-slightly different from `XID_Start` in a few edge | ||
|
@@ -4588,6 +4764,45 @@ impl ExportedClass { | |
} | ||
} | ||
|
||
impl ExportedNamespace { | ||
fn push( | ||
&mut self, | ||
function_name: &str, | ||
js_docs: &str, | ||
js: &str, | ||
ts_docs: &str, | ||
ts: Option<&str>, | ||
) { | ||
self.contents.push_str(js_docs); | ||
self.contents.push_str("function "); | ||
self.contents.push_str(function_name); | ||
self.contents.push_str(js); | ||
self.contents.push('\n'); | ||
self.contents.push_str(&self.name); | ||
self.contents.push('.'); | ||
self.contents.push_str(function_name); | ||
self.contents.push_str(" = "); | ||
self.contents.push_str(function_name); | ||
self.contents.push_str(";\n"); | ||
|
||
if let Some(ts) = ts { | ||
if !ts_docs.is_empty() { | ||
for line in ts_docs.lines() { | ||
self.typescript.push_str(" "); | ||
self.typescript.push_str(line); | ||
self.typescript.push('\n'); | ||
} | ||
} | ||
self.typescript.push_str(" export function "); | ||
self.typescript.push_str(function_name); | ||
self.typescript.push_str(ts); | ||
self.typescript.push_str(";\n"); | ||
} | ||
} | ||
} | ||
|
||
impl ClassOrNamespace<'_> {} | ||
|
||
struct MemView { | ||
name: Cow<'static, str>, | ||
num: usize, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
/** | ||
* C-style enum | ||
*/ | ||
export enum ImageFormat { | ||
PNG = 0, | ||
JPEG = 1, | ||
GIF = 2, | ||
} | ||
/** | ||
* String enum | ||
*/ | ||
type Status = "success" | "failure"; | ||
export namespace ImageFormat { | ||
export function from_str(s: string): ImageFormat; | ||
} | ||
export namespace Status { | ||
/** | ||
* I have documentation. | ||
*/ | ||
export function from_bool(success: boolean): Status; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
let wasm; | ||
export function __wbg_set_wasm(val) { | ||
wasm = val; | ||
} | ||
|
||
|
||
const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder; | ||
|
||
let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true }); | ||
|
||
cachedTextDecoder.decode(); | ||
|
||
let cachedUint8ArrayMemory0 = null; | ||
|
||
function getUint8ArrayMemory0() { | ||
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { | ||
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); | ||
} | ||
return cachedUint8ArrayMemory0; | ||
} | ||
|
||
function getStringFromWasm0(ptr, len) { | ||
ptr = ptr >>> 0; | ||
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); | ||
} | ||
|
||
let WASM_VECTOR_LEN = 0; | ||
|
||
const lTextEncoder = typeof TextEncoder === 'undefined' ? (0, module.require)('util').TextEncoder : TextEncoder; | ||
|
||
let cachedTextEncoder = new lTextEncoder('utf-8'); | ||
|
||
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' | ||
? function (arg, view) { | ||
return cachedTextEncoder.encodeInto(arg, view); | ||
} | ||
: function (arg, view) { | ||
const buf = cachedTextEncoder.encode(arg); | ||
view.set(buf); | ||
return { | ||
read: arg.length, | ||
written: buf.length | ||
}; | ||
}); | ||
|
||
function passStringToWasm0(arg, malloc, realloc) { | ||
|
||
if (realloc === undefined) { | ||
const buf = cachedTextEncoder.encode(arg); | ||
const ptr = malloc(buf.length, 1) >>> 0; | ||
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); | ||
WASM_VECTOR_LEN = buf.length; | ||
return ptr; | ||
} | ||
|
||
let len = arg.length; | ||
let ptr = malloc(len, 1) >>> 0; | ||
|
||
const mem = getUint8ArrayMemory0(); | ||
|
||
let offset = 0; | ||
|
||
for (; offset < len; offset++) { | ||
const code = arg.charCodeAt(offset); | ||
if (code > 0x7F) break; | ||
mem[ptr + offset] = code; | ||
} | ||
|
||
if (offset !== len) { | ||
if (offset !== 0) { | ||
arg = arg.slice(offset); | ||
} | ||
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; | ||
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); | ||
const ret = encodeString(arg, view); | ||
|
||
offset += ret.written; | ||
ptr = realloc(ptr, len, offset, 1) >>> 0; | ||
} | ||
|
||
WASM_VECTOR_LEN = offset; | ||
return ptr; | ||
} | ||
/** | ||
* C-style enum | ||
* @enum {0 | 1 | 2} | ||
*/ | ||
export const ImageFormat = { | ||
PNG: 0, "0": "PNG", | ||
JPEG: 1, "1": "JPEG", | ||
GIF: 2, "2": "GIF", | ||
}; | ||
daxpedda marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const __wbindgen_enum_Status = ["success", "failure"]; | ||
|
||
(function(ImageFormat) { | ||
/** | ||
* @param {string} s | ||
* @returns {ImageFormat} | ||
*/ | ||
function from_str(s) { | ||
const ptr0 = passStringToWasm0(s, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); | ||
const len0 = WASM_VECTOR_LEN; | ||
const ret = wasm.imageformat_from_str(ptr0, len0); | ||
return ret; | ||
} | ||
ImageFormat.from_str = from_str; | ||
})(ImageFormat); | ||
|
||
export const Status = {}; | ||
daxpedda marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(function(Status) { | ||
/** | ||
* I have documentation. | ||
* @param {boolean} success | ||
* @returns {Status} | ||
*/ | ||
function from_bool(success) { | ||
const ret = wasm.status_from_bool(success); | ||
return __wbindgen_enum_Status[ret]; | ||
} | ||
Status.from_bool = from_bool; | ||
})(Status); | ||
|
||
export function __wbindgen_throw(arg0, arg1) { | ||
throw new Error(getStringFromWasm0(arg0, arg1)); | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
use wasm_bindgen::prelude::*; | ||
|
||
/// C-style enum | ||
#[wasm_bindgen] | ||
#[derive(Copy, Clone)] | ||
pub enum ImageFormat { | ||
PNG, | ||
JPEG, | ||
GIF, | ||
} | ||
|
||
#[wasm_bindgen] | ||
impl ImageFormat { | ||
pub fn from_str(s: &str) -> ImageFormat { | ||
match s { | ||
"PNG" => ImageFormat::PNG, | ||
"JPEG" => ImageFormat::JPEG, | ||
"GIF" => ImageFormat::GIF, | ||
_ => panic!("unknown image format: {}", s), | ||
} | ||
} | ||
} | ||
|
||
/// String enum | ||
#[wasm_bindgen] | ||
#[derive(Copy, Clone)] | ||
pub enum Status { | ||
Success = "success", | ||
Failure = "failure", | ||
} | ||
|
||
#[wasm_bindgen] | ||
impl Status { | ||
/// I have documentation. | ||
pub fn from_bool(success: bool) -> Status { | ||
if success { | ||
Status::Success | ||
} else { | ||
Status::Failure | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
(module $reference_test.wasm | ||
(type (;0;) (func (param i32) (result i32))) | ||
(type (;1;) (func (param i32 i32) (result i32))) | ||
(type (;2;) (func (param i32 i32 i32 i32) (result i32))) | ||
(func $__wbindgen_realloc (;0;) (type 2) (param i32 i32 i32 i32) (result i32)) | ||
(func $__wbindgen_malloc (;1;) (type 1) (param i32 i32) (result i32)) | ||
(func $imageformat_from_str (;2;) (type 1) (param i32 i32) (result i32)) | ||
(func $status_from_bool (;3;) (type 0) (param i32) (result i32)) | ||
(memory (;0;) 17) | ||
(export "memory" (memory 0)) | ||
(export "imageformat_from_str" (func $imageformat_from_str)) | ||
(export "status_from_bool" (func $status_from_bool)) | ||
(export "__wbindgen_malloc" (func $__wbindgen_malloc)) | ||
(export "__wbindgen_realloc" (func $__wbindgen_realloc)) | ||
(@custom "target_features" (after code) "\04+\0amultivalue+\0fmutable-globals+\0freference-types+\08sign-ext") | ||
) | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.