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

uniffi::custom_type! should have try_lower instead of just lower #2425

Open
kriswuollett opened this issue Feb 3, 2025 · 2 comments
Open

Comments

@kriswuollett
Copy link

A possible common use case could be serializing a complex value instead of using Uniffi for everything like a structured record like a JSON type. For example I'd expect to be able to have a failure when lowering:

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct Metadata(serde_json::Value);

uniffi::custom_type!(Metadata, String, {
    try_lower: |s| serde_json::to_string(&s).context("Metadata serialization failed"),
    try_lift: |s| serde_json::from_str(&s).context("Metadata deserialization failed"),
});

I assumed that was possible, but found out only lower that doesn't return an error is available. A generic structure like a serde_json::Value may be invalid if non-string keys are used:

/// Serialize the given data structure as a String of JSON.
///
/// # Errors
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
/// fail, or if `T` contains a map with non-string keys.
#[inline]
pub fn to_string<T>(value: &T) -> Result<String>
where
    T: ?Sized + Serialize,
{
    let vec = tri!(to_vec(value));
    let string = unsafe {
        // We do not emit invalid UTF-8.
        String::from_utf8_unchecked(vec)
    };
    Ok(string)
}
@kriswuollett
Copy link
Author

[dependencies]
async-trait = "0.1.85"
serde = { version = "1.0.217", features = ["derive"] }
serde_json = { version = "1.0.138" }
thiserror = "2.0.11"
uniffi = { git = "http://github.com/mozilla/uniffi-rs", rev = "9c83e1de164b4168bd33bd991d22184ee9f6c856", optional = true }

@bendk
Copy link
Contributor

bendk commented Feb 27, 2025

I agree with this. The current system is based on the general lift/lower system, where we assume that any Rust type can be lowered and the only error possibility is when lifting data from the other side of the FFI. This is usually true, but not always.

I feel like I remember some corner cases with callback interfaces that are related to this as well, but I'm coming up blank when trying to recall them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants