-
Notifications
You must be signed in to change notification settings - Fork 62
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
Optimize RustStr
's Equatable
implementation
#151
Conversation
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.
Minor notes then looks good to me.
Great work here, thanks for figuring this out!
} | ||
XCTContext.runActivity(named: "Should not be equal"){ | ||
_ in | ||
//Equal length |
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.
minor: The Equal length
and Not equal length
are on the wrong tests. Need to switch them.
struct RustStr __swift_bridge__$RustString$trim(void* self); | ||
bool __swift_bridge__equality_operator_for_RustStr(struct RustStr lhs, struct RustStr rhs); |
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.
__swift_bridge__$RustStr$partial_eq
src/lib.rs
Outdated
@@ -92,5 +92,25 @@ pub extern "C" fn __swift_bridge__null_pointer() -> *const std::ffi::c_void { | |||
std::ptr::null() | |||
} | |||
|
|||
#[no_mangle] | |||
#[doc(hidden)] | |||
pub extern "C" fn __swift_bridge__equality_operator_for_RustStr( |
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.
__swift_bridge__RustStr__partial_eq
src/lib.rs
Outdated
return false; | ||
} | ||
|
||
unsafe { |
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.
Another alternative that I thought of was:
unsafe {
std::slice::from_raw_parts(lhs.start, lhs.len) ==
std::slice::from_raw_parts(rhs.start, rhs.len)
}
I was thinking that the stdlib might have an optimization that I was unfamiliar with, but I think that desugars to https://doc.rust-lang.org/1.52.1/src/core/slice/cmp.rs.html#69-75
Which looks like the same as what you're doing. So this looks good to me.
src/lib.rs
Outdated
@@ -92,5 +92,25 @@ pub extern "C" fn __swift_bridge__null_pointer() -> *const std::ffi::c_void { | |||
std::ptr::null() | |||
} | |||
|
|||
#[no_mangle] |
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.
You can put this in std_bridge/string.rs
under here
swift-bridge/src/std_bridge/string.rs
Lines 61 to 82 in 23d60fe
impl RustStr { | |
pub fn len(&self) -> usize { | |
self.len | |
} | |
// TODO: Think through these lifetimes and the implications of them... | |
pub fn to_str<'a>(self) -> &'a str { | |
let bytes = unsafe { std::slice::from_raw_parts(self.start, self.len) }; | |
std::str::from_utf8(bytes).expect("Failed to convert RustStr to &str") | |
} | |
pub fn to_string(self) -> String { | |
self.to_str().to_string() | |
} | |
pub fn from_str(str: &str) -> Self { | |
RustStr { | |
start: str.as_ptr(), | |
len: str.len(), | |
} | |
} | |
} |
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.
I got the link error like:
Testing failed:
Undefined symbol: ___swift_bridge__$RustStr$partial_eq
Testing cancelled because the build failed.
How does the Swift-compiler know where methods are, such as len
, to_string
.
swift-bridge/src/std_bridge/string.rs
Lines 62 to 80 in 0de0dc8
pub fn len(&self) -> usize { | |
self.len | |
} | |
// TODO: Think through these lifetimes and the implications of them... | |
pub fn to_str<'a>(self) -> &'a str { | |
let bytes = unsafe { std::slice::from_raw_parts(self.start, self.len) }; | |
std::str::from_utf8(bytes).expect("Failed to convert RustStr to &str") | |
} | |
pub fn to_string(self) -> String { | |
self.to_str().to_string() | |
} | |
pub fn from_str(str: &str) -> Self { | |
RustStr { | |
start: str.as_ptr(), | |
len: str.len(), | |
} |
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.
Seaching for RustStr
's methods with a tool like grep
, I couldn't find any declarations of them in any c-header files.
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.
swift-bridge/crates/swift-bridge-build/src/generate_core.rs
Lines 16 to 38 in e8d3859
pub(super) fn write_core_swift_and_c(out_dir: &Path) { | |
let core_swift_out = out_dir.join("SwiftBridgeCore.swift"); | |
let mut swift = core_swift(); | |
swift += "\n"; | |
swift += &RUST_STRING_SWIFT; | |
swift += "\n"; | |
swift += &SWIFT_CALLBACK_SUPPORT_NO_ARGS_NO_RETURN; | |
swift += "\n"; | |
swift += &SWIFT_RUST_RESULT; | |
std::fs::write(core_swift_out, swift).unwrap(); | |
let core_c_header_out = out_dir.join("SwiftBridgeCore.h"); | |
let mut c_header = core_c_header().to_string(); | |
c_header += "\n"; | |
c_header += &RUST_STRING_C; | |
c_header += "\n"; | |
c_header += &C_CALLBACK_SUPPORT_NO_ARGS_NO_RETURN; | |
c_header += "\n"; | |
c_header += &C_RESULT_SUPPORT; | |
std::fs::write(core_c_header_out, c_header).unwrap(); | |
} |
struct RustStr __swift_bridge__$RustString$as_str(void* self); | |
struct RustStr __swift_bridge__$RustString$trim(void* self); |
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.
Oh wait, it looks like none of the RustStr
methods like len
or to_string
are actually bridged. So that's why you couldn't find them.
But yeah you can declare the ___swift_bridge__$RustStr$partial_eq
inside of rust_string.c.h
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.
The build script might not be getting re-ran.
Try running touch crates/swift-integration-tests/build.rs
or otherwise modifying and saving (then removing the modification of) the build.rs
so that it gets re-run and seeing if that works.
https://doc.rust-lang.org/cargo/reference/build-scripts.html#life-cycle-of-a-build-script
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.
Try running touch crates/swift-integration-tests/build.rs or otherwise modifying and saving
I got the link error again.
RustString
's methods, such as len()
and as_str()
, seem to be imported on the Swift side.
However, RustStr
's methods don't seem to be imported on the Swift side.
I tried to dive into this problem, and run objdump -d libswift_integration_tests.a | grep RustStr
:
0000000000000328 <__ZN12swift_bridge10std_bridge6string7RustStr10partial_eq17h39b2f23e5457666eE
patial_eq
might be not __swift_bridge__$RustStr$partial_eq
but __ZN12swift_bridge10std_bridge6string7RustStr10partial_eq17h39b2f23e5457666eE
.
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.
I just fetched your branch and I can reproduce the error. Give me a sec
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.
This should work:
// std_bridge/string.rs
impl RustStr {
// ...
}
impl PartialEq for RustStr {
fn eq(&self, other: &Self) -> bool {
unsafe {
std::slice::from_raw_parts(self.start, self.len)
== std::slice::from_raw_parts(other.start, other.len)
}
}
}
#[export_name = "__swift_bridge__$RustStr$partial_eq"]
#[allow(non_snake_case)]
pub extern "C" fn __swift_bridge__RustStr_partial_eq(lhs: RustStr, rhs: RustStr) -> bool {
lhs == rhs
}
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.
I'm sorry for taking up your time. I'm going to study rust hard.
// on the Rust side that compares the underlying byte slices. | ||
return | ||
lhs.toString() == rhs.toString() | ||
return __swift_bridge__equality_operator_for_RustStr(lhs, rhs); |
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.
Beautiful
RustStr
's Equatable
implementation
src/lib.rs
Outdated
lhs: string::RustStr, | ||
rhs: string::RustStr, | ||
) -> bool { | ||
if lhs.len != rhs.len { |
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.
Let's make this lhs == rhs
And then you can
impl PartialEq for RustStr { .. }
And handle the comparison inside of the PartialEq
impl.
src/std_bridge/string.rs
Outdated
@@ -79,4 +81,15 @@ impl RustStr { | |||
len: str.len(), | |||
} | |||
} | |||
|
|||
pub fn partial_eq( |
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.
Should move this into a PartialEq
trait implementation.
impl PartialEq for RustStr {
// ...
}
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.
Should move this into a PartialEq trait implementation.
Sorry...I know that I should do it, but I want to solve the link error first. So, I pushed 03245ec to share this problem.
I addressed your review. Sorry... |
Great work! |
Addresses #148.