-
-
Notifications
You must be signed in to change notification settings - Fork 5
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
Introduce WithDeserialized trait, which does not work #11
Conversation
Note that this pattern works in isolation, outside of the let input = String::from(r#"{"name": "John Doe", "age": 30}"#);
let value = merde_json::from_str(&input)?;
let my_struct = MyStruct::json_deserialize(Some(&value));
println!("{:?}", my_struct); ...where every binding borrows from the previous one. The difficulty here is to express the extension trait itself. |
diff --git a/src/lib.rs b/src/lib.rs
index c8687c8..c6e0448 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1552,24 +1552,22 @@ impl std::fmt::Debug for Fantome<'_, '_> {
/// Allows deserializing and interacting with a borrowed JSON value all
/// in one go.
-pub trait WithDeserialized<'src, 'val, T>
+pub trait WithDeserialized<'src, T>
where
Self: 'src,
- T: JsonDeserialize<'src, 'val> + 'val,
- 'src: 'val,
+ for<'x> T: JsonDeserialize<'src, 'x> + 'x
{
/// Parses as JSON, deserializes as a Rust type `T`, then
/// calls `f` with the deserialized value.
- fn with_deserialized(&'val self, f: impl FnOnce(&T)) -> Result<(), MerdeJsonError>;
+ fn with_deserialized(&self, f: impl FnOnce(&T)) -> Result<(), MerdeJsonError>;
}
-impl<'src, 'val, T> WithDeserialized<'src, 'val, T> for &'src str
+impl<'src, T> WithDeserialized<'src, T> for &'src str
where
Self: 'src,
- T: JsonDeserialize<'src, 'val> + 'val,
- 'src: 'val,
+ for<'x> T: JsonDeserialize<'src, 'x> + 'x,
{
- fn with_deserialized(&'val self, f: impl FnOnce(&T)) -> Result<(), MerdeJsonError> {
+ fn with_deserialized(&self, f: impl FnOnce(&T)) -> Result<(), MerdeJsonError> {
let json_value = from_str(self)?;
let deserialized: T = json_value.to_rust_value()?;
let _ = f(&deserialized); |
The trait constraint was wrong, because what you need is that As you cannot name that lifetime, the only solution (that I know of) is to use a HRTB which says "I need this to work for any lifetime, no matter how it's related to your other type parameters." |
Note that this only passes |
That won't work (see that the tests fail), because it needs to work for any lifetime, which is restricted above by |
Alright cool, that's my assessment too — was just curious if I missed something obvious. |
Riiight… Trying to fix the tests I got rustc to ICE, I think I'm done for the day.
That was my gut feeling, too, and even though the build passes, the failing tests make me think you're right about it. |
Report it! |
In order to properly get this to work, one would need to use GATs in which means one would have to introduce another trait to guide translation of some type to some "non-bounded object", similar to the mess of the |
Right, I did try that earlier! But then let x: u64 = some_json_value.to_rust_value()?; You get this: Which is to say: as long as Come to think of it, maybe that's the easier approach? I wonder if rustc devs would consider that a bug. |
yeah, it would probably make it required in practical usage to then use some newly introduced |
Here’s an idea: https://x.com/bushrat011899/status/1818770596727341313?s=46 — Instead of using + 'val as the lifetime bound, have you tried using a + Captures<'val> style of bound instead? There's a subtle difference in the lifetime resolution process that I'm not good enough to explain, but this trick solved a similar problem for me. I had a hard time finding code when I was trying this myself, but it's based on this feature: https://rust-lang.github.io/rfcs/3498-lifetime-capture-rules-2024.html You basically define a trait Captures which says any type implementing it has the same lifetime as T (e.g., &'a ()). This "fixes" the + 'a syntax (outlives) |
Closing now, this can be revisited. |
If anyone could explain:
JsonDeserialize
trait to make it workI would be ever so thankful.
Note that I've already tried to get rid of one of the two lifetime parameters on
JsonDeserialize
, or pass one or both of them onto the function itself, and to use GATs with an Output (which breaksToRustValue
), etc. — none of that works.The main reason why I have two lifetime parameters on
JsonDeserialize
is becauseJsonValue<'s>
is invariant over's
.