-
Notifications
You must be signed in to change notification settings - Fork 211
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
Add TryFrom to convert from Varargs to tuples #886
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.
Thanks for this! 🙂
Maybe a general question, what was your use case for this feature?
It seems like type safety is the main reason, i.e. not dealing with Variant
but direct Rust types. On the other hand, this is quite a low-level API (implementing Method
trait), and for type safety we also have #[derive(FromVarargs)] struct Args
which is only slightly more verbose. I'm a bit hesitant to heavily invest in convenience of the low-level builder APIs, as most people use the proc-macros, and a lot of this might become entirely obsolete with GDExtension 🤔
This doesn't support match patterns (for different number of arguments), right?
I guess for that we could still use slice patterns, even though that means Variant
elements:
match varargs.as_slice() {
[a, b] => ...,
[first, .., last] => ...,
_ => ...,
}
gdnative-core/src/export/method.rs
Outdated
/// All possible error types for convert from Varargs. | ||
#[derive(Debug)] | ||
pub enum VarargsError { | ||
ArgumentLengthError(ArgumentLengthError), | ||
FromVariantError(FromVariantError), | ||
} |
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.
Do we really need nested types here?
We have struct-like enumerators for FromVariantError
and it seems to work well.
We also don't really need all the From<T>
implementations -- as I see it, they provide minor convenience for this one file, at the cost of much more 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.
That's what I missed! 🤣
However, FromVariantError
does not appear to be specialized to arguments error messages. In Rust, Change of type enum is breaking change, so it cannot be changed immediately either. So it looks like we will create an ArgumentTypeError
that is specialized for argument errors and VarargsError
will remain nested.
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 could also be done like this, no?
#[derive(Debug)]
pub enum VarargsError {
ArgumentLengthError {
passed: usize,
expected: usize,
},
FromVariantError(FromVariantError),
}
Or if you find ArgumentTypeError
more meaningful than FromVariantError
, you could also do a struct-like enumerator for that.
Unless of course we find a good reason to reuse those types, but they seem used isolated.
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 did not do that, because if we write the structure directly to enum, we would not be able to write methods for each errors.
Btw, the I think the proper way would have been implementing That's probably something we can adjust for v0.11. |
My use case is refactoring of the However, this is a failure because it lacks a bit of flexibility. 😅 Nevertheless, the PR was created because it is useful.
Don't worry, the types passed as arguments are the same. See header (
Interesting, but |
I see, but that on its own is not a reason to make that a public and documented API. If it's only used by the proc-macro, it can still be In other words: why does a user need this, when there is already the safer
Thanks for checking! However, both being So, we would need to check that. What I meant is that with the current bottom-up approach toward GDExtension, I'm not sure yet which parts of the code can be kept (and at what cost). A lot of stuff has accumulated over the years, and it's an opportunity to strip down rarely used legacy code, also in light of bigger safety refactorings. So... time will tell, don't be discouraged if not everything will be taken over to GDExtension 😉 |
This PR is replaces the |
Sorry, I totally wrote to the wrong PR. I meant to comment on your other changes #887 🙈 hope that makes more sense. |
gdnative-core/src/export/method.rs
Outdated
if self.idx < self.args.len() { | ||
let idx = self.idx; | ||
self.idx += 1; | ||
Some(self.args[idx]) | ||
} else { | ||
None | ||
} |
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 part may be simplified by using slice.get
?
if self.idx < self.args.len() { | |
let idx = self.idx; | |
self.idx += 1; | |
Some(self.args[idx]) | |
} else { | |
None | |
} | |
let result = self.args.get(self.idx); | |
self.idx += 1; | |
result |
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 test did not pass, so I made some fixes.
if self.idx < self.args.len() { | |
let idx = self.idx; | |
self.idx += 1; | |
Some(self.args[idx]) | |
} else { | |
None | |
} | |
let ret = self.args.get(self.idx); | |
ret.map(|&v| { | |
self.idx += 1; | |
v | |
}) |
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 is slightly confusing, as map()
typically transforms the contents of the Option
and has no side effects.
I'd rather do:
let ret = self.args.get(self.idx);
if ret.is_some() {
self.idx += 1;
}
ret
In the future there might be Option::inspect()
for this purpose, but it's not yet stable.
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.
Fixed. Reflected in next push.
Note that this PR now depends on #892! |
Then I'd say we sort out #892 first, which would make this PR significantly smaller to review. |
Change Varargs struct to store a slice instead of an iterator
Since this is a rarely used feature, a rich encapsulated API for error handling is likely not needed. Most users do not explicitly differentiate error variants, having a descriptive Display impl is usually more important. Supports only 4 expressions for length checks: a, a.., ..=b, a..=b. These are almost always literals and exclusive bounds are likely error prone in this context. Additionally, check_length() with the full range '..' makes no sense, so it's not supported.
f6fe765
to
461b72e
Compare
Rebased on bors r+ |
Build succeeded: |
This PR is stacked on
varargs_gets
branch. See #892 for details on some of the commits included in this PR.Feature
Dirty syntax to convert to tuples. This makes manual binding easier to write than ever before.
Implement via
varargs_into_tuple!()
macro. Can be converted to tuples up to 12 in length. This is the same length supported by standard library.Compatibility
Since this PR only adds an API, there are no compatibility issues.