diff --git a/dynatos-router/src/query_array_signal.rs b/dynatos-router/src/query_array_signal.rs index d6f1d20..ce3bb0d 100644 --- a/dynatos-router/src/query_array_signal.rs +++ b/dynatos-router/src/query_array_signal.rs @@ -125,17 +125,52 @@ where } } +/// Updates the location on `Drop` +// Note: We need this wrapper because `BorrowRefMut::value` must +// already be dropped when we update the location, which we +// can't do if we implement `Drop` on `BorrowRefMut`. +#[derive(Debug)] +struct UpdateLocationOnDrop<'a, T: ToString + 'static>(pub &'a QueryArraySignal); + +impl<'a, T> Drop for UpdateLocationOnDrop<'a, T> +where + T: ToString + 'static, +{ + fn drop(&mut self) { + // Update the location + // Note: We suppress the update, given that it won't change anything, + // as we already have the latest value. + // TODO: Force an update anyway just to ensure some consistency with `FromStr` + `ToString`? + self.0.update_effect.suppressed(|| { + dynatos_context::with_expect::(|location| { + let mut location = location.borrow_mut(); + let mut queries = location + .query_pairs() + .into_owned() + .filter(|(key, _)| *key != *self.0.key) + .collect::>(); + for value in &*self.0.borrow() { + let value = value.to_string(); + queries.push(((*self.0.key).to_owned(), value)); + } + location.query_pairs_mut().clear().extend_pairs(queries); + }); + }); + } +} + /// Reference type for [`SignalBorrowMut`] impl #[derive(Debug)] pub struct BorrowRefMut<'a, T> where - T: ToString, + T: ToString + 'static, { /// Value value: signal::BorrowRefMut<'a, Vec>, - /// Signal - signal: &'a QueryArraySignal, + /// Update location on drop + // Note: Must be dropped *after* `value`. + _update_location_on_drop: UpdateLocationOnDrop<'a, T>, } impl<'a, T> Deref for BorrowRefMut<'a, T> @@ -158,32 +193,6 @@ where } } -impl<'a, T> Drop for BorrowRefMut<'a, T> -where - T: ToString, -{ - fn drop(&mut self) { - // Update the location - // Note: We suppress the update, given that it won't change anything, - // as we already have the latest value. - // TODO: Force an update anyway just to ensure some consistency with `FromStr` + `ToString`? - self.signal.update_effect.suppressed(|| { - dynatos_context::with_expect::(|location| { - let mut location = location.borrow_mut(); - let mut queries = location - .query_pairs() - .into_owned() - .filter(|(key, _)| *key != *self.signal.key) - .collect::>(); - for value in &*self.value { - let value = value.to_string(); - queries.push(((*self.signal.key).to_owned(), value)); - } - location.query_pairs_mut().clear().extend_pairs(queries); - }); - }); - } -} impl SignalBorrowMut for QueryArraySignal where @@ -196,7 +205,10 @@ where #[track_caller] fn borrow_mut(&self) -> Self::RefMut<'_> { let value = self.inner.borrow_mut(); - BorrowRefMut { value, signal: self } + BorrowRefMut { + value, + _update_location_on_drop: UpdateLocationOnDrop(self), + } } } diff --git a/dynatos-router/src/query_signal.rs b/dynatos-router/src/query_signal.rs index ce7ced8..5c18610 100644 --- a/dynatos-router/src/query_signal.rs +++ b/dynatos-router/src/query_signal.rs @@ -126,17 +126,49 @@ where } } +/// Updates the location on `Drop` +// Note: We need this wrapper because `BorrowRefMut::value` must +// already be dropped when we update the location, which we +// can't do if we implement `Drop` on `BorrowRefMut`. +#[derive(Debug)] +struct UpdateLocationOnDrop<'a, T: ToString + 'static>(pub &'a QuerySignal); + +impl<'a, T> Drop for UpdateLocationOnDrop<'a, T> +where + T: ToString + 'static, +{ + fn drop(&mut self) { + // Update the location + // Note: We suppress the update, given that it won't change anything, + // as we already have the latest value. + // TODO: Force an update anyway just to ensure some consistency with `FromStr` + `ToString`? + self.0.update_effect.suppressed(|| { + dynatos_context::with_expect::(|location| { + let mut location = location.borrow_mut(); + let mut queries = location.query_pairs().into_owned().collect::>(); + match self.0.borrow().as_deref().map(T::to_string) { + Some(value) => queries.insert((*self.0.key).to_owned(), value), + None => queries.remove(&*self.0.key), + }; + + location.query_pairs_mut().clear().extend_pairs(queries); + }); + }); + } +} + /// Reference type for [`SignalBorrowMut`] impl #[derive(Debug)] pub struct BorrowRefMut<'a, T> where - T: ToString, + T: ToString + 'static, { /// Value value: signal::BorrowRefMut<'a, Option>, - /// Signal - signal: &'a QuerySignal, + /// Update location on drop + // Note: Must be dropped *after* `value`. + _update_location_on_drop: UpdateLocationOnDrop<'a, T>, } impl<'a, T> Deref for BorrowRefMut<'a, T> @@ -159,30 +191,6 @@ where } } -impl<'a, T> Drop for BorrowRefMut<'a, T> -where - T: ToString, -{ - fn drop(&mut self) { - // Update the location - // Note: We suppress the update, given that it won't change anything, - // as we already have the latest value. - // TODO: Force an update anyway just to ensure some consistency with `FromStr` + `ToString`? - self.signal.update_effect.suppressed(|| { - dynatos_context::with_expect::(|location| { - let mut location = location.borrow_mut(); - let mut queries = location.query_pairs().into_owned().collect::>(); - match self.value.as_ref().map(T::to_string) { - Some(value) => queries.insert((*self.signal.key).to_owned(), value), - None => queries.remove(&*self.signal.key), - }; - - location.query_pairs_mut().clear().extend_pairs(queries); - }); - }); - } -} - impl SignalBorrowMut for QuerySignal where T: ToString + 'static, @@ -194,7 +202,10 @@ where #[track_caller] fn borrow_mut(&self) -> Self::RefMut<'_> { let value = self.inner.borrow_mut(); - BorrowRefMut { value, signal: self } + BorrowRefMut { + value, + _update_location_on_drop: UpdateLocationOnDrop(self), + } } }