Skip to content
Closed
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
6 changes: 3 additions & 3 deletions src/bindings/filters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub fn typescript_ffi_converter_name(typ: &impl AsType, askama_values: &dyn aska
Type::Float64 => "FfiConverterFloat64".into(),
Type::Boolean => "FfiConverterBool".into(),
Type::String => "FfiConverterString".into(),
Type::Bytes => "FfiConverterBytes".into(),
Type::Bytes => "FfiConverterArrayBuffer".into(),
Type::Timestamp => "FfiConverterTimestamp".into(),
Type::Duration => "FfiConverterDuration".into(),
Type::Enum { name, .. } | Type::Record { name, .. } | Type::Object { name, .. } => typescript_ffi_converter_struct_enum_object_name(&name, askama_values)?,
Expand All @@ -131,7 +131,7 @@ pub fn typescript_ffi_converter_name(typ: &impl AsType, askama_values: &dyn aska

pub fn typescript_ffi_converter_lift_with(target: String, askama_values: &dyn askama::Values, typ: &impl AsType) -> Result<String> {
Ok(match typ.as_type() {
Type::String | Type::Map { .. } | Type::Sequence { .. } | Type::Enum { .. } | Type::Record { .. } => {
Type::String | Type::Bytes | Type::Map { .. } | Type::Sequence { .. } | Type::Enum { .. } | Type::Record { .. } => {
format!("{}.lift(new UniffiRustBufferValue({target}).consumeIntoUint8Array())", typescript_ffi_converter_name(typ, askama_values)?)
},
Type::Optional { inner_type } => {
Expand All @@ -143,7 +143,7 @@ pub fn typescript_ffi_converter_lift_with(target: String, askama_values: &dyn as

pub fn typescript_ffi_converter_lower_with(target: String, askama_values: &dyn askama::Values, typ: &impl AsType) -> Result<String> {
Ok(match typ.as_type() {
Type::String | Type::Map { .. } | Type::Sequence { .. } | Type::Enum { .. } | Type::Record { .. } => {
Type::String | Type::Bytes | Type::Map { .. } | Type::Sequence { .. } | Type::Enum { .. } | Type::Record { .. } => {
format!("UniffiRustBufferValue.allocateWithBytes({}.lower({target})).toStruct()", typescript_ffi_converter_name(typ, askama_values)?)
},
Type::Optional { inner_type } => {
Expand Down
48 changes: 48 additions & 0 deletions src/bindings/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,51 @@ pub fn generate_node_bindings(
index_ts_file_contents,
})
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn bytes_roundtrip_uses_rust_buffer_serde_in_generated_bindings() {
let ci = ComponentInterface::from_webidl(
r#"
namespace test {
bytes round_trip(bytes input);
};
"#,
"crate_name",
).unwrap();

let bindings = generate_node_bindings(
&ci,
GenerateNodeBindingsOptions {
sys_ts_main_file_name: "test-sys",
node_ts_main_file_name: "test-node",
out_dirname_api: DirnameApi::Dirname,
out_lib_disable_auto_loading: false,
out_import_extension: ImportExtension::None,
out_node_version: "^18",
out_verbose_logs: false,
out_lib_path: LibPath::Omitted,
},
).unwrap();

assert!(
bindings.node_ts_file_contents.contains("export function roundTrip("),
"node.ts should render the bytes round-trip function from the UDL"
);
assert!(
bindings.node_ts_file_contents.contains(
"let inputArg = UniffiRustBufferValue.allocateWithBytes(FfiConverterArrayBuffer.lower(input)).toStruct();"
),
"node.ts should lower bytes arguments into a RustBuffer struct before the ffi call"
);
assert!(
bindings.node_ts_file_contents.contains(
"return FfiConverterArrayBuffer.lift(new UniffiRustBufferValue(returnValue).consumeIntoUint8Array());"
),
"node.ts should lift bytes return values from the RustBuffer returned by ffi"
);
}
}
12 changes: 5 additions & 7 deletions templates/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

{%- macro function_return_type_or_void(func_def) -%}
{%- call function_return_type(func_def) -%}
{%- if func_def.return_type().is_none() -%}: void{%- endif %}
{%- if func_def.return_type().is_none() -%}: {% if func_def.is_async() -%}Promise<void>{%- else -%}void{%- endif %}{%- endif %}
{%- endmacro -%}

{% macro function_call_body(func_def, associated_object_name = "") %}
Expand Down Expand Up @@ -136,7 +136,7 @@
{%- match func_def.throws_type() -%}
{%- when Some(err) -%}
uniffiCaller.rustCallWithError(
/*liftError:*/ (buffer) => ["{{err | typescript_type_name}}", {{err | typescript_ffi_converter_name}}.lift(buffer)],
/*liftError:*/ (buffer) => new UniffiThrownObject("{{err | typescript_type_name}}", {{err | typescript_ffi_converter_name}}.lift(buffer)),
/*caller:*/ (callStatus) => {
{%- else -%}
uniffiCaller.rustCall(
Expand Down Expand Up @@ -204,7 +204,7 @@ import {
FfiConverterArrayBuffer,
FfiConverterObject,
RustBuffer,
UniffiError,
UniffiThrownObject,
UniffiInternalError,
type UniffiRustCaller,
type UniffiRustCallStatus,
Expand Down Expand Up @@ -382,7 +382,7 @@ export class {{ object_def.name() | typescript_class_name }} extends UniffiAbstr
const pointer = {%- match constructor_fn.throws_type() -%}
{%- when Some(err) -%}
uniffiCaller.rustCallWithError(
/*liftError:*/ (buffer) => ["{{err | typescript_type_name}}", {{err | typescript_ffi_converter_name}}.lift(buffer)],
/*liftError:*/ (buffer) => new UniffiThrownObject("{{err | typescript_type_name}}", {{err | typescript_ffi_converter_name}}.lift(buffer)),
/*caller:*/ (callStatus) => {
{%- else -%}
uniffiCaller.rustCall(
Expand Down Expand Up @@ -554,9 +554,7 @@ const {{ object_def.name() | typescript_ffi_converter_struct_enum_object_name }}
{% call ts::docstring(func_def, 0) %}
export {% if func_def.is_async() %}async {% endif %}function {{ func_def.name() | typescript_fn_name }}(
{%- call ts::param_list(func_def) -%}
){%- if let Some(ret_type) = func_def.return_type() -%}: {% if func_def.is_async() -%}
Promise<{%- endif -%}{{ ret_type | typescript_type_name }}{%- if func_def.is_async() -%}>{%- endif -%}
{%- endif %} {
){% call function_return_type_or_void(func_def) %} {
{%- call function_call_body(func_def) -%}
}

Expand Down
18 changes: 8 additions & 10 deletions templates/sys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
type UniffiByteArray,
UniffiInternalError,
uniffiCreateFfiConverterString,
UniffiError,
} from 'uniffi-bindgen-react-native';


Expand Down Expand Up @@ -156,8 +155,8 @@ class UniffiFfiRsRustCaller {
return this.makeRustCall(caller, liftString);
}

rustCallWithError<T, ErrorEnumAndVariant extends [string, string]>(
liftError: (buffer: UniffiByteArray) => ErrorEnumAndVariant,
rustCallWithError<T>(
liftError: (buffer: UniffiByteArray) => Error,
caller: (status: JsExternal) => T,
liftString: (bytes: UniffiByteArray) => string,
): T {
Expand Down Expand Up @@ -187,10 +186,10 @@ class UniffiFfiRsRustCaller {
// return status;
}

makeRustCall<T, ErrorEnumAndVariant extends [string, string]>(
makeRustCall<T>(
caller: (status: JsExternal) => T,
liftString: (bytes: UniffiByteArray) => string,
liftError?: (buffer: UniffiByteArray) => ErrorEnumAndVariant,
liftError?: (buffer: UniffiByteArray) => Error,
): T {
_checkUniffiLoaded();

Expand All @@ -207,10 +206,10 @@ class UniffiFfiRsRustCaller {
}
}

function uniffiCheckCallStatus<ErrorEnumAndVariant extends [string, string]>(
function uniffiCheckCallStatus(
callStatus: UniffiRustCallStatusStruct,
liftString: (bytes: UniffiByteArray) => string,
liftError?: (buffer: UniffiByteArray) => ErrorEnumAndVariant,
liftError?: (buffer: UniffiByteArray) => Error,
) {
switch (callStatus.code) {
case CALL_SUCCESS:
Expand All @@ -224,8 +223,7 @@ function uniffiCheckCallStatus<ErrorEnumAndVariant extends [string, string]>(
const errorBufBytes = struct.consumeIntoUint8Array();

if (liftError) {
const [enumName, errorVariant] = liftError(errorBufBytes);
throw new UniffiError(enumName, errorVariant);
throw liftError(errorBufBytes);
}
}
throw new UniffiInternalError.UnexpectedRustCallError();
Expand Down Expand Up @@ -498,7 +496,7 @@ const FFI_DYNAMIC_LIB = define({
/* {{ arg.name() }} */ {{ arg.type_().borrow() | typescript_ffi_type_name }}{% if !loop.last %}, {% endif %}
{%- endfor %}
{%- if callback.has_rust_call_status_arg() -%}
{% if callback.arguments().len() > 0 %}, {% endif %} RustCallStatus
{% if callback.arguments().len() > 0 %}, {% endif %}{{ &FfiType::RustCallStatus | typescript_ffi_type_name }}
{%- endif %}
]) => {%- match callback.return_type() %}
{%- when Some(return_type) %}
Expand Down
Loading