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

Support Hashable #140

Merged
merged 8 commits into from
Jan 19, 2023
Merged

Support Hashable #140

merged 8 commits into from
Jan 19, 2023

Conversation

NiwakaDev
Copy link
Collaborator

This PR addresses #77 and introduces the #[swift_bridge(Hashable)] attribute, which is used to generate a type that conforms to Hashable protocol.

Somthing like:

// Rust 
mod ffi {
    extern "Rust" {
        #[swift_bridge(Hashable)]
        type SomeType;
    }
}
// Generated Swift
class SomeType {
    // ...
}

// SomeType inherits SomeTypeRef. So, SomeType also conforms to Hashable protocol.
extension SomeTypeRef: Hashable {
    public func hash(into hasher: inout Hasher) {
        hasher.combine(__swift_bridge__$SomeType$_hash(rhs.ptr))
    }
}

@NiwakaDev NiwakaDev changed the title Support hashable Support Hashable Jan 19, 2023
Copy link
Owner

@chinedufn chinedufn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks GREAT!

Left some very minor feedback and then we can merge this.

Thanks for your awesome work.

pub extern "C" fn #function_name (
this: *const super::#ty_name,
) -> u64 {
let mut s = DefaultHasher::new();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let mut s = std::collections::hash_map::DefaultHasher

ty.ty.span(),
);
let tokens = quote! {
use std::hash::Hash;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move use std::hash::{Hash, Hasher} inside of the generated function so that we don't have multiple includes in the same scope when there are multiple Hashable attributes.

Copy link
Collaborator Author

@NiwakaDev NiwakaDev Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move use std::hash::{Hash, Hasher} inside of the generated function

Do you mean this?:

pub extern "C" fn #function_name (
    this: *const super::#ty_name,
) -> u64 {
    use std::hash::{Hash, Hasher};
    let mut s = std::collections::hash_map::DefaultHasher::new();
    (unsafe {&*this}).hash(&mut s);
    s.finish()
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup

Copy link
Owner

@chinedufn chinedufn Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh and you can also use DefaultHasher if you want.

use std::collections::hash_map::DefaultHasher;
let mut s = DefaultHasher::new();

I'm fine either way as long we we keep the use statements inside of the function so that we don't the same use multiple times in the module's root scope (since that would create a warning that we'd have to silence).

@@ -89,5 +89,46 @@ class OpaqueRustStructTests: XCTestCase {
XCTAssertNotEqual(val1, val2)
}
}

func testOpaqueRustTypeImplHashable() throws {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding tests!!

#[derive(Hash, PartialEq)]
struct RustHashType(u32);

impl RustHashType {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this impl, as well as the one in the Equatable example above.

I know I'm the one that introduced this, but I'm now realizing that it's a waste of space.

You can also delete the fn new in the bridge module in both this Hashable example as well as the Equatable one. Just to get rid of noise.


#### #[swift_bridge(Hashable)]

The `Hashable` attribute allows you to expose a Rust `Hash` trait via Swift's
Copy link
Owner

@chinedufn chinedufn Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very minor feedback -> "... expose Rust's `Hash` trait via ..."

Copy link
Owner

@chinedufn chinedufn Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry.. actually can you make it "... expose a Rust `Hash` trait implementation via ..."

Sorry for the hassle just trying to keep things somewhat consistent.

You can ignore this feedback if you've already went and changed it to the first comment... Not a big deal for now...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry.. actually can you make it "... expose a Rust Hash trait implementation via ..."

Yes!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Sorry for the hassle just trying to keep things somewhat consistent.
You can ignore this feedback if you've already went and changed it to the first comment... Not a big deal for now...

Please do not apologize...

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I felt bad for nitpicking, glad you don't care.
Sweet, thanks!

Copy link
Owner

@chinedufn chinedufn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Once tests are passing I can merge. Thank you!!

```

```swift
// In Swift

let val1 = RustPartialEqType(5)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry we should keep this, I just meant to get rid of the fn new

}
}

#[derive(PartialEq)]
struct RustPartialEqType(u32);
Copy link
Owner

@chinedufn chinedufn Jan 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry we should keep this struct RustPartialEqType(u32);. I just meant to get rid of the fn new impl and fn new bridge.

}

#[derive(Hash, PartialEq)]
struct RustHashType;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RustHashType(u32)

```swift
// In Swift

let val = RustHashType()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RustHashType(10)


fn expected_rust_tokens() -> ExpectedRustTokens {
ExpectedRustTokens::Contains(quote! {
use std::hash::Hash;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now failing. Just need to move it inside and then I can merge

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry...After addressing your review, I forgot to run unit tests.

@NiwakaDev
Copy link
Collaborator Author

Addressed your review!

@chinedufn
Copy link
Owner

This is great stuff, thanks again. Loving your contributions!

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

Successfully merging this pull request may close these issues.

2 participants