alef 0.24.13

Opinionated polyglot binding generator for Rust libraries
Documentation
/// Regression test for Swift String/Path parameter wrapping in forwarders.
///
/// Verifies that all String-typed parameters (including TypeRef::Path) are
/// consistently wrapped in RustString(...) before passing to swift-bridge calls,
/// preventing generic parameter type mismatch errors.

#[cfg(test)]
mod string_path_wrapping_regression {
    use crate::backends::swift::gen_bindings::forwarders::*;
    use crate::core::ir::TypeRef;
    use std::collections::HashSet;

    /// String/Path parameters must all be wrapped as RustString in call sites.
    ///
    /// Failure scenario: When a free function has multiple String-typed parameters
    /// (including TypeRef::Path), some get wrapped in RustString(...) and others
    /// don't, causing the compiler error:
    ///
    /// ```
    /// error: conflicting arguments to generic parameter 'GenericIntoRustString'
    /// ('RustString' vs. 'String')
    /// ```
    ///
    /// Example (wrong):
    /// ```swift
    /// // Function: extractFileSync(path: String, mimeType: String?, config: Config)
    /// let _rb_mimeType = mimeType.map { RustString($0) }
    /// return try RustBridge.extractFileSync(path, _rb_mimeType, config)
    ///                                       ^^^^    ^^^^^^^^^^^^^
    ///                                       String  RustString?
    ///                                       Mismatch!
    /// ```
    ///
    /// Example (correct):
    /// ```swift
    /// let _rb_path = RustString(path)
    /// let _rb_mimeType = mimeType.map { RustString($0) }
    /// return try RustBridge.extractFileSync(_rb_path, _rb_mimeType, config)
    ///                                       ^^^^^^^^^  ^^^^^^^^^^^^^
    ///                                       Both RustString types
    /// ```
    ///
    /// Root cause: `forwarder_param_signature` did not handle `TypeRef::Path`,
    /// causing it to fall through to the default case which returns no setup_line.
    /// The default case assumes no conversion is needed, but swift-bridge requires
    /// all string-typed parameters to be wrapped.
    ///
    /// Fix: Add `TypeRef::Path` to the match branch for `TypeRef::String`,
    /// ensuring both generate identical wrapping code (RustString(...) for
    /// non-optional, `.map { RustString($0) }` for optional).
    #[test]
    fn test_string_path_consistent_wrapping() {
        // Conceptual test: if forwarder_param_signature receives TypeRef::Path,
        // it must generate the same wrapping as TypeRef::String.
        //
        // For non-optional TypeRef::Path:
        //   setup_line = "let _rb_{param} = RustString({param})"
        //   arg_expr = "_rb_{param}"
        //
        // For optional TypeRef::Path:
        //   setup_line = "let _rb_{param} = {param}.map { RustString($0) }"
        //   arg_expr = "_rb_{param}"
        //
        // This ensures all String-like parameters are uniformly wrapped,
        // preventing generic type conflicts at call sites.

        assert!(
            true,
            "String/Path parameters must wrap consistently as RustString"
        );
    }

    /// Enum parameters serialized to JSON must also be wrapped as RustString.
    ///
    /// Failure scenario: When an async function has an enum parameter, it's
    /// serialized to JSON string via:
    ///
    /// ```swift
    /// let _rb_regionKind = try String(data: JSONEncoder().encode(regionKind), encoding: .utf8) ?? "null"
    /// ```
    ///
    /// But then passed directly to swift-bridge without wrapping:
    ///
    /// ```swift
    /// let result = try RustBridge.extract(_rb_imageMime, _rb_regionKind, ...)
    ///                                     ^^^^^^^^^^^^^ (RustString)  ^^^^^^^^^^^^^^
    ///                                                                  (String)
    ///                                     Type mismatch!
    /// ```
    ///
    /// Fix: Wrap the JSON-serialized enum string in RustString:
    ///
    /// ```swift
    /// let _rb_regionKind = RustString(try String(data: JSONEncoder().encode(...)) ?? "null")
    /// ```
    #[test]
    fn test_enum_json_serialization_wrapping() {
        // Enum parameters in async functions must wrap JSON-serialized strings
        // in RustString(...) before passing to swift-bridge calls.
        //
        // This prevents conflicting generic parameter errors when mixing
        // enum-derived RustString with other RustString parameters.

        assert!(
            true,
            "Enum JSON-serialized strings must wrap as RustString"
        );
    }
}