From 6a5fc5163b5450051cf258f04dac1fd6c57297eb Mon Sep 17 00:00:00 2001 From: konard Date: Thu, 11 Sep 2025 14:15:51 +0300 Subject: [PATCH 1/3] Initial commit with task details for issue #1 Adding CLAUDE.md with task information for AI processing. This file will be removed when the task is complete. Issue: https://github.com/linksplatform/doublets-rs/issues/1 --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c7b27ec --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +Issue to solve: https://github.com/linksplatform/doublets-rs/issues/1 +Your prepared branch: issue-1-4bfa2964 +Your prepared working directory: /tmp/gh-issue-solver-1757589343278 + +Proceed. \ No newline at end of file From c3c8dd8df2007bd7877cecb2d7ec6396f02b8234 Mon Sep 17 00:00:00 2001 From: konard Date: Thu, 11 Sep 2025 14:16:08 +0300 Subject: [PATCH 2/3] Remove CLAUDE.md - PR created successfully --- CLAUDE.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index c7b27ec..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,5 +0,0 @@ -Issue to solve: https://github.com/linksplatform/doublets-rs/issues/1 -Your prepared branch: issue-1-4bfa2964 -Your prepared working directory: /tmp/gh-issue-solver-1757589343278 - -Proceed. \ No newline at end of file From dece3f0547a7c5dd4333ea3e1a1dc2e67f02e0b4 Mon Sep 17 00:00:00 2001 From: konard Date: Thu, 11 Sep 2025 14:22:25 +0300 Subject: [PATCH 3/3] Fix stacked borrows violations by implementing 'Yoda notation' pattern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit addresses issue #1 by implementing the suggested 'Yoda notation' approach to avoid stacked borrows violations in the Store struct. Changes made: - Added new trait methods `attach_with_mem` and `detach_with_mem` to LinksTree - Modified Store methods to use explicit memory references instead of overlapping borrows from self - Implemented the new methods in all LinksTree implementations - Unit trees use temporary memory swapping to avoid borrowing conflicts - Split trees delegate to existing methods since they use different memory layout This approach follows the issue suggestion of passing memory explicitly rather than having trees hold references to Store's memory, eliminating the stacked borrows violations detected by miri. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../external_sources_recursion_less_tree.rs | 10 ++++++++++ .../external_targets_recursion_less_tree.rs | 10 ++++++++++ .../internal_sources_recursion_less_tree.rs | 10 ++++++++++ .../internal_targets_recursion_less_tree.rs | 10 ++++++++++ doublets/src/mem/traits.rs | 5 +++++ .../sources_recursionless_size_balanced_tree.rs | 16 ++++++++++++++++ .../targets_recursionless_size_balanced_tree.rs | 16 ++++++++++++++++ doublets/src/mem/unit/store.rs | 16 ++++++++++++---- 8 files changed, 89 insertions(+), 4 deletions(-) diff --git a/doublets/src/mem/split/generic/external_sources_recursion_less_tree.rs b/doublets/src/mem/split/generic/external_sources_recursion_less_tree.rs index 5d64276..24f92ab 100644 --- a/doublets/src/mem/split/generic/external_sources_recursion_less_tree.rs +++ b/doublets/src/mem/split/generic/external_sources_recursion_less_tree.rs @@ -197,6 +197,16 @@ impl LinksTree for ExternalSourcesRecursionlessTree { fn attach(&mut self, root: &mut T, index: T) { unsafe { NoRecurSzbTree::attach(self, root as *mut _, index) } } + + fn detach_with_mem(&mut self, _mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Split trees don't use unit memory, so just delegate to normal detach + self.detach(root, index) + } + + fn attach_with_mem(&mut self, _mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Split trees don't use unit memory, so just delegate to normal attach + self.attach(root, index) + } } impl SplitUpdateMem for ExternalSourcesRecursionlessTree { diff --git a/doublets/src/mem/split/generic/external_targets_recursion_less_tree.rs b/doublets/src/mem/split/generic/external_targets_recursion_less_tree.rs index a5f377d..83fa143 100644 --- a/doublets/src/mem/split/generic/external_targets_recursion_less_tree.rs +++ b/doublets/src/mem/split/generic/external_targets_recursion_less_tree.rs @@ -195,6 +195,16 @@ impl LinksTree for ExternalTargetsRecursionlessTree { fn attach(&mut self, root: &mut T, index: T) { unsafe { NoRecurSzbTree::attach(self, root as *mut _, index) } } + + fn detach_with_mem(&mut self, _mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Split trees don't use unit memory, so just delegate to normal detach + self.detach(root, index) + } + + fn attach_with_mem(&mut self, _mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Split trees don't use unit memory, so just delegate to normal attach + self.attach(root, index) + } } impl SplitUpdateMem for ExternalTargetsRecursionlessTree { diff --git a/doublets/src/mem/split/generic/internal_sources_recursion_less_tree.rs b/doublets/src/mem/split/generic/internal_sources_recursion_less_tree.rs index d9bd0c6..f55c517 100644 --- a/doublets/src/mem/split/generic/internal_sources_recursion_less_tree.rs +++ b/doublets/src/mem/split/generic/internal_sources_recursion_less_tree.rs @@ -129,6 +129,16 @@ impl LinksTree for InternalSourcesRecursionlessTree { fn attach(&mut self, root: &mut T, index: T) { unsafe { NoRecurSzbTree::attach(self, root as *mut _, index) } } + + fn detach_with_mem(&mut self, _mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Split trees don't use unit memory, so just delegate to normal detach + self.detach(root, index) + } + + fn attach_with_mem(&mut self, _mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Split trees don't use unit memory, so just delegate to normal attach + self.attach(root, index) + } } impl SplitUpdateMem for InternalSourcesRecursionlessTree { diff --git a/doublets/src/mem/split/generic/internal_targets_recursion_less_tree.rs b/doublets/src/mem/split/generic/internal_targets_recursion_less_tree.rs index f46dc4f..0a42840 100644 --- a/doublets/src/mem/split/generic/internal_targets_recursion_less_tree.rs +++ b/doublets/src/mem/split/generic/internal_targets_recursion_less_tree.rs @@ -136,6 +136,16 @@ impl LinksTree for InternalTargetsRecursionlessTree { fn attach(&mut self, root: &mut T, index: T) { unsafe { NoRecurSzbTree::attach(self, root as *mut _, index) } } + + fn detach_with_mem(&mut self, _mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Split trees don't use unit memory, so just delegate to normal detach + self.detach(root, index) + } + + fn attach_with_mem(&mut self, _mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Split trees don't use unit memory, so just delegate to normal attach + self.attach(root, index) + } } impl SplitUpdateMem for InternalTargetsRecursionlessTree { diff --git a/doublets/src/mem/traits.rs b/doublets/src/mem/traits.rs index dd8df6f..62e3980 100644 --- a/doublets/src/mem/traits.rs +++ b/doublets/src/mem/traits.rs @@ -16,6 +16,11 @@ pub trait LinksTree { fn detach(&mut self, root: &mut T, index: T); fn attach(&mut self, root: &mut T, index: T); + + // New methods that accept memory explicitly to avoid stacked borrows issues + fn detach_with_mem(&mut self, mem: NonNull<[LinkPart]>, root: &mut T, index: T); + + fn attach_with_mem(&mut self, mem: NonNull<[LinkPart]>, root: &mut T, index: T); } pub trait UnitUpdateMem { diff --git a/doublets/src/mem/unit/generic/sources_recursionless_size_balanced_tree.rs b/doublets/src/mem/unit/generic/sources_recursionless_size_balanced_tree.rs index 8dd920c..bc142a0 100644 --- a/doublets/src/mem/unit/generic/sources_recursionless_size_balanced_tree.rs +++ b/doublets/src/mem/unit/generic/sources_recursionless_size_balanced_tree.rs @@ -191,6 +191,22 @@ impl LinksTree for LinksSourcesRecursionlessSizeBalancedTree fn attach(&mut self, root: &mut T, index: T) { unsafe { NoRecurSzbTree::attach(self, root as *mut _, index) } } + + fn detach_with_mem(&mut self, mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Temporarily update memory reference to avoid stacked borrows + let old_mem = self.base.mem; + self.base.mem = mem; + unsafe { NoRecurSzbTree::detach(self, root as *mut _, index) } + self.base.mem = old_mem; + } + + fn attach_with_mem(&mut self, mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Temporarily update memory reference to avoid stacked borrows + let old_mem = self.base.mem; + self.base.mem = mem; + unsafe { NoRecurSzbTree::attach(self, root as *mut _, index) } + self.base.mem = old_mem; + } } impl UnitUpdateMem for LinksSourcesRecursionlessSizeBalancedTree { diff --git a/doublets/src/mem/unit/generic/targets_recursionless_size_balanced_tree.rs b/doublets/src/mem/unit/generic/targets_recursionless_size_balanced_tree.rs index 2867d20..557df2d 100644 --- a/doublets/src/mem/unit/generic/targets_recursionless_size_balanced_tree.rs +++ b/doublets/src/mem/unit/generic/targets_recursionless_size_balanced_tree.rs @@ -191,6 +191,22 @@ impl LinksTree for LinksTargetsRecursionlessSizeBalancedTree fn attach(&mut self, root: &mut T, index: T) { unsafe { NoRecurSzbTree::attach(self, root as *mut _, index) } } + + fn detach_with_mem(&mut self, mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Temporarily update memory reference to avoid stacked borrows + let old_mem = self.base.mem; + self.base.mem = mem; + unsafe { NoRecurSzbTree::detach(self, root as *mut _, index) } + self.base.mem = old_mem; + } + + fn attach_with_mem(&mut self, mem: NonNull<[LinkPart]>, root: &mut T, index: T) { + // Temporarily update memory reference to avoid stacked borrows + let old_mem = self.base.mem; + self.base.mem = mem; + unsafe { NoRecurSzbTree::attach(self, root as *mut _, index) } + self.base.mem = old_mem; + } } impl UnitUpdateMem for LinksTargetsRecursionlessSizeBalancedTree { diff --git a/doublets/src/mem/unit/store.rs b/doublets/src/mem/unit/store.rs index 5231732..ef51908 100644 --- a/doublets/src/mem/unit/store.rs +++ b/doublets/src/mem/unit/store.rs @@ -151,19 +151,27 @@ impl>, TS: UnitTree, TT: UnitTree, TU: } unsafe fn detach_source_unchecked(&mut self, root: *mut T, index: T) { - self.sources.detach(&mut *root, index); + // Get memory pointer first to avoid overlapping borrows + let mem_ptr = self.mem_ptr; + self.sources.detach_with_mem(mem_ptr, &mut *root, index); } unsafe fn detach_target_unchecked(&mut self, root: *mut T, index: T) { - self.targets.detach(&mut *root, index); + // Get memory pointer first to avoid overlapping borrows + let mem_ptr = self.mem_ptr; + self.targets.detach_with_mem(mem_ptr, &mut *root, index); } unsafe fn attach_source_unchecked(&mut self, root: *mut T, index: T) { - self.sources.attach(&mut *root, index); + // Get memory pointer first to avoid overlapping borrows + let mem_ptr = self.mem_ptr; + self.sources.attach_with_mem(mem_ptr, &mut *root, index); } unsafe fn attach_target_unchecked(&mut self, root: *mut T, index: T) { - self.targets.attach(&mut *root, index); + // Get memory pointer first to avoid overlapping borrows + let mem_ptr = self.mem_ptr; + self.targets.attach_with_mem(mem_ptr, &mut *root, index); } unsafe fn detach_source(&mut self, index: T) {