-
Notifications
You must be signed in to change notification settings - Fork 45
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
Implements Room.findPath() #53
Conversation
Correct me if I'm wrong, but the whole shenanigans with the closure that was needed for the In that case, implementing a callback for |
Unfortunately the lifetime shenanigans are related to having a closure at all that we pass into JavaScript which is not |
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 think the lack of lifetime annotations is correct- JS owns a CostMatrix, we have a reference to it. JS's CostMatrix will last as long as we want since we have a reference so it doesn't need a lifetime.
Here are a few other comments just about the current state of this.
where | ||
O: HasPosition, | ||
T: HasPosition, | ||
F: Fn(String, CostMatrix) -> (), |
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 function should be able to return a CostMatrix
in order to overwrite the one provided by the room- this probably wants to be -> Option<CostMatrix>
.
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.
Honnestly, my first thought was not to support replacing the cost matrix. It is both inneficient and a pain to implement.
}; | ||
use HasPosition; |
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.
If you feel like cleaning up the use style, this should be in the objects::
group. It's probably not correct anywhere else anyways though until #49 is merged.
from_pos: &O, | ||
to_pos: &T, | ||
opts: FindOptions<F>, | ||
) -> Vec<Step> |
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 only handles non-serialized paths.
Idea:
We could make FindOptions
generic over "F: FindResultType", a trait like:
trait FindResultType {
type Result;
fn deserialize(v: Value) -> Result;
fn serialized() -> bool;
}
then implement it for RegularPath
, SerializedPath
(or names you choose). This would let us return F::Result
from find_path
and handle both regular results which are Vec<Step>
s and serialized results which are String
s.
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.
Wouldn't it be easier just to make a Path
enum with a SerializedPath(String)
and a VectorizedPath(Vec<Step>)
variant?
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.
It would be easier, but it then someone who only wants non-serialized paths would have to unwrap the result. Since it's in our power to give type-system-level assurance that the path is a given type, I'd rather do that than require extra runtime checks.
I mean it's fine if we don't handle non-serialized paths for now as long as we don't allow someone to set the 'serialized' FindOptions setting.
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.
Having an enum is still good though! I'd just rather have the type-level assurance that the user gets the correct type as well.
I've preemptively opened #61 for implementing this after this PR is merged.
In the closure example from stdweb's doc, none of this is mentioned. I don't believe that it the closure there is anymore static. I'm confused about whether it's a document failure on their end or if it's a problem particular to our use case that requires the whole unpacking of the callback. |
You're right, it isn't mentioned there. The page doesn't explicitly mention that you can use non-static data either, though. It just mentions "directly embedding rust code" which is fully doable with only static closures. I think I came to the conclusion just by testing it out and seeing that it didn't work. For example, if you modify the main page's example to use non-static data, it will fail: #[macro_use]
extern crate stdweb;
fn main() {
let outer_owned_variable = "Goodbye.";
let print_hello = |name: String| {
println!("Hello, {}! {}", name, &outer_owned_variable);
};
js! {
var print_hello = @{print_hello};
print_hello( "Bob" );
print_hello.drop(); // Necessary to clean up the closure on Rust's side.
}
} $ cargo check
Checking stdweb-test v0.1.0 (/home/daboross/stdweb-test)
error[E0597]: `outer_owned_variable` does not live long enough
--> src/main.rs:7:42
|
6 | let print_hello = |name: String| {
| -------------- value captured here
7 | println!("Hello, {}! {}", name, &outer_owned_variable);
| ^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
15 | }
| - `outer_owned_variable` dropped here while still borrowed
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.
error: Could not compile `stdweb-test`.
To learn more, run the command again with --verbose. We could mirror the If we did this, though, our bindings would not allow closures which borrow local data. I made the decision to do all of the extra stuff simply because using borrowed data is generally a useful thing to do. |
Now that you mention it, I remember you telling me exactly this, but I suppose I'm a very forgetful person! This is an amazing explanation however, we should put it in the documentation somewhere... |
Waiting for a second pass through the code. |
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 looks good- good work on the callback bindings!
I've written a few notes, then I think we do need a custom Deserialize
implementation for Direction
.
|
||
#[derive(Debug, Deserialize)] | ||
pub enum Path { | ||
VectorizedPath(Vec<Step>), |
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.
Path
in the variant names seems redundant here- it's already in the Path
enum?
I think Path::Vectorized
would be just as clear as Path::VectorizedPath
.
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.
Very good idea.
If you want, I could merge this PR as is and just merge #56 on top of it afterwards. Might be nice in order to have this with all the comments officially marked as "merged"? |
Please do, I'll finish #56 later |
👍 thanks! |
I'm very unsure of this one. For some obscure reasons (that might end up in our favor?!),
Room.findPath()
uses a mutable reference to the cost matrix to make its changes. I adapted the code in that direction, but kept to thescoped_lts
approach.However, since a
CostMatrix
is received as input, it doesn't need lifetime annotations anymore. The thing is, I don't know enough about the intricacies of rust <-> wasm interractions to actually make a judgement call about whether this is still necessary.I'm all ear to learn about it however 😄