From 9572a823c4fad1d6afed54a16535b229b607316b Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Mon, 20 Jan 2025 17:47:17 +0100 Subject: [PATCH 1/8] Check VeriFast proofs --- .github/workflows/verifast.yml | 41 + verifast-proofs/.gitignore | 2 + .../collections/check-verifast-proofs.mysh | 4 + .../collections/linked_list.code-changes.diff | 1212 +++++ .../alloc/collections/linked_list.original.rs | 2243 ++++++++++ .../collections/linked_list.verifast-proof.rs | 3982 +++++++++++++++++ verifast-proofs/check-verifast-proofs.mysh | 5 + 7 files changed, 7489 insertions(+) create mode 100644 .github/workflows/verifast.yml create mode 100644 verifast-proofs/.gitignore create mode 100644 verifast-proofs/alloc/collections/check-verifast-proofs.mysh create mode 100644 verifast-proofs/alloc/collections/linked_list.code-changes.diff create mode 100644 verifast-proofs/alloc/collections/linked_list.original.rs create mode 100644 verifast-proofs/alloc/collections/linked_list.verifast-proof.rs create mode 100644 verifast-proofs/check-verifast-proofs.mysh diff --git a/.github/workflows/verifast.yml b/.github/workflows/verifast.yml new file mode 100644 index 0000000000000..c87b7cbe91674 --- /dev/null +++ b/.github/workflows/verifast.yml @@ -0,0 +1,41 @@ +name: VeriFast + +on: + workflow_dispatch: + merge_group: + pull_request: + branches: [ main ] + push: + paths: + - 'library/**' + - '.github/workflows/verifast.yml' + - 'verifast-proofs/**' + +defaults: + run: + shell: bash + +jobs: + check-verifast-on-std: + name: Verify std library + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + path: head + submodules: true + + - name: Install VeriFast + run: | + cd ~ + curl -OL https://github.com/verifast/verifast/releases/download/24.12/verifast-24.12-linux.tar.gz + echo '51bebf990f31666abcd3675000e7714ef79b417390e930953ef25383e8d59421 verifast-24.12-linux.tar.gz' | shasum -a 256 -c + tar xf verifast-24.12-linux.tar.gz + + - name: Run VeriFast Verification + run: | + export PATH=~/verifast-24.12/bin:$PATH + cd verifast-proofs + mysh check-verifast-proofs.mysh diff --git a/verifast-proofs/.gitignore b/verifast-proofs/.gitignore new file mode 100644 index 0000000000000..58c1ca59715c0 --- /dev/null +++ b/verifast-proofs/.gitignore @@ -0,0 +1,2 @@ +*.stripped.rs +*.computed.diff diff --git a/verifast-proofs/alloc/collections/check-verifast-proofs.mysh b/verifast-proofs/alloc/collections/check-verifast-proofs.mysh new file mode 100644 index 0000000000000..7921cd576d172 --- /dev/null +++ b/verifast-proofs/alloc/collections/check-verifast-proofs.mysh @@ -0,0 +1,4 @@ +diff linked_list.original.rs ../../../library/alloc/src/collections/linked_list.rs +vfstrip < linked_list.verifast-proof.rs > linked_list.verifast-proof.stripped.rs +diff linked_list.original.rs linked_list.verifast-proof.stripped.rs > linked_list.code-changes.computed.diff; diff linked_list.code-changes.diff linked_list.code-changes.computed.diff +verifast -rustc_arg --crate-name -rustc_arg linked_list -c -prover z3v4.5 -skip_specless_fns linked_list.verifast-proof.rs diff --git a/verifast-proofs/alloc/collections/linked_list.code-changes.diff b/verifast-proofs/alloc/collections/linked_list.code-changes.diff new file mode 100644 index 0000000000000..5302806a2ed5c --- /dev/null +++ b/verifast-proofs/alloc/collections/linked_list.code-changes.diff @@ -0,0 +1,1212 @@ +0a1,2 +> // verifast_options{prover:z3v4.5 skip_specless_fns} +> +13c15 +< #![stable(feature = "rust1", since = "1.0.0")] +--- +> // This is a slightly tweaked version of https://github.com/rust-lang/rust/blob/c290e9de32e8ba6a673ef125fde40eadd395d170/library/alloc/src/collections/linked_list.rs +14a17,28 +> //#![stable(feature = "rust1", since = "1.0.0")] +> #![feature(rustc_attrs)] +> #![feature(dropck_eyepatch)] +> #![feature(specialization)] +> #![feature(allocator_api)] +> #![feature(extend_one)] +> #![feature(exact_size_is_empty)] +> #![feature(hasher_prefixfree_extras)] +> #![feature(box_into_inner)] +> +> use std as core; +> +15a30 +> use core::fmt; +16a32 +> use core::iter::FromIterator; +18a35 +> use core::mem; +20d36 +< use core::{fmt, mem}; +22,24c38,39 +< use super::SpecExtend; +< use crate::alloc::{Allocator, Global}; +< use crate::boxed::Box; +--- +> use std::alloc::{Allocator, Global}; +> use std::boxed::Box; +25a41 +> +28a45,48 +> trait SpecExtend { +> fn spec_extend(&mut self, iter: I); +> } +> +47,48c67,68 +< #[stable(feature = "rust1", since = "1.0.0")] +< #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +> //#[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] +52c72 +< #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +--- +> /*#[unstable(feature = "allocator_api", issue = "32838")]*/ A: Allocator = Global, +70c90 +< /// documentation for more. +--- +> /// documentation for more. +72c92 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +80,94c100,114 +< #[stable(feature = "collection_debug", since = "1.17.0")] +< impl fmt::Debug for Iter<'_, T> { +< fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +< f.debug_tuple("Iter") +< .field(&*mem::ManuallyDrop::new(LinkedList { +< head: self.head, +< tail: self.tail, +< len: self.len, +< alloc: Global, +< marker: PhantomData, +< })) +< .field(&self.len) +< .finish() +< } +< } +--- +> //#[stable(feature = "collection_debug", since = "1.17.0")] +> // impl fmt::Debug for Iter<'_, T> { +> // fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +> // f.debug_tuple("Iter") +> // .field(&*mem::ManuallyDrop::new(LinkedList { +> // head: self.head, +> // tail: self.tail, +> // len: self.len, +> // alloc: Global, +> // marker: PhantomData, +> // })) +> // .field(&self.len) +> // .finish() +> // } +> // } +97c117 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +109c129 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +117,131c137,151 +< #[stable(feature = "collection_debug", since = "1.17.0")] +< impl fmt::Debug for IterMut<'_, T> { +< fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +< f.debug_tuple("IterMut") +< .field(&*mem::ManuallyDrop::new(LinkedList { +< head: self.head, +< tail: self.tail, +< len: self.len, +< alloc: Global, +< marker: PhantomData, +< })) +< .field(&self.len) +< .finish() +< } +< } +--- +> //#[stable(feature = "collection_debug", since = "1.17.0")] +> // impl fmt::Debug for IterMut<'_, T> { +> // fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +> // f.debug_tuple("IterMut") +> // .field(&*mem::ManuallyDrop::new(LinkedList { +> // head: self.head, +> // tail: self.tail, +> // len: self.len, +> // alloc: Global, +> // marker: PhantomData, +> // })) +> // .field(&self.len) +> // .finish() +> // } +> // } +140c160 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +143c163 +< #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +--- +> /*#[unstable(feature = "allocator_api", issue = "32838")]*/ A: Allocator = Global, +148,153c168,173 +< #[stable(feature = "collection_debug", since = "1.17.0")] +< impl fmt::Debug for IntoIter { +< fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +< f.debug_tuple("IntoIter").field(&self.list).finish() +< } +< } +--- +> //#[stable(feature = "collection_debug", since = "1.17.0")] +> // impl fmt::Debug for IntoIter { +> // fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +> // f.debug_tuple("IntoIter").field(&self.list).finish() +> // } +> // } +156c176,177 +< fn new(element: T) -> Self { +--- +> unsafe fn new(element: T) -> Self +> { +160,161c181,183 +< fn into_element(self: Box) -> T { +< self.element +--- +> unsafe fn into_element(self: Box) -> T +> { +> Box::into_inner(self).element // self.element +173c195,196 +< unsafe fn push_front_node(&mut self, node: NonNull>) { +--- +> unsafe fn push_front_node(&mut self, node: NonNull>) +> { +179c202 +< let node = Some(node); +--- +> let node_ = Some(node); +182c205,207 +< None => self.tail = node, +--- +> None => { +> self.tail = node_ +> } +184c209,211 +< Some(head) => (*head.as_ptr()).prev = node, +--- +> Some(head) => { +> (*head.as_ptr()).prev = node_; +> } +187c214 +< self.head = node; +--- +> self.head = node_; +194c221,222 +< fn pop_front_node(&mut self) -> Option, &A>> { +--- +> unsafe fn pop_front_node<'a>(&'a mut self) -> Option, &'a A>> +> { +197,199c225,229 +< self.head.map(|node| unsafe { +< let node = Box::from_raw_in(node.as_ptr(), &self.alloc); +< self.head = node.next; +--- +> match self.head { +> None => None, +> Some(node) => unsafe { +> self.head = (*node.as_ptr()).next; +> let node_ = Box::from_raw_in(node.as_ptr(), &self.alloc); +201,205c231,235 +< match self.head { +< None => self.tail = None, +< // Not creating new mutable (unique!) references overlapping `element`. +< Some(head) => (*head.as_ptr()).prev = None, +< } +--- +> match self.head { +> None => self.tail = None, +> // Not creating new mutable (unique!) references overlapping `element`. +> Some(head) => (*head.as_ptr()).prev = None, +> } +207,209c237,240 +< self.len -= 1; +< node +< }) +--- +> self.len -= 1; +> Some(node_) +> } +> } +224c255 +< let node = Some(node); +--- +> let node_ = Some(node); +227c258 +< None => self.head = node, +--- +> None => self.head = node_, +229c260 +< Some(tail) => (*tail.as_ptr()).next = node, +--- +> Some(tail) => (*tail.as_ptr()).next = node_, +232c263 +< self.tail = node; +--- +> self.tail = node_; +242,244c273,277 +< self.tail.map(|node| unsafe { +< let node = Box::from_raw_in(node.as_ptr(), &self.alloc); +< self.tail = node.prev; +--- +> match self.tail { +> None => None, +> Some(node) => unsafe { +> let node_ = Box::from_raw_in(node.as_ptr(), &self.alloc); +> self.tail = node_.prev; +246,250c279,283 +< match self.tail { +< None => self.head = None, +< // Not creating new mutable (unique!) references overlapping `element`. +< Some(tail) => (*tail.as_ptr()).next = None, +< } +--- +> match self.tail { +> None => self.head = None, +> // Not creating new mutable (unique!) references overlapping `element`. +> Some(tail) => (*tail.as_ptr()).next = None, +> } +252,254c285,288 +< self.len -= 1; +< node +< }) +--- +> self.len -= 1; +> Some(node_) +> } +> } +264,265c298,300 +< unsafe fn unlink_node(&mut self, mut node: NonNull>) { +< let node = unsafe { node.as_mut() }; // this one is ours now, we can create an &mut. +--- +> unsafe fn unlink_node(&mut self, mut node: NonNull>) +> { +> let node_ = unsafe { node.as_mut() }; // this one is ours now, we can create an &mut. +268,269c303,306 +< match node.prev { +< Some(prev) => unsafe { (*prev.as_ptr()).next = node.next }, +--- +> match node_.prev { +> Some(prev) => unsafe { +> (*prev.as_ptr()).next = node_.next; +> }, +271c308,310 +< None => self.head = node.next, +--- +> None => { +> self.head = node_.next +> } +274,275c313,316 +< match node.next { +< Some(next) => unsafe { (*next.as_ptr()).prev = node.prev }, +--- +> match node_.next { +> Some(next) => unsafe { +> (*next.as_ptr()).prev = node_.prev; +> }, +277c318,321 +< None => self.tail = node.prev, +--- +> None => { +> self.tail = node_.prev; +> +> } +297c341 +< if let Some(mut existing_prev) = existing_prev { +--- +> if let Some(mut existing_prev_) = existing_prev { +299c343 +< existing_prev.as_mut().next = Some(splice_start); +--- +> existing_prev_.as_mut().next = Some(splice_start); +304c348 +< if let Some(mut existing_next) = existing_next { +--- +> if let Some(mut existing_next_) = existing_next { +306c350 +< existing_next.as_mut().prev = Some(splice_end); +--- +> existing_next_.as_mut().prev = Some(splice_end); +390c434 +< if let Some(mut split_node) = split_node { +--- +> if let Some(mut split_node_) = split_node { +394c438 +< second_part_head = split_node.as_mut().next.take(); +--- +> second_part_head = split_node_.as_mut().next.take(); +409c453 +< alloc: self.alloc.clone(), +--- +> alloc: clone_allocator(&self.alloc), +414c458 +< self.tail = Some(split_node); +--- +> self.tail = Some(split_node_); +416d459 +< +419c462,464 +< mem::replace(self, LinkedList::new_in(self.alloc.clone())) +--- +> let alloc = clone_allocator(&self.alloc); +> let r = LinkedList::new_in(alloc); +> mem::replace(self, r) +424c469,474 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> unsafe fn clone_allocator<'a, A: Allocator + Clone>(alloc: &'a A) -> A +> { +> alloc.clone() //~allow_dead_code +> } //~allow_dead_code +> +> //#[stable(feature = "rust1", since = "1.0.0")] +444,445c494,495 +< #[rustc_const_stable(feature = "const_linked_list_new", since = "1.39.0")] +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> /*#[rustc_const_stable(feature = "const_linked_list_new", since = "1.39.0")]*/ +> //#[stable(feature = "rust1", since = "1.0.0")] +447,448c497,500 +< pub const fn new() -> Self { +< LinkedList { head: None, tail: None, len: 0, alloc: Global, marker: PhantomData } +--- +> pub const fn new() -> Self +> { +> let r = LinkedList { head: None, tail: None, len: 0, alloc: Global, marker: PhantomData }; +> r +480c532 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +515,517c567,571 +< #[unstable(feature = "allocator_api", issue = "32838")] +< pub const fn new_in(alloc: A) -> Self { +< LinkedList { head: None, tail: None, len: 0, alloc, marker: PhantomData } +--- +> /*#[unstable(feature = "allocator_api", issue = "32838")]*/ +> pub const fn new_in(alloc: A) -> Self +> { +> let r = LinkedList { head: None, tail: None, len: 0, alloc, marker: PhantomData }; +> r +539,541c593,597 +< #[stable(feature = "rust1", since = "1.0.0")] +< pub fn iter(&self) -> Iter<'_, T> { +< Iter { head: self.head, tail: self.tail, len: self.len, marker: PhantomData } +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +> pub fn iter<'a>(&'a self) -> Iter<'a, T> +> { +> let r = Iter { head: self.head, tail: self.tail, len: self.len, marker: PhantomData }; +> r +568c624 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +578c634 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +588,590c644,648 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T, A> { +< CursorMut { index: 0, current: self.head, list: self } +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +> pub fn cursor_front_mut<'a>(&'a mut self) -> CursorMut<'a, T, A> +> { +> let r = CursorMut { index: 0, current: self.head, list: self }; +> r +598c656 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +608,610c666,670 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T, A> { +< CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self } +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +> pub fn cursor_back_mut<'a>(&'a mut self) -> CursorMut<'a, T, A> +> { +> let r = CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }; +> r +630c690 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +657c717 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +684,685c744,746 +< #[stable(feature = "rust1", since = "1.0.0")] +< pub fn clear(&mut self) { +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +> pub fn clear(&mut self) +> { +688,694c749,758 +< drop(LinkedList { +< head: self.head.take(), +< tail: self.tail.take(), +< len: mem::take(&mut self.len), +< alloc: &self.alloc, +< marker: PhantomData, +< }); +--- +> { +> let ll = LinkedList { +> head: self.head.take(), +> tail: self.tail.take(), +> len: mem::replace(&mut self.len, 0), //mem::take(&mut self.len), +> alloc: &self.alloc, +> marker: PhantomData, +> }; +> drop(ll); +> } +716c780 +< #[stable(feature = "linked_list_contains", since = "1.12.0")] +--- +> //#[stable(feature = "linked_list_contains", since = "1.12.0")] +742c806 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +772c836 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +795c859 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +823c887 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +845,849c909,911 +< #[stable(feature = "rust1", since = "1.0.0")] +< pub fn push_front(&mut self, elt: T) { +< let node = Box::new_in(Node::new(elt), &self.alloc); +< let node_ptr = NonNull::from(Box::leak(node)); +< // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +> pub fn push_front(&mut self, elt: T) +> { +850a913,915 +> let node = Box::new_in(Node::new(elt), &self.alloc); +> let node_ptr = NonNull::new_unchecked(Box::leak(node) as *mut Node); //NonNull::from(Box::leak(node)); +> // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked +874,876c939,952 +< #[stable(feature = "rust1", since = "1.0.0")] +< pub fn pop_front(&mut self) -> Option { +< self.pop_front_node().map(Node::into_element) +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +> pub fn pop_front(&mut self) -> Option +> { +> unsafe { +> match self.pop_front_node() { //.map(Node::into_element) +> None => { +> None +> } +> Some(node) => { +> let r = Some(node.into_element()); +> r +> } +> } +> } +893c969 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +896,898d971 +< let node = Box::new_in(Node::new(elt), &self.alloc); +< let node_ptr = NonNull::from(Box::leak(node)); +< // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked +899a973,975 +> let node = Box::new_in(Node::new(elt), &self.alloc); +> let node_ptr = NonNull::from(Box::leak(node)); +> // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked +920c996 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +922c998,1003 +< self.pop_back_node().map(Node::into_element) +--- +> unsafe { +> match self.pop_back_node() { //.map(Node::into_element) +> None => None, +> Some(node) => Some(node.into_element()) +> } +> } +950c1031 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +955,971c1036,1044 +< let len = self.len(); +< assert!(at <= len, "Cannot split off at a nonexistent index"); +< if at == 0 { +< return mem::replace(self, Self::new_in(self.alloc.clone())); +< } else if at == len { +< return Self::new_in(self.alloc.clone()); +< } +< +< // Below, we iterate towards the `i-1`th node, either from the start or the end, +< // depending on which would be faster. +< let split_node = if at - 1 <= len - 1 - (at - 1) { +< let mut iter = self.iter_mut(); +< // instead of skipping using .skip() (which creates a new struct), +< // we skip manually so we can access the head field without +< // depending on implementation details of Skip +< for _ in 0..at - 1 { +< iter.next(); +--- +> unsafe { +> let len = self.len; +> assert!(at <= len, "Cannot split off at a nonexistent index"); +> if at == 0 { +> let alloc1 = clone_allocator(&self.alloc); +> return mem::replace(self, Self::new_in(alloc1)); +> } else if at == len { +> let alloc2 = clone_allocator(&self.alloc); +> return Self::new_in(alloc2); +973,982c1046,1076 +< iter.head +< } else { +< // better off starting from the end +< let mut iter = self.iter_mut(); +< for _ in 0..len - 1 - (at - 1) { +< iter.next_back(); +< } +< iter.tail +< }; +< unsafe { self.split_off_after_node(split_node, at) } +--- +> +> // Below, we iterate towards the `i-1`th node, either from the start or the end, +> // depending on which would be faster. +> let mut iter; +> let mut i; +> let split_node = if at - 1 <= len - 1 - (at - 1) { +> iter = self.head; +> i = 0; +> loop { +> if i == at - 1 { +> break; +> } +> iter = (*iter.unwrap_unchecked().as_ptr()).next; +> i += 1; +> } +> iter +> } else { +> // better off starting from the end +> iter = self.tail; +> i = 0; +> loop { // for _ in 0..len - 1 - (at - 1) { +> if i == len - 1 - (at - 1) { +> break; +> } +> iter = (*iter.unwrap_unchecked().as_ptr()).prev; +> i += 1; +> } +> iter +> }; +> unsafe { self.split_off_after_node(split_node, at) } +> } +1008c1102 +< #[unstable(feature = "linked_list_remove", issue = "69210")] +--- +> /*#[unstable(feature = "linked_list_remove", issue = "69210")]*/ +1075c1169 +< #[unstable(feature = "linked_list_retain", issue = "114135")] +--- +> /*#[unstable(feature = "linked_list_retain", issue = "114135")]*/ +1085c1179 +< /// In other words, remove all elements `e` for which `f(&mut e)` returns false. +--- +> /// In other words, remove all elements `e` for which `f(&e)` returns false. +1110c1204 +< #[unstable(feature = "linked_list_retain", issue = "114135")] +--- +> /*#[unstable(feature = "linked_list_retain", issue = "114135")]*/ +1155,1156c1249,1250 +< #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +< pub fn extract_if(&mut self, filter: F) -> ExtractIf<'_, T, F, A> +--- +> /*#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]*/ +> pub fn extract_if<'a, F>(&'a mut self, filter: F) -> ExtractIf<'a, T, F, A> +1159a1254 +> +1162a1258 +> +1164c1260,1261 +< ExtractIf { list: self, it, pred: filter, idx: 0, old_len } +--- +> let r = ExtractIf { list: self, it, pred: filter, idx: 0, old_len }; +> r +1168,1171c1265 +< #[stable(feature = "rust1", since = "1.0.0")] +< unsafe impl<#[may_dangle] T, A: Allocator> Drop for LinkedList { +< fn drop(&mut self) { +< struct DropGuard<'a, T, A: Allocator>(&'a mut LinkedList); +--- +> struct DropGuard<'a, T, A: Allocator>(&'a mut LinkedList); +1173,1178c1267,1272 +< impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { +< fn drop(&mut self) { +< // Continue the same loop we do below. This only runs when a destructor has +< // panicked. If another one panics this will abort. +< while self.0.pop_front_node().is_some() {} +< } +--- +> impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { +> fn drop(&mut self) { +> unsafe { +> // Continue the same loop we do below. This only runs when a destructor has +> // panicked. If another one panics this will abort. +> while self.0.pop_front_node().is_some() {} +1179a1274,1275 +> } +> } +1181,1184c1277,1292 +< // Wrap self so that if a destructor panics, we can try to keep looping +< let guard = DropGuard(self); +< while guard.0.pop_front_node().is_some() {} +< mem::forget(guard); +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +> unsafe impl<#[may_dangle] T, A: Allocator> Drop for LinkedList { +> fn drop(&mut self) +> { +> unsafe { +> // Wrap self so that if a destructor panics, we can try to keep looping +> let guard = DropGuard(self); +> loop { +> match guard.0.pop_front() { +> None => { break; } +> Some(element) => { +> } +> } +> } +> mem::forget(guard); +> } +1188c1296 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +1193c1301,1302 +< fn next(&mut self) -> Option<&'a T> { +--- +> fn next(&mut self) -> Option<&'a T> +> { +1197,1203c1306,1319 +< self.head.map(|node| unsafe { +< // Need an unbound lifetime to get 'a +< let node = &*node.as_ptr(); +< self.len -= 1; +< self.head = node.next; +< &node.element +< }) +--- +> match self.head { //.map(|node| unsafe { +> None => { +> None +> } +> Some(node_) => unsafe { +> // Need an unbound lifetime to get 'a +> let node = node_.as_ptr(); //&*node_.as_ptr(); +> let len = self.len; +> self.len = len - 1; +> self.head = (*node).next; +> let r = &(*node).element; +> Some(r) +> } +> } +1218c1334 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +1236c1352 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +1239c1355 +< #[stable(feature = "fused", since = "1.26.0")] +--- +> //#[stable(feature = "fused", since = "1.26.0")] +1242c1358 +< #[stable(feature = "default_iters", since = "1.70.0")] +--- +> //#[stable(feature = "default_iters", since = "1.70.0")] +1256c1372 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +1286c1402 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +1304c1420 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +1307c1423 +< #[stable(feature = "fused", since = "1.26.0")] +--- +> //#[stable(feature = "fused", since = "1.26.0")] +1310c1426 +< #[stable(feature = "default_iters", since = "1.70.0")] +--- +> //#[stable(feature = "default_iters", since = "1.70.0")] +1326c1442 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1330c1446 +< #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +--- +> /*#[unstable(feature = "allocator_api", issue = "32838")]*/ A: Allocator = Global, +1337c1453 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1345c1461 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1362c1478 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1366c1482 +< #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +--- +> /*#[unstable(feature = "allocator_api", issue = "32838")]*/ A: Allocator = Global, +1373c1489 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1386c1502 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1397c1513 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1419c1535 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1441c1557 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1452c1568 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1469c1585 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1483c1599 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1492c1608 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1497,1504d1612 +< +< /// Provides a reference to the cursor's parent list. +< #[must_use] +< #[inline(always)] +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< pub fn as_list(&self) -> &'a LinkedList { +< self.list +< } +1513c1621 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1524,1525c1632,1634 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< pub fn move_next(&mut self) { +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +> pub fn move_next(&mut self) +> { +1535c1644 +< self.current = current.as_ref().next; +--- +> self.current = (*current.as_ptr()).next; //current.as_ref().next; +1538c1647 +< } +--- +> }; +1546,1547c1655,1657 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< pub fn move_prev(&mut self) { +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +> pub fn move_prev(&mut self) +> { +1552c1662 +< self.index = self.list.len().checked_sub(1).unwrap_or(0); +--- +> self.index = self.list.len.checked_sub(1).unwrap_or(0); +1556,1557c1666,1674 +< self.current = current.as_ref().prev; +< self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); +--- +> self.current = (*current.as_ptr()).prev; //current.as_ref().prev; +> match self.index.checked_sub(1) { // self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); +> None => { +> self.index = self.list.len; +> } +> Some(index1) => { +> self.index = index1; +> } +> } +1568,1570c1685,1697 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< pub fn current(&mut self) -> Option<&mut T> { +< unsafe { self.current.map(|current| &mut (*current.as_ptr()).element) } +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +> pub fn current<'b>(&'b mut self) -> Option<&'b mut T> +> { +> unsafe { +> match self.current { //self.current.map(|current| &mut (*current.as_ptr()).element) +> None => { +> None +> } +> Some(current) => { +> Some(&mut (*current.as_ptr()).element) +> } +> } +> } +1578c1705 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1594c1721 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1611c1738 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1614,1625d1740 +< } +< +< /// Provides a read-only reference to the cursor's parent list. +< /// +< /// The lifetime of the returned reference is bound to that of the +< /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the +< /// `CursorMut` is frozen for the lifetime of the reference. +< #[must_use] +< #[inline(always)] +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< pub fn as_list(&self) -> &LinkedList { +< self.list +1636c1751 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1659c1774 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1681c1796 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1701c1816 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1721,1728c1836,1851 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< pub fn remove_current(&mut self) -> Option { +< let unlinked_node = self.current?; +< unsafe { +< self.current = unlinked_node.as_ref().next; +< self.list.unlink_node(unlinked_node); +< let unlinked_node = Box::from_raw_in(unlinked_node.as_ptr(), &self.list.alloc); +< Some(unlinked_node.element) +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +> pub fn remove_current(&mut self) -> Option +> { +> //let unlinked_node = self.current?; +> match self.current { +> None => { +> None +> } +> Some(unlinked_node) => unsafe { +> +> self.current = (*unlinked_node.as_ptr()).next; //unlinked_node.as_ref().next; +> self.list.unlink_node(unlinked_node); +> let unlinked_node_ = Box::from_raw_in(unlinked_node.as_ptr(), &self.list.alloc); +> let r = Some(Box::into_inner(unlinked_node_).element); // Some(unlinked_node_.element) +> r +> } +1739c1862 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1767c1890 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1786c1909 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1802c1925 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1815c1938 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1835c1958 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1862c1985 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1883c2006 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1892c2015 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1900c2023 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1928c2051 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +1935c2058 +< #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +--- +> /*#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]*/ +1941c2064 +< #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +--- +> /*#[unstable(feature = "allocator_api", issue = "32838")]*/ A: Allocator = Global, +1952,1953c2075,2081 +< #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +< impl Iterator for ExtractIf<'_, T, F, A> +--- +> fn call_pred bool>(f: &mut F, element: &mut T) -> bool +> { +> f(element) //~allow_dead_code +> } //~allow_dead_code +> +> /*#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]*/ +> impl<'a, T, F, A: Allocator> Iterator for ExtractIf<'a, T, F, A> +1959,1963c2087,2095 +< fn next(&mut self) -> Option { +< while let Some(mut node) = self.it { +< unsafe { +< self.it = node.as_ref().next; +< self.idx += 1; +--- +> fn next(&mut self) -> Option +> { +> loop { //while let Some(mut node) = self.it { +> match self.it { +> None => break, +> Some(mut node) => unsafe { +> self.it = (*node.as_ptr()).next; //node.as_ref().next; +> self.idx += 1; +> +1965,1968c2097,2103 +< if (self.pred)(&mut node.as_mut().element) { +< // `unlink_node` is okay with aliasing `element` references. +< self.list.unlink_node(node); +< return Some(Box::from_raw_in(node.as_ptr(), &self.list.alloc).element); +--- +> if call_pred(&mut self.pred, &mut node.as_mut().element) { +> // `unlink_node` is okay with aliasing `element` references. +> self.list.unlink_node(node); +> let r = Some(Box::into_inner(Box::from_raw_in(node.as_ptr(), &self.list.alloc)).element); +> return r +> } +> +1972d2106 +< +1981c2115 +< #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +--- +> /*#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]*/ +1991c2125 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2006c2140 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2014c2148 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2017c2151 +< #[stable(feature = "fused", since = "1.26.0")] +--- +> //#[stable(feature = "fused", since = "1.26.0")] +2020c2154 +< #[stable(feature = "default_iters", since = "1.70.0")] +--- +> //#[stable(feature = "default_iters", since = "1.70.0")] +2034c2168 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2043c2177 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2055c2189 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2065c2199 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2075c2209 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2099c2233 +< #[stable(feature = "extend_ref", since = "1.2.0")] +--- +> //#[stable(feature = "extend_ref", since = "1.2.0")] +2111c2245 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2122c2256 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2125c2259 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2132c2266 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2140c2274 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2168c2302 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2175c2309 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2185c2319 +< #[stable(feature = "std_collections_from_array", since = "1.56.0")] +--- +> //#[stable(feature = "std_collections_from_array", since = "1.56.0")] +2203,2212c2337,2338 +< fn assert_covariance() { +< fn a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> { +< x +< } +< fn b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> { +< x +< } +< fn c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> { +< x +< } +--- +> fn assert_covariance_a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> { +> x +2215c2341,2351 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> #[allow(dead_code)] +> fn assert_covariance_b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> { +> x +> } +> +> #[allow(dead_code)] +> fn assert_covariance_c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> { +> x +> } +> +> //#[stable(feature = "rust1", since = "1.0.0")] +2218c2354 +< #[stable(feature = "rust1", since = "1.0.0")] +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +2221,2222c2357,2358 +< #[stable(feature = "rust1", since = "1.0.0")] +< unsafe impl Send for Iter<'_, T> {} +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +> unsafe impl<'a, T: Sync> Send for Iter<'a, T> {} +2224,2225c2360,2361 +< #[stable(feature = "rust1", since = "1.0.0")] +< unsafe impl Sync for Iter<'_, T> {} +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +> unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {} +2227,2228c2363,2364 +< #[stable(feature = "rust1", since = "1.0.0")] +< unsafe impl Send for IterMut<'_, T> {} +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +> unsafe impl<'a, T: Send> Send for IterMut<'a, T> {} +2230,2231c2366,2367 +< #[stable(feature = "rust1", since = "1.0.0")] +< unsafe impl Sync for IterMut<'_, T> {} +--- +> //#[stable(feature = "rust1", since = "1.0.0")] +> unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {} +2233,2234c2369,2370 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< unsafe impl Send for Cursor<'_, T, A> {} +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +> unsafe impl<'a, T: Sync, A: Allocator + Sync> Send for Cursor<'a, T, A> {} +2236,2237c2372,2373 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< unsafe impl Sync for Cursor<'_, T, A> {} +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +> unsafe impl<'a, T: Sync, A: Allocator + Sync> Sync for Cursor<'a, T, A> {} +2239,2240c2375,2376 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< unsafe impl Send for CursorMut<'_, T, A> {} +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +> unsafe impl<'a, T: Send, A: Allocator + Send> Send for CursorMut<'a, T, A> {} +2242,2243c2378,2379 +< #[unstable(feature = "linked_list_cursors", issue = "58533")] +< unsafe impl Sync for CursorMut<'_, T, A> {} +--- +> /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +> unsafe impl<'a, T: Sync, A: Allocator + Sync> Sync for CursorMut<'a, T, A> {} diff --git a/verifast-proofs/alloc/collections/linked_list.original.rs b/verifast-proofs/alloc/collections/linked_list.original.rs new file mode 100644 index 0000000000000..ca0ea1ec8b2ba --- /dev/null +++ b/verifast-proofs/alloc/collections/linked_list.original.rs @@ -0,0 +1,2243 @@ +//! A doubly-linked list with owned nodes. +//! +//! The `LinkedList` allows pushing and popping elements at either end +//! in constant time. +//! +//! NOTE: It is almost always better to use [`Vec`] or [`VecDeque`] because +//! array-based containers are generally faster, +//! more memory efficient, and make better use of CPU cache. +//! +//! [`Vec`]: crate::vec::Vec +//! [`VecDeque`]: super::vec_deque::VecDeque + +#![stable(feature = "rust1", since = "1.0.0")] + +use core::cmp::Ordering; +use core::hash::{Hash, Hasher}; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::ptr::NonNull; +use core::{fmt, mem}; + +use super::SpecExtend; +use crate::alloc::{Allocator, Global}; +use crate::boxed::Box; + +#[cfg(test)] +mod tests; + +/// A doubly-linked list with owned nodes. +/// +/// The `LinkedList` allows pushing and popping elements at either end +/// in constant time. +/// +/// A `LinkedList` with a known list of items can be initialized from an array: +/// ``` +/// use std::collections::LinkedList; +/// +/// let list = LinkedList::from([1, 2, 3]); +/// ``` +/// +/// NOTE: It is almost always better to use [`Vec`] or [`VecDeque`] because +/// array-based containers are generally faster, +/// more memory efficient, and make better use of CPU cache. +/// +/// [`Vec`]: crate::vec::Vec +/// [`VecDeque`]: super::vec_deque::VecDeque +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] +#[rustc_insignificant_dtor] +pub struct LinkedList< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + head: Option>>, + tail: Option>>, + len: usize, + alloc: A, + marker: PhantomData, A>>, +} + +struct Node { + next: Option>>, + prev: Option>>, + element: T, +} + +/// An iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by [`LinkedList::iter()`]. See its +/// documentation for more. +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, T: 'a> { + head: Option>>, + tail: Option>>, + len: usize, + marker: PhantomData<&'a Node>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Iter") + .field(&*mem::ManuallyDrop::new(LinkedList { + head: self.head, + tail: self.tail, + len: self.len, + alloc: Global, + marker: PhantomData, + })) + .field(&self.len) + .finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { + Iter { ..*self } + } +} + +/// A mutable iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by [`LinkedList::iter_mut()`]. See its +/// documentation for more. +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IterMut<'a, T: 'a> { + head: Option>>, + tail: Option>>, + len: usize, + marker: PhantomData<&'a mut Node>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("IterMut") + .field(&*mem::ManuallyDrop::new(LinkedList { + head: self.head, + tail: self.tail, + len: self.len, + alloc: Global, + marker: PhantomData, + })) + .field(&self.len) + .finish() + } +} + +/// An owning iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`into_iter`] method on [`LinkedList`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// +/// [`into_iter`]: LinkedList::into_iter +#[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter< + T, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + list: LinkedList, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("IntoIter").field(&self.list).finish() + } +} + +impl Node { + fn new(element: T) -> Self { + Node { next: None, prev: None, element } + } + + fn into_element(self: Box) -> T { + self.element + } +} + +// private methods +impl LinkedList { + /// Adds the given node to the front of the list. + /// + /// # Safety + /// `node` must point to a valid node that was boxed and leaked using the list's allocator. + /// This method takes ownership of the node, so the pointer should not be used again. + #[inline] + unsafe fn push_front_node(&mut self, node: NonNull>) { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. + unsafe { + (*node.as_ptr()).next = self.head; + (*node.as_ptr()).prev = None; + let node = Some(node); + + match self.head { + None => self.tail = node, + // Not creating new mutable (unique!) references overlapping `element`. + Some(head) => (*head.as_ptr()).prev = node, + } + + self.head = node; + self.len += 1; + } + } + + /// Removes and returns the node at the front of the list. + #[inline] + fn pop_front_node(&mut self) -> Option, &A>> { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. + self.head.map(|node| unsafe { + let node = Box::from_raw_in(node.as_ptr(), &self.alloc); + self.head = node.next; + + match self.head { + None => self.tail = None, + // Not creating new mutable (unique!) references overlapping `element`. + Some(head) => (*head.as_ptr()).prev = None, + } + + self.len -= 1; + node + }) + } + + /// Adds the given node to the back of the list. + /// + /// # Safety + /// `node` must point to a valid node that was boxed and leaked using the list's allocator. + /// This method takes ownership of the node, so the pointer should not be used again. + #[inline] + unsafe fn push_back_node(&mut self, node: NonNull>) { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. + unsafe { + (*node.as_ptr()).next = None; + (*node.as_ptr()).prev = self.tail; + let node = Some(node); + + match self.tail { + None => self.head = node, + // Not creating new mutable (unique!) references overlapping `element`. + Some(tail) => (*tail.as_ptr()).next = node, + } + + self.tail = node; + self.len += 1; + } + } + + /// Removes and returns the node at the back of the list. + #[inline] + fn pop_back_node(&mut self) -> Option, &A>> { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. + self.tail.map(|node| unsafe { + let node = Box::from_raw_in(node.as_ptr(), &self.alloc); + self.tail = node.prev; + + match self.tail { + None => self.head = None, + // Not creating new mutable (unique!) references overlapping `element`. + Some(tail) => (*tail.as_ptr()).next = None, + } + + self.len -= 1; + node + }) + } + + /// Unlinks the specified node from the current list. + /// + /// Warning: this will not check that the provided node belongs to the current list. + /// + /// This method takes care not to create mutable references to `element`, to + /// maintain validity of aliasing pointers. + #[inline] + unsafe fn unlink_node(&mut self, mut node: NonNull>) { + let node = unsafe { node.as_mut() }; // this one is ours now, we can create an &mut. + + // Not creating new mutable (unique!) references overlapping `element`. + match node.prev { + Some(prev) => unsafe { (*prev.as_ptr()).next = node.next }, + // this node is the head node + None => self.head = node.next, + }; + + match node.next { + Some(next) => unsafe { (*next.as_ptr()).prev = node.prev }, + // this node is the tail node + None => self.tail = node.prev, + }; + + self.len -= 1; + } + + /// Splices a series of nodes between two existing nodes. + /// + /// Warning: this will not check that the provided node belongs to the two existing lists. + #[inline] + unsafe fn splice_nodes( + &mut self, + existing_prev: Option>>, + existing_next: Option>>, + mut splice_start: NonNull>, + mut splice_end: NonNull>, + splice_length: usize, + ) { + // This method takes care not to create multiple mutable references to whole nodes at the same time, + // to maintain validity of aliasing pointers into `element`. + if let Some(mut existing_prev) = existing_prev { + unsafe { + existing_prev.as_mut().next = Some(splice_start); + } + } else { + self.head = Some(splice_start); + } + if let Some(mut existing_next) = existing_next { + unsafe { + existing_next.as_mut().prev = Some(splice_end); + } + } else { + self.tail = Some(splice_end); + } + unsafe { + splice_start.as_mut().prev = existing_prev; + splice_end.as_mut().next = existing_next; + } + + self.len += splice_length; + } + + /// Detaches all nodes from a linked list as a series of nodes. + #[inline] + fn detach_all_nodes(mut self) -> Option<(NonNull>, NonNull>, usize)> { + let head = self.head.take(); + let tail = self.tail.take(); + let len = mem::replace(&mut self.len, 0); + if let Some(head) = head { + // SAFETY: In a LinkedList, either both the head and tail are None because + // the list is empty, or both head and tail are Some because the list is populated. + // Since we have verified the head is Some, we are sure the tail is Some too. + let tail = unsafe { tail.unwrap_unchecked() }; + Some((head, tail, len)) + } else { + None + } + } + + #[inline] + unsafe fn split_off_before_node( + &mut self, + split_node: Option>>, + at: usize, + ) -> Self + where + A: Clone, + { + // The split node is the new head node of the second part + if let Some(mut split_node) = split_node { + let first_part_head; + let first_part_tail; + unsafe { + first_part_tail = split_node.as_mut().prev.take(); + } + if let Some(mut tail) = first_part_tail { + unsafe { + tail.as_mut().next = None; + } + first_part_head = self.head; + } else { + first_part_head = None; + } + + let first_part = LinkedList { + head: first_part_head, + tail: first_part_tail, + len: at, + alloc: self.alloc.clone(), + marker: PhantomData, + }; + + // Fix the head ptr of the second part + self.head = Some(split_node); + self.len = self.len - at; + + first_part + } else { + mem::replace(self, LinkedList::new_in(self.alloc.clone())) + } + } + + #[inline] + unsafe fn split_off_after_node( + &mut self, + split_node: Option>>, + at: usize, + ) -> Self + where + A: Clone, + { + // The split node is the new tail node of the first part and owns + // the head of the second part. + if let Some(mut split_node) = split_node { + let second_part_head; + let second_part_tail; + unsafe { + second_part_head = split_node.as_mut().next.take(); + } + if let Some(mut head) = second_part_head { + unsafe { + head.as_mut().prev = None; + } + second_part_tail = self.tail; + } else { + second_part_tail = None; + } + + let second_part = LinkedList { + head: second_part_head, + tail: second_part_tail, + len: self.len - at, + alloc: self.alloc.clone(), + marker: PhantomData, + }; + + // Fix the tail ptr of the first part + self.tail = Some(split_node); + self.len = at; + + second_part + } else { + mem::replace(self, LinkedList::new_in(self.alloc.clone())) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Default for LinkedList { + /// Creates an empty `LinkedList`. + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl LinkedList { + /// Creates an empty `LinkedList`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let list: LinkedList = LinkedList::new(); + /// ``` + #[inline] + #[rustc_const_stable(feature = "const_linked_list_new", since = "1.39.0")] + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub const fn new() -> Self { + LinkedList { head: None, tail: None, len: 0, alloc: Global, marker: PhantomData } + } + + /// Moves all elements from `other` to the end of the list. + /// + /// This reuses all the nodes from `other` and moves them into `self`. After + /// this operation, `other` becomes empty. + /// + /// This operation should compute in *O*(1) time and *O*(1) memory. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list1 = LinkedList::new(); + /// list1.push_back('a'); + /// + /// let mut list2 = LinkedList::new(); + /// list2.push_back('b'); + /// list2.push_back('c'); + /// + /// list1.append(&mut list2); + /// + /// let mut iter = list1.iter(); + /// assert_eq!(iter.next(), Some(&'a')); + /// assert_eq!(iter.next(), Some(&'b')); + /// assert_eq!(iter.next(), Some(&'c')); + /// assert!(iter.next().is_none()); + /// + /// assert!(list2.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn append(&mut self, other: &mut Self) { + match self.tail { + None => mem::swap(self, other), + Some(mut tail) => { + // `as_mut` is okay here because we have exclusive access to the entirety + // of both lists. + if let Some(mut other_head) = other.head.take() { + unsafe { + tail.as_mut().next = Some(other_head); + other_head.as_mut().prev = Some(tail); + } + + self.tail = other.tail.take(); + self.len += mem::replace(&mut other.len, 0); + } + } + } + } +} + +impl LinkedList { + /// Constructs an empty `LinkedList`. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// use std::collections::LinkedList; + /// + /// let list: LinkedList = LinkedList::new_in(System); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + pub const fn new_in(alloc: A) -> Self { + LinkedList { head: None, tail: None, len: 0, alloc, marker: PhantomData } + } + /// Provides a forward iterator. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// let mut iter = list.iter(); + /// assert_eq!(iter.next(), Some(&0)); + /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter(&self) -> Iter<'_, T> { + Iter { head: self.head, tail: self.tail, len: self.len, marker: PhantomData } + } + + /// Provides a forward iterator with mutable references. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// for element in list.iter_mut() { + /// *element += 10; + /// } + /// + /// let mut iter = list.iter(); + /// assert_eq!(iter.next(), Some(&10)); + /// assert_eq!(iter.next(), Some(&11)); + /// assert_eq!(iter.next(), Some(&12)); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut { head: self.head, tail: self.tail, len: self.len, marker: PhantomData } + } + + /// Provides a cursor at the front element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. + #[inline] + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn cursor_front(&self) -> Cursor<'_, T, A> { + Cursor { index: 0, current: self.head, list: self } + } + + /// Provides a cursor with editing operations at the front element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. + #[inline] + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T, A> { + CursorMut { index: 0, current: self.head, list: self } + } + + /// Provides a cursor at the back element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. + #[inline] + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn cursor_back(&self) -> Cursor<'_, T, A> { + Cursor { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self } + } + + /// Provides a cursor with editing operations at the back element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. + #[inline] + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T, A> { + CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self } + } + + /// Returns `true` if the `LinkedList` is empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert!(dl.is_empty()); + /// + /// dl.push_front("foo"); + /// assert!(!dl.is_empty()); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + self.head.is_none() + } + + /// Returns the length of the `LinkedList`. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// + /// dl.push_front(2); + /// assert_eq!(dl.len(), 1); + /// + /// dl.push_front(1); + /// assert_eq!(dl.len(), 2); + /// + /// dl.push_back(3); + /// assert_eq!(dl.len(), 3); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("length", "size")] + pub fn len(&self) -> usize { + self.len + } + + /// Removes all elements from the `LinkedList`. + /// + /// This operation should compute in *O*(*n*) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// + /// dl.push_front(2); + /// dl.push_front(1); + /// assert_eq!(dl.len(), 2); + /// assert_eq!(dl.front(), Some(&1)); + /// + /// dl.clear(); + /// assert_eq!(dl.len(), 0); + /// assert_eq!(dl.front(), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn clear(&mut self) { + // We need to drop the nodes while keeping self.alloc + // We can do this by moving (head, tail, len) into a new list that borrows self.alloc + drop(LinkedList { + head: self.head.take(), + tail: self.tail.take(), + len: mem::take(&mut self.len), + alloc: &self.alloc, + marker: PhantomData, + }); + } + + /// Returns `true` if the `LinkedList` contains an element equal to the + /// given value. + /// + /// This operation should compute linearly in *O*(*n*) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// assert_eq!(list.contains(&0), true); + /// assert_eq!(list.contains(&10), false); + /// ``` + #[stable(feature = "linked_list_contains", since = "1.12.0")] + pub fn contains(&self, x: &T) -> bool + where + T: PartialEq, + { + self.iter().any(|e| e == x) + } + + /// Provides a reference to the front element, or `None` if the list is + /// empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.front(), None); + /// + /// dl.push_front(1); + /// assert_eq!(dl.front(), Some(&1)); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("first")] + pub fn front(&self) -> Option<&T> { + unsafe { self.head.as_ref().map(|node| &node.as_ref().element) } + } + + /// Provides a mutable reference to the front element, or `None` if the list + /// is empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.front(), None); + /// + /// dl.push_front(1); + /// assert_eq!(dl.front(), Some(&1)); + /// + /// match dl.front_mut() { + /// None => {}, + /// Some(x) => *x = 5, + /// } + /// assert_eq!(dl.front(), Some(&5)); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn front_mut(&mut self) -> Option<&mut T> { + unsafe { self.head.as_mut().map(|node| &mut node.as_mut().element) } + } + + /// Provides a reference to the back element, or `None` if the list is + /// empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.back(), None); + /// + /// dl.push_back(1); + /// assert_eq!(dl.back(), Some(&1)); + /// ``` + #[inline] + #[must_use] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn back(&self) -> Option<&T> { + unsafe { self.tail.as_ref().map(|node| &node.as_ref().element) } + } + + /// Provides a mutable reference to the back element, or `None` if the list + /// is empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.back(), None); + /// + /// dl.push_back(1); + /// assert_eq!(dl.back(), Some(&1)); + /// + /// match dl.back_mut() { + /// None => {}, + /// Some(x) => *x = 5, + /// } + /// assert_eq!(dl.back(), Some(&5)); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn back_mut(&mut self) -> Option<&mut T> { + unsafe { self.tail.as_mut().map(|node| &mut node.as_mut().element) } + } + + /// Adds an element first in the list. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// + /// dl.push_front(2); + /// assert_eq!(dl.front().unwrap(), &2); + /// + /// dl.push_front(1); + /// assert_eq!(dl.front().unwrap(), &1); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn push_front(&mut self, elt: T) { + let node = Box::new_in(Node::new(elt), &self.alloc); + let node_ptr = NonNull::from(Box::leak(node)); + // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked + unsafe { + self.push_front_node(node_ptr); + } + } + + /// Removes the first element and returns it, or `None` if the list is + /// empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// assert_eq!(d.pop_front(), None); + /// + /// d.push_front(1); + /// d.push_front(3); + /// assert_eq!(d.pop_front(), Some(3)); + /// assert_eq!(d.pop_front(), Some(1)); + /// assert_eq!(d.pop_front(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn pop_front(&mut self) -> Option { + self.pop_front_node().map(Node::into_element) + } + + /// Appends an element to the back of a list. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// d.push_back(1); + /// d.push_back(3); + /// assert_eq!(3, *d.back().unwrap()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("push", "append")] + pub fn push_back(&mut self, elt: T) { + let node = Box::new_in(Node::new(elt), &self.alloc); + let node_ptr = NonNull::from(Box::leak(node)); + // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked + unsafe { + self.push_back_node(node_ptr); + } + } + + /// Removes the last element from a list and returns it, or `None` if + /// it is empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// assert_eq!(d.pop_back(), None); + /// d.push_back(1); + /// d.push_back(3); + /// assert_eq!(d.pop_back(), Some(3)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn pop_back(&mut self) -> Option { + self.pop_back_node().map(Node::into_element) + } + + /// Splits the list into two at the given index. Returns everything after the given index, + /// including the index. + /// + /// This operation should compute in *O*(*n*) time. + /// + /// # Panics + /// + /// Panics if `at > len`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// let mut split = d.split_off(2); + /// + /// assert_eq!(split.pop_front(), Some(1)); + /// assert_eq!(split.pop_front(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn split_off(&mut self, at: usize) -> LinkedList + where + A: Clone, + { + let len = self.len(); + assert!(at <= len, "Cannot split off at a nonexistent index"); + if at == 0 { + return mem::replace(self, Self::new_in(self.alloc.clone())); + } else if at == len { + return Self::new_in(self.alloc.clone()); + } + + // Below, we iterate towards the `i-1`th node, either from the start or the end, + // depending on which would be faster. + let split_node = if at - 1 <= len - 1 - (at - 1) { + let mut iter = self.iter_mut(); + // instead of skipping using .skip() (which creates a new struct), + // we skip manually so we can access the head field without + // depending on implementation details of Skip + for _ in 0..at - 1 { + iter.next(); + } + iter.head + } else { + // better off starting from the end + let mut iter = self.iter_mut(); + for _ in 0..len - 1 - (at - 1) { + iter.next_back(); + } + iter.tail + }; + unsafe { self.split_off_after_node(split_node, at) } + } + + /// Removes the element at the given index and returns it. + /// + /// This operation should compute in *O*(*n*) time. + /// + /// # Panics + /// Panics if at >= len + /// + /// # Examples + /// + /// ``` + /// #![feature(linked_list_remove)] + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// assert_eq!(d.remove(1), 2); + /// assert_eq!(d.remove(0), 3); + /// assert_eq!(d.remove(0), 1); + /// ``` + #[unstable(feature = "linked_list_remove", issue = "69210")] + #[rustc_confusables("delete", "take")] + pub fn remove(&mut self, at: usize) -> T { + let len = self.len(); + assert!(at < len, "Cannot remove at an index outside of the list bounds"); + + // Below, we iterate towards the node at the given index, either from + // the start or the end, depending on which would be faster. + let offset_from_end = len - at - 1; + if at <= offset_from_end { + let mut cursor = self.cursor_front_mut(); + for _ in 0..at { + cursor.move_next(); + } + cursor.remove_current().unwrap() + } else { + let mut cursor = self.cursor_back_mut(); + for _ in 0..offset_from_end { + cursor.move_prev(); + } + cursor.remove_current().unwrap() + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` for which `f(&e)` returns false. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + /// + /// # Examples + /// + /// ``` + /// #![feature(linked_list_retain)] + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// d.retain(|&x| x % 2 == 0); + /// + /// assert_eq!(d.pop_front(), Some(2)); + /// assert_eq!(d.pop_front(), None); + /// ``` + /// + /// Because the elements are visited exactly once in the original order, + /// external state may be used to decide which elements to keep. + /// + /// ``` + /// #![feature(linked_list_retain)] + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// let keep = [false, true, false]; + /// let mut iter = keep.iter(); + /// d.retain(|_| *iter.next().unwrap()); + /// assert_eq!(d.pop_front(), Some(2)); + /// assert_eq!(d.pop_front(), None); + /// ``` + #[unstable(feature = "linked_list_retain", issue = "114135")] + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.retain_mut(|elem| f(elem)); + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` for which `f(&mut e)` returns false. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + /// + /// # Examples + /// + /// ``` + /// #![feature(linked_list_retain)] + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// d.retain_mut(|x| if *x % 2 == 0 { + /// *x += 1; + /// true + /// } else { + /// false + /// }); + /// assert_eq!(d.pop_front(), Some(3)); + /// assert_eq!(d.pop_front(), None); + /// ``` + #[unstable(feature = "linked_list_retain", issue = "114135")] + pub fn retain_mut(&mut self, mut f: F) + where + F: FnMut(&mut T) -> bool, + { + let mut cursor = self.cursor_front_mut(); + while let Some(node) = cursor.current() { + if !f(node) { + cursor.remove_current().unwrap(); + } else { + cursor.move_next(); + } + } + } + + /// Creates an iterator which uses a closure to determine if an element should be removed. + /// + /// If the closure returns true, then the element is removed and yielded. + /// If the closure returns false, the element will remain in the list and will not be yielded + /// by the iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use `extract_if().for_each(drop)` if you do not need the returned iterator. + /// + /// Note that `extract_if` lets you mutate every element in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// # Examples + /// + /// Splitting a list into evens and odds, reusing the original list: + /// + /// ``` + /// #![feature(extract_if)] + /// use std::collections::LinkedList; + /// + /// let mut numbers: LinkedList = LinkedList::new(); + /// numbers.extend(&[1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]); + /// + /// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::>(); + /// let odds = numbers; + /// + /// assert_eq!(evens.into_iter().collect::>(), vec![2, 4, 6, 8, 14]); + /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 9, 11, 13, 15]); + /// ``` + #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] + pub fn extract_if(&mut self, filter: F) -> ExtractIf<'_, T, F, A> + where + F: FnMut(&mut T) -> bool, + { + // avoid borrow issues. + let it = self.head; + let old_len = self.len; + + ExtractIf { list: self, it, pred: filter, idx: 0, old_len } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for LinkedList { + fn drop(&mut self) { + struct DropGuard<'a, T, A: Allocator>(&'a mut LinkedList); + + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { + fn drop(&mut self) { + // Continue the same loop we do below. This only runs when a destructor has + // panicked. If another one panics this will abort. + while self.0.pop_front_node().is_some() {} + } + } + + // Wrap self so that if a destructor panics, we can try to keep looping + let guard = DropGuard(self); + while guard.0.pop_front_node().is_some() {} + mem::forget(guard); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option<&'a T> { + if self.len == 0 { + None + } else { + self.head.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &*node.as_ptr(); + self.len -= 1; + self.head = node.next; + &node.element + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } + + #[inline] + fn last(mut self) -> Option<&'a T> { + self.next_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a T> { + if self.len == 0 { + None + } else { + self.tail.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &*node.as_ptr(); + self.len -= 1; + self.tail = node.prev; + &node.element + }) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Iter<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Iter<'_, T> {} + +#[stable(feature = "default_iters", since = "1.70.0")] +impl Default for Iter<'_, T> { + /// Creates an empty `linked_list::Iter`. + /// + /// ``` + /// # use std::collections::linked_list; + /// let iter: linked_list::Iter<'_, u8> = Default::default(); + /// assert_eq!(iter.len(), 0); + /// ``` + fn default() -> Self { + Iter { head: None, tail: None, len: 0, marker: Default::default() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + #[inline] + fn next(&mut self) -> Option<&'a mut T> { + if self.len == 0 { + None + } else { + self.head.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &mut *node.as_ptr(); + self.len -= 1; + self.head = node.next; + &mut node.element + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } + + #[inline] + fn last(mut self) -> Option<&'a mut T> { + self.next_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut T> { + if self.len == 0 { + None + } else { + self.tail.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &mut *node.as_ptr(); + self.len -= 1; + self.tail = node.prev; + &mut node.element + }) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IterMut<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IterMut<'_, T> {} + +#[stable(feature = "default_iters", since = "1.70.0")] +impl Default for IterMut<'_, T> { + fn default() -> Self { + IterMut { head: None, tail: None, len: 0, marker: Default::default() } + } +} + +/// A cursor over a `LinkedList`. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth. +/// +/// Cursors always rest between two elements in the list, and index in a logically circular way. +/// To accommodate this, there is a "ghost" non-element that yields `None` between the head and +/// tail of the list. +/// +/// When created, cursors start at the front of the list, or the "ghost" non-element if the list is empty. +#[unstable(feature = "linked_list_cursors", issue = "58533")] +pub struct Cursor< + 'a, + T: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + index: usize, + current: Option>>, + list: &'a LinkedList, +} + +#[unstable(feature = "linked_list_cursors", issue = "58533")] +impl Clone for Cursor<'_, T, A> { + fn clone(&self) -> Self { + let Cursor { index, current, list } = *self; + Cursor { index, current, list } + } +} + +#[unstable(feature = "linked_list_cursors", issue = "58533")] +impl fmt::Debug for Cursor<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Cursor").field(&self.list).field(&self.index()).finish() + } +} + +/// A cursor over a `LinkedList` with editing operations. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can +/// safely mutate the list during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying list. This means +/// cursors cannot yield multiple elements at once. +/// +/// Cursors always rest between two elements in the list, and index in a logically circular way. +/// To accommodate this, there is a "ghost" non-element that yields `None` between the head and +/// tail of the list. +#[unstable(feature = "linked_list_cursors", issue = "58533")] +pub struct CursorMut< + 'a, + T: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> { + index: usize, + current: Option>>, + list: &'a mut LinkedList, +} + +#[unstable(feature = "linked_list_cursors", issue = "58533")] +impl fmt::Debug for CursorMut<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("CursorMut").field(&self.list).field(&self.index()).finish() + } +} + +impl<'a, T, A: Allocator> Cursor<'a, T, A> { + /// Returns the cursor position index within the `LinkedList`. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn index(&self) -> Option { + let _ = self.current?; + Some(self.index) + } + + /// Moves the cursor to the next element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this will move it to the "ghost" non-element. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn move_next(&mut self) { + match self.current.take() { + // We had no current element; the cursor was sitting at the start position + // Next element should be the head of the list + None => { + self.current = self.list.head; + self.index = 0; + } + // We had a previous element, so let's go to its next + Some(current) => unsafe { + self.current = current.as_ref().next; + self.index += 1; + }, + } + } + + /// Moves the cursor to the previous element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this will move it to the "ghost" non-element. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn move_prev(&mut self) { + match self.current.take() { + // No current. We're at the start of the list. Yield None and jump to the end. + None => { + self.current = self.list.tail; + self.index = self.list.len().checked_sub(1).unwrap_or(0); + } + // Have a prev. Yield it and go to the previous element. + Some(current) => unsafe { + self.current = current.as_ref().prev; + self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); + }, + } + } + + /// Returns a reference to the element that the cursor is currently + /// pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn current(&self) -> Option<&'a T> { + unsafe { self.current.map(|current| &(*current.as_ptr()).element) } + } + + /// Returns a reference to the next element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this returns `None`. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn peek_next(&self) -> Option<&'a T> { + unsafe { + let next = match self.current { + None => self.list.head, + Some(current) => current.as_ref().next, + }; + next.map(|next| &(*next.as_ptr()).element) + } + } + + /// Returns a reference to the previous element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this returns `None`. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn peek_prev(&self) -> Option<&'a T> { + unsafe { + let prev = match self.current { + None => self.list.tail, + Some(current) => current.as_ref().prev, + }; + prev.map(|prev| &(*prev.as_ptr()).element) + } + } + + /// Provides a reference to the front element of the cursor's parent list, + /// or None if the list is empty. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + #[rustc_confusables("first")] + pub fn front(&self) -> Option<&'a T> { + self.list.front() + } + + /// Provides a reference to the back element of the cursor's parent list, + /// or None if the list is empty. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + #[rustc_confusables("last")] + pub fn back(&self) -> Option<&'a T> { + self.list.back() + } + + /// Provides a reference to the cursor's parent list. + #[must_use] + #[inline(always)] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn as_list(&self) -> &'a LinkedList { + self.list + } +} + +impl<'a, T, A: Allocator> CursorMut<'a, T, A> { + /// Returns the cursor position index within the `LinkedList`. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn index(&self) -> Option { + let _ = self.current?; + Some(self.index) + } + + /// Moves the cursor to the next element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this will move it to the "ghost" non-element. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn move_next(&mut self) { + match self.current.take() { + // We had no current element; the cursor was sitting at the start position + // Next element should be the head of the list + None => { + self.current = self.list.head; + self.index = 0; + } + // We had a previous element, so let's go to its next + Some(current) => unsafe { + self.current = current.as_ref().next; + self.index += 1; + }, + } + } + + /// Moves the cursor to the previous element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this will move it to the "ghost" non-element. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn move_prev(&mut self) { + match self.current.take() { + // No current. We're at the start of the list. Yield None and jump to the end. + None => { + self.current = self.list.tail; + self.index = self.list.len().checked_sub(1).unwrap_or(0); + } + // Have a prev. Yield it and go to the previous element. + Some(current) => unsafe { + self.current = current.as_ref().prev; + self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); + }, + } + } + + /// Returns a reference to the element that the cursor is currently + /// pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn current(&mut self) -> Option<&mut T> { + unsafe { self.current.map(|current| &mut (*current.as_ptr()).element) } + } + + /// Returns a reference to the next element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this returns `None`. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn peek_next(&mut self) -> Option<&mut T> { + unsafe { + let next = match self.current { + None => self.list.head, + Some(current) => current.as_ref().next, + }; + next.map(|next| &mut (*next.as_ptr()).element) + } + } + + /// Returns a reference to the previous element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this returns `None`. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn peek_prev(&mut self) -> Option<&mut T> { + unsafe { + let prev = match self.current { + None => self.list.tail, + Some(current) => current.as_ref().prev, + }; + prev.map(|prev| &mut (*prev.as_ptr()).element) + } + } + + /// Returns a read-only cursor pointing to the current element. + /// + /// The lifetime of the returned `Cursor` is bound to that of the + /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the + /// `CursorMut` is frozen for the lifetime of the `Cursor`. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn as_cursor(&self) -> Cursor<'_, T, A> { + Cursor { list: self.list, current: self.current, index: self.index } + } + + /// Provides a read-only reference to the cursor's parent list. + /// + /// The lifetime of the returned reference is bound to that of the + /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the + /// `CursorMut` is frozen for the lifetime of the reference. + #[must_use] + #[inline(always)] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn as_list(&self) -> &LinkedList { + self.list + } +} + +// Now the list editing operations + +impl<'a, T> CursorMut<'a, T> { + /// Inserts the elements from the given `LinkedList` after the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new elements are + /// inserted at the start of the `LinkedList`. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn splice_after(&mut self, list: LinkedList) { + unsafe { + let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { + Some(parts) => parts, + _ => return, + }; + let node_next = match self.current { + None => self.list.head, + Some(node) => node.as_ref().next, + }; + self.list.splice_nodes(self.current, node_next, splice_head, splice_tail, splice_len); + if self.current.is_none() { + // The "ghost" non-element's index has changed. + self.index = self.list.len; + } + } + } + + /// Inserts the elements from the given `LinkedList` before the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new elements are + /// inserted at the end of the `LinkedList`. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn splice_before(&mut self, list: LinkedList) { + unsafe { + let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { + Some(parts) => parts, + _ => return, + }; + let node_prev = match self.current { + None => self.list.tail, + Some(node) => node.as_ref().prev, + }; + self.list.splice_nodes(node_prev, self.current, splice_head, splice_tail, splice_len); + self.index += splice_len; + } + } +} + +impl<'a, T, A: Allocator> CursorMut<'a, T, A> { + /// Inserts a new element into the `LinkedList` after the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new element is + /// inserted at the front of the `LinkedList`. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn insert_after(&mut self, item: T) { + unsafe { + let spliced_node = Box::leak(Box::new_in(Node::new(item), &self.list.alloc)).into(); + let node_next = match self.current { + None => self.list.head, + Some(node) => node.as_ref().next, + }; + self.list.splice_nodes(self.current, node_next, spliced_node, spliced_node, 1); + if self.current.is_none() { + // The "ghost" non-element's index has changed. + self.index = self.list.len; + } + } + } + + /// Inserts a new element into the `LinkedList` before the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new element is + /// inserted at the end of the `LinkedList`. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn insert_before(&mut self, item: T) { + unsafe { + let spliced_node = Box::leak(Box::new_in(Node::new(item), &self.list.alloc)).into(); + let node_prev = match self.current { + None => self.list.tail, + Some(node) => node.as_ref().prev, + }; + self.list.splice_nodes(node_prev, self.current, spliced_node, spliced_node, 1); + self.index += 1; + } + } + + /// Removes the current element from the `LinkedList`. + /// + /// The element that was removed is returned, and the cursor is + /// moved to point to the next element in the `LinkedList`. + /// + /// If the cursor is currently pointing to the "ghost" non-element then no element + /// is removed and `None` is returned. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn remove_current(&mut self) -> Option { + let unlinked_node = self.current?; + unsafe { + self.current = unlinked_node.as_ref().next; + self.list.unlink_node(unlinked_node); + let unlinked_node = Box::from_raw_in(unlinked_node.as_ptr(), &self.list.alloc); + Some(unlinked_node.element) + } + } + + /// Removes the current element from the `LinkedList` without deallocating the list node. + /// + /// The node that was removed is returned as a new `LinkedList` containing only this node. + /// The cursor is moved to point to the next element in the current `LinkedList`. + /// + /// If the cursor is currently pointing to the "ghost" non-element then no element + /// is removed and `None` is returned. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn remove_current_as_list(&mut self) -> Option> + where + A: Clone, + { + let mut unlinked_node = self.current?; + unsafe { + self.current = unlinked_node.as_ref().next; + self.list.unlink_node(unlinked_node); + + unlinked_node.as_mut().prev = None; + unlinked_node.as_mut().next = None; + Some(LinkedList { + head: Some(unlinked_node), + tail: Some(unlinked_node), + len: 1, + alloc: self.list.alloc.clone(), + marker: PhantomData, + }) + } + } + + /// Splits the list into two after the current element. This will return a + /// new list consisting of everything after the cursor, with the original + /// list retaining everything before. + /// + /// If the cursor is pointing at the "ghost" non-element then the entire contents + /// of the `LinkedList` are moved. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn split_after(&mut self) -> LinkedList + where + A: Clone, + { + let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 }; + if self.index == self.list.len { + // The "ghost" non-element's index has changed to 0. + self.index = 0; + } + unsafe { self.list.split_off_after_node(self.current, split_off_idx) } + } + + /// Splits the list into two before the current element. This will return a + /// new list consisting of everything before the cursor, with the original + /// list retaining everything after. + /// + /// If the cursor is pointing at the "ghost" non-element then the entire contents + /// of the `LinkedList` are moved. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn split_before(&mut self) -> LinkedList + where + A: Clone, + { + let split_off_idx = self.index; + self.index = 0; + unsafe { self.list.split_off_before_node(self.current, split_off_idx) } + } + + /// Appends an element to the front of the cursor's parent list. The node + /// that the cursor points to is unchanged, even if it is the "ghost" node. + /// + /// This operation should compute in *O*(1) time. + // `push_front` continues to point to "ghost" when it adds a node to mimic + // the behavior of `insert_before` on an empty list. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn push_front(&mut self, elt: T) { + // Safety: We know that `push_front` does not change the position in + // memory of other nodes. This ensures that `self.current` remains + // valid. + self.list.push_front(elt); + self.index += 1; + } + + /// Appends an element to the back of the cursor's parent list. The node + /// that the cursor points to is unchanged, even if it is the "ghost" node. + /// + /// This operation should compute in *O*(1) time. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + #[rustc_confusables("push", "append")] + pub fn push_back(&mut self, elt: T) { + // Safety: We know that `push_back` does not change the position in + // memory of other nodes. This ensures that `self.current` remains + // valid. + self.list.push_back(elt); + if self.current().is_none() { + // The index of "ghost" is the length of the list, so we just need + // to increment self.index to reflect the new length of the list. + self.index += 1; + } + } + + /// Removes the first element from the cursor's parent list and returns it, + /// or None if the list is empty. The element the cursor points to remains + /// unchanged, unless it was pointing to the front element. In that case, it + /// points to the new front element. + /// + /// This operation should compute in *O*(1) time. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn pop_front(&mut self) -> Option { + // We can't check if current is empty, we must check the list directly. + // It is possible for `self.current == None` and the list to be + // non-empty. + if self.list.is_empty() { + None + } else { + // We can't point to the node that we pop. Copying the behavior of + // `remove_current`, we move on to the next node in the sequence. + // If the list is of length 1 then we end pointing to the "ghost" + // node at index 0, which is expected. + if self.list.head == self.current { + self.move_next(); + } else { + self.index -= 1; + } + self.list.pop_front() + } + } + + /// Removes the last element from the cursor's parent list and returns it, + /// or None if the list is empty. The element the cursor points to remains + /// unchanged, unless it was pointing to the back element. In that case, it + /// points to the "ghost" element. + /// + /// This operation should compute in *O*(1) time. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + #[rustc_confusables("pop")] + pub fn pop_back(&mut self) -> Option { + if self.list.is_empty() { + None + } else { + if self.list.tail == self.current { + // The index now reflects the length of the list. It was the + // length of the list minus 1, but now the list is 1 smaller. No + // change is needed for `index`. + self.current = None; + } else if self.current.is_none() { + self.index = self.list.len - 1; + } + self.list.pop_back() + } + } + + /// Provides a reference to the front element of the cursor's parent list, + /// or None if the list is empty. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + #[rustc_confusables("first")] + pub fn front(&self) -> Option<&T> { + self.list.front() + } + + /// Provides a mutable reference to the front element of the cursor's + /// parent list, or None if the list is empty. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn front_mut(&mut self) -> Option<&mut T> { + self.list.front_mut() + } + + /// Provides a reference to the back element of the cursor's parent list, + /// or None if the list is empty. + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + #[rustc_confusables("last")] + pub fn back(&self) -> Option<&T> { + self.list.back() + } + + /// Provides a mutable reference to back element of the cursor's parent + /// list, or `None` if the list is empty. + /// + /// # Examples + /// Building and mutating a list with a cursor, then getting the back element: + /// ``` + /// #![feature(linked_list_cursors)] + /// use std::collections::LinkedList; + /// let mut dl = LinkedList::new(); + /// dl.push_front(3); + /// dl.push_front(2); + /// dl.push_front(1); + /// let mut cursor = dl.cursor_front_mut(); + /// *cursor.current().unwrap() = 99; + /// *cursor.back_mut().unwrap() = 0; + /// let mut contents = dl.into_iter(); + /// assert_eq!(contents.next(), Some(99)); + /// assert_eq!(contents.next(), Some(2)); + /// assert_eq!(contents.next(), Some(0)); + /// assert_eq!(contents.next(), None); + /// ``` + #[must_use] + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn back_mut(&mut self) -> Option<&mut T> { + self.list.back_mut() + } +} + +/// An iterator produced by calling `extract_if` on LinkedList. +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +#[must_use = "iterators are lazy and do nothing unless consumed"] +pub struct ExtractIf< + 'a, + T: 'a, + F: 'a, + #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, +> where + F: FnMut(&mut T) -> bool, +{ + list: &'a mut LinkedList, + it: Option>>, + pred: F, + idx: usize, + old_len: usize, +} + +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +impl Iterator for ExtractIf<'_, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + type Item = T; + + fn next(&mut self) -> Option { + while let Some(mut node) = self.it { + unsafe { + self.it = node.as_ref().next; + self.idx += 1; + + if (self.pred)(&mut node.as_mut().element) { + // `unlink_node` is okay with aliasing `element` references. + self.list.unlink_node(node); + return Some(Box::from_raw_in(node.as_ptr(), &self.list.alloc).element); + } + } + } + + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.old_len - self.idx)) + } +} + +#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +impl fmt::Debug for ExtractIf<'_, T, F> +where + F: FnMut(&mut T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("ExtractIf").field(&self.list).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.list.pop_front() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.list.len, Some(self.list.len)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + self.list.pop_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} + +#[stable(feature = "default_iters", since = "1.70.0")] +impl Default for IntoIter { + /// Creates an empty `linked_list::IntoIter`. + /// + /// ``` + /// # use std::collections::linked_list; + /// let iter: linked_list::IntoIter = Default::default(); + /// assert_eq!(iter.len(), 0); + /// ``` + fn default() -> Self { + LinkedList::new().into_iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromIterator for LinkedList { + fn from_iter>(iter: I) -> Self { + let mut list = Self::new(); + list.extend(iter); + list + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for LinkedList { + type Item = T; + type IntoIter = IntoIter; + + /// Consumes the list into an iterator yielding elements by value. + #[inline] + fn into_iter(self) -> IntoIter { + IntoIter { list: self } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, A: Allocator> IntoIterator for &'a LinkedList { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, A: Allocator> IntoIterator for &'a mut LinkedList { + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Extend for LinkedList { + fn extend>(&mut self, iter: I) { + >::spec_extend(self, iter); + } + + #[inline] + fn extend_one(&mut self, elem: T) { + self.push_back(elem); + } +} + +impl SpecExtend for LinkedList { + default fn spec_extend(&mut self, iter: I) { + iter.into_iter().for_each(move |elt| self.push_back(elt)); + } +} + +impl SpecExtend> for LinkedList { + fn spec_extend(&mut self, ref mut other: LinkedList) { + self.append(other); + } +} + +#[stable(feature = "extend_ref", since = "1.2.0")] +impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for LinkedList { + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } + + #[inline] + fn extend_one(&mut self, &elem: &'a T) { + self.push_back(elem); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for LinkedList { + fn eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.iter().eq(other) + } + + fn ne(&self, other: &Self) -> bool { + self.len() != other.len() || self.iter().ne(other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for LinkedList {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for LinkedList { + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for LinkedList { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for LinkedList { + fn clone(&self) -> Self { + let mut list = Self::new_in(self.alloc.clone()); + list.extend(self.iter().cloned()); + list + } + + /// Overwrites the contents of `self` with a clone of the contents of `source`. + /// + /// This method is preferred over simply assigning `source.clone()` to `self`, + /// as it avoids reallocation of the nodes of the linked list. Additionally, + /// if the element type `T` overrides `clone_from()`, this will reuse the + /// resources of `self`'s elements as well. + fn clone_from(&mut self, source: &Self) { + let mut source_iter = source.iter(); + if self.len() > source.len() { + self.split_off(source.len()); + } + for (elem, source_elem) in self.iter_mut().zip(&mut source_iter) { + elem.clone_from(source_elem); + } + if !source_iter.is_empty() { + self.extend(source_iter.cloned()); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for LinkedList { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for LinkedList { + fn hash(&self, state: &mut H) { + state.write_length_prefix(self.len()); + for elt in self { + elt.hash(state); + } + } +} + +#[stable(feature = "std_collections_from_array", since = "1.56.0")] +impl From<[T; N]> for LinkedList { + /// Converts a `[T; N]` into a `LinkedList`. + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let list1 = LinkedList::from([1, 2, 3, 4]); + /// let list2: LinkedList<_> = [1, 2, 3, 4].into(); + /// assert_eq!(list1, list2); + /// ``` + fn from(arr: [T; N]) -> Self { + Self::from_iter(arr) + } +} + +// Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters. +#[allow(dead_code)] +fn assert_covariance() { + fn a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> { + x + } + fn b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> { + x + } + fn c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> { + x + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for LinkedList {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for LinkedList {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for Iter<'_, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for Iter<'_, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for IterMut<'_, T> {} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for IterMut<'_, T> {} + +#[unstable(feature = "linked_list_cursors", issue = "58533")] +unsafe impl Send for Cursor<'_, T, A> {} + +#[unstable(feature = "linked_list_cursors", issue = "58533")] +unsafe impl Sync for Cursor<'_, T, A> {} + +#[unstable(feature = "linked_list_cursors", issue = "58533")] +unsafe impl Send for CursorMut<'_, T, A> {} + +#[unstable(feature = "linked_list_cursors", issue = "58533")] +unsafe impl Sync for CursorMut<'_, T, A> {} diff --git a/verifast-proofs/alloc/collections/linked_list.verifast-proof.rs b/verifast-proofs/alloc/collections/linked_list.verifast-proof.rs new file mode 100644 index 0000000000000..894a63a2fbb9e --- /dev/null +++ b/verifast-proofs/alloc/collections/linked_list.verifast-proof.rs @@ -0,0 +1,3982 @@ +// verifast_options{prover:z3v4.5 skip_specless_fns} + +//! A doubly-linked list with owned nodes. +//! +//! The `LinkedList` allows pushing and popping elements at either end +//! in constant time. +//! +//! NOTE: It is almost always better to use [`Vec`] or [`VecDeque`] because +//! array-based containers are generally faster, +//! more memory efficient, and make better use of CPU cache. +//! +//! [`Vec`]: crate::vec::Vec +//! [`VecDeque`]: super::vec_deque::VecDeque + +// This is a slightly tweaked version of https://github.com/rust-lang/rust/blob/c290e9de32e8ba6a673ef125fde40eadd395d170/library/alloc/src/collections/linked_list.rs + +//#![stable(feature = "rust1", since = "1.0.0")] +#![feature(rustc_attrs)] +#![feature(dropck_eyepatch)] +#![feature(specialization)] +#![feature(allocator_api)] +#![feature(extend_one)] +#![feature(exact_size_is_empty)] +#![feature(hasher_prefixfree_extras)] +#![feature(box_into_inner)] + +use std as core; + +use core::cmp::Ordering; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::iter::FromIterator; +use core::iter::FusedIterator; +use core::marker::PhantomData; +use core::mem; +use core::ptr::NonNull; + +use std::alloc::{Allocator, Global}; +use std::boxed::Box; + +//@ use std::alloc::{alloc_block_in, Layout, Global, Allocator}; +//@ use std::option::{Option, Option::None, Option::Some}; +//@ use std::ptr::{NonNull, NonNull_ptr}; +//@ use std::boxed::Box_in; + +#[cfg(test)] +mod tests; + +/*@ + +lem foreach_unappend(xs1: list, xs2: list, p: pred(a)) + req foreach(append(xs1, xs2), p); + ens foreach(xs1, p) &*& foreach(xs2, p); +{ + match xs1 { + nil => {} + cons(x, xs10) => { + open foreach(_, _); + foreach_unappend(xs10, xs2, p); + } + } + close foreach(xs1, p); +} + + +pred foreachp2(xs: list, p: pred(a; b); ys: list) = + match xs { + nil => ys == nil, + cons(x, xs0) => p(x, ?y) &*& foreachp2(xs0, p, ?ys0) &*& ys == cons(y, ys0) + }; + +lem_auto foreachp2_inv() + req foreachp2::(?xs, ?p, ?ys); + ens foreachp2::(xs, p, ys) &*& length(ys) == length(xs); +{ + open foreachp2(xs, p, ys); + match xs { + nil => {} + cons(x, xs0) => { + foreachp2_inv(); + } + } + close foreachp2(xs, p, ys); +} + +lem foreachp2_append(xs1: list, xs2: list, p: pred(a; b)) + req foreachp2(xs1, p, ?ys1) &*& foreachp2(xs2, p, ?ys2); + ens foreachp2(append(xs1, xs2), p, append(ys1, ys2)); +{ + open foreachp2(xs1, p, ys1); + match xs1 { + nil => {} + cons(x, xs10) => { + foreachp2_append(xs10, xs2, p); + close foreachp2(append(xs1, xs2), p, append(ys1, ys2)); + } + } +} + +lem foreachp2_unappend(xs1: list, xs2: list, p: pred(a; b)) + req foreachp2(append(xs1, xs2), p, ?ys); + ens foreachp2(xs1, p, take(length(xs1), ys)) &*& foreachp2(xs2, p, drop(length(xs1), ys)); +{ + match xs1 { + nil => {} + cons(x, xs10) => { + open foreachp2(_, _, _); + foreachp2_unappend(xs10, xs2, p); + } + } + close foreachp2(xs1, p, take(length(xs1), ys)); +} + +@*/ + +trait SpecExtend { + fn spec_extend(&mut self, iter: I); +} + +/// A doubly-linked list with owned nodes. +/// +/// The `LinkedList` allows pushing and popping elements at either end +/// in constant time. +/// +/// A `LinkedList` with a known list of items can be initialized from an array: +/// ``` +/// use std::collections::LinkedList; +/// +/// let list = LinkedList::from([1, 2, 3]); +/// ``` +/// +/// NOTE: It is almost always better to use [`Vec`] or [`VecDeque`] because +/// array-based containers are generally faster, +/// more memory efficient, and make better use of CPU cache. +/// +/// [`Vec`]: crate::vec::Vec +/// [`VecDeque`]: super::vec_deque::VecDeque +//#[stable(feature = "rust1", since = "1.0.0")] +//#[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] +#[rustc_insignificant_dtor] +pub struct LinkedList< + T, + /*#[unstable(feature = "allocator_api", issue = "32838")]*/ A: Allocator = Global, +> { + head: Option>>, + tail: Option>>, + len: usize, + alloc: A, + marker: PhantomData, A>>, +} + +struct Node { + next: Option>>, + prev: Option>>, + element: T, +} + +/*@ + +pred >.own(t, node) = .own(t, node.element); + +lem Node_drop() + req Node_own::(?_t, ?_v); + ens .own(_t, _v.element); +{ + open >.own(_t, _v); +} + +lem Node_own_mono() + req type_interp::() &*& type_interp::() &*& Node_own::(?t, ?v) &*& is_subtype_of::() == true; + ens type_interp::() &*& type_interp::() &*& Node_own::(t, Node:: { next: upcast(v.next), prev: upcast(v.prev), element: upcast(v.element) }); +{ + open >.own(t, v); + own_mono::(t, v.element); + Node_upcast::(v); + close >.own(t, upcast(v)); +} + +lem Node_send(t1: thread_id_t) + req type_interp::() &*& is_Send(typeid(T)) == true &*& Node_own::(?t0, ?v); + ens type_interp::() &*& Node_own::(t1, v); +{ + open >.own(t0, v); + Send::send::(t0, t1, v.element); + close >.own(t1, v); +} + +pred Nodes(alloc_id: any, n: Option>>, prev: Option>>, last: Option>>, next: Option>>; nodes: list>>) = + if n == next { + nodes == [] &*& last == prev + } else { + n == Option::Some(?n_) &*& + alloc_block_in(alloc_id, NonNull_ptr(n_) as *u8, Layout::new_::>()) &*& struct_Node_padding(NonNull_ptr(n_)) &*& + (*NonNull_ptr(n_)).prev |-> prev &*& + (*NonNull_ptr(n_)).next |-> ?next0 &*& + pointer_within_limits(&(*NonNull_ptr(n_)).element) == true &*& + Nodes(alloc_id, next0, n, last, next, ?nodes0) &*& + nodes == cons(n_, nodes0) + }; + +lem Nodes_last_lemma(n: Option>>) + req Nodes::(?alloc_id, n, ?prev, ?last, ?next, ?nodes); + ens Nodes::(alloc_id, n, prev, last, next, nodes) &*& + match last { + Option::None => n == next && prev == last && nodes == [], + Option::Some(last_) => + match prev { + Option::None => n != next && length(nodes) > 0 && nth(length(nodes) - 1, nodes) == last_, + Option::Some(prev_) => nth(length(nodes), cons(prev_, nodes)) == last_ + } + }; +{ + open Nodes(alloc_id, n, prev, last, next, nodes); + if n == next { + } else { + assert Nodes(_, ?next0, _, _, _, _); + Nodes_last_lemma(next0); + } + close Nodes(alloc_id, n, prev, last, next, nodes); +} + +lem Nodes_split_off_last(n: Option>>) + req Nodes::(?alloc_id, n, ?prev, ?last, ?next, ?nodes) &*& n != next; + ens last == Option::Some(?last_) &*& + Nodes::(alloc_id, n, prev, ?last1, last, ?nodes0) &*& + alloc_block_in(alloc_id, NonNull_ptr(last_) as *u8, Layout::new_::>()) &*& + (*NonNull_ptr(last_)).prev |-> last1 &*& + (*NonNull_ptr(last_)).next |-> next &*& + pointer_within_limits(&(*NonNull_ptr(last_)).element) == true &*& + struct_Node_padding(NonNull_ptr(last_)) &*& + nodes == append(nodes0, [last_]); +{ + open Nodes::(alloc_id, n, prev, last, next, nodes); + assert Nodes(alloc_id, ?next0, _, _, _, _); + assert n == Option::Some(?n_); + if next0 == next { + open Nodes(alloc_id, next0, _, _, _, _); + close Nodes::(alloc_id, n, prev, prev, n, []); + } else { + Nodes_split_off_last(next0); + assert Nodes(alloc_id, next0, n, ?last1, last, ?nodes0); + close Nodes::(alloc_id, n, prev, last1, last, cons(n_, nodes0)); + } +} + +lem Nodes_append_one_(head: Option>>) + req Nodes::(?alloc_id, head, ?prev, ?last, Option::Some(?n), ?nodes1) &*& + alloc_block_in(alloc_id, NonNull_ptr(n) as *u8, Layout::new_::>()) &*& + (*NonNull_ptr(n)).prev |-> last &*& + (*NonNull_ptr(n)).next |-> ?next &*& + pointer_within_limits(&(*NonNull_ptr(n)).element) == true &*& + struct_Node_padding(NonNull_ptr(n)) &*& + Nodes(alloc_id, next, Option::Some(n), ?tail, None, ?nodes2); + ens Nodes(alloc_id, head, prev, Option::Some(n), next, append(nodes1, [n])) &*& + Nodes(alloc_id, next, Option::Some(n), tail, None, nodes2); +{ + open Nodes::(alloc_id, head, prev, last, Option::Some(n), nodes1); + if head == Option::Some(n) { + open Nodes(alloc_id, next, Option::Some(n), tail, None, nodes2); + close Nodes(alloc_id, next, Option::Some(n), tail, None, nodes2); + close Nodes(alloc_id, next, Option::Some(n), Some(n), next, []); + } else { + open Nodes(alloc_id, next, Option::Some(n), tail, None, nodes2); + close Nodes(alloc_id, next, Option::Some(n), tail, None, nodes2); + open Nodes(_, ?next0, head, _, _, _); + close Nodes(alloc_id, next0, head, last, Option::Some(n), tail(nodes1)); + Nodes_append_one_(next0); + } + close Nodes::(alloc_id, head, prev, Some(n), next, append(nodes1, [n])); +} + +lem Nodes_append(n: Option>>) + req Nodes::(?alloc_id, n, ?prev, ?n1, ?n2, ?nodes1) &*& Nodes::(alloc_id, n2, n1, ?tail, None, ?nodes2); + ens Nodes::(alloc_id, n, prev, tail, None, append(nodes1, nodes2)); +{ + open Nodes::(alloc_id, n, prev, n1, n2, nodes1); + if n == n2 { + } else { + assert n == Option::Some(?n_); + Nodes_append((*NonNull_ptr(n_)).next); + close Nodes::(alloc_id, n, prev, tail, None, append(nodes1, nodes2)); + } +} + +lem Nodes_append_(n: Option>>) + req Nodes::(?alloc_id, n, ?prev, ?n1, ?n2, ?nodes1) &*& Nodes::(alloc_id, n2, n1, ?n3, ?n4, ?nodes2) &*& Nodes::(alloc_id, n4, ?n5, ?tail, None, ?nodes3); + ens Nodes::(alloc_id, n, prev, n3, n4, append(nodes1, nodes2)) &*& Nodes::(alloc_id, n4, n5, tail, None, nodes3); +{ + open Nodes::(alloc_id, n, prev, n1, n2, nodes1); + if n == n2 { + } else { + assert n == Option::Some(?n_); + Nodes_append_((*NonNull_ptr(n_)).next); + open Nodes(alloc_id, n4, n5, tail, None, nodes3); + close Nodes(alloc_id, n4, n5, tail, None, nodes3); + close Nodes::(alloc_id, n, prev, n3, n4, append(nodes1, nodes2)); + } +} + +lem Nodes_append__(n: Option>>) + req Nodes::(?alloc_id, n, ?prev, ?n1, ?n2, ?nodes1) &*& Nodes::(alloc_id, n2, n1, ?n3, Option::Some(?n4), ?nodes2) &*& (*NonNull_ptr(n4)).prev |-> n3; + ens Nodes::(alloc_id, n, prev, n3, Some(n4), append(nodes1, nodes2)) &*& (*NonNull_ptr(n4)).prev |-> n3; +{ + open Nodes::(alloc_id, n, prev, n1, n2, nodes1); + if n == n2 { + } else { + assert n == Option::Some(?n_); + Nodes_append__((*NonNull_ptr(n_)).next); + close Nodes::(alloc_id, n, prev, n3, Some(n4), append(nodes1, nodes2)); + } +} + +pred_ctor elem_fbc(t: thread_id_t)(node: NonNull>) = (*NonNull_ptr(node)).element |-> ?elem &*& .own(t, elem); + +pred >.own(t, ll) = + Allocator(t, ll.alloc, ?alloc_id) &*& + Nodes(alloc_id, ll.head, None, ll.tail, None, ?nodes) &*& + ll.len == length(nodes) &*& + foreach(nodes, elem_fbc::(t)); + +lem Nodes_upcast() + req Nodes::(?alloc_id, ?head, ?prev, ?tail, ?next, ?nodes) &*& is_subtype_of::() == true; + ens Nodes::(alloc_id, upcast(head), upcast(prev), upcast(tail), upcast(next), upcast(nodes)); +{ + assume(false); +} + +lem LinkedList_own_mono() + req type_interp::() &*& type_interp::() &*& type_interp::() &*& type_interp::() &*& LinkedList_own::(?t, ?v) &*& is_subtype_of::() == true &*& is_subtype_of::() == true; + ens type_interp::() &*& type_interp::() &*& type_interp::() &*& type_interp::() &*& LinkedList_own::(t, LinkedList:: { head: upcast(v.head), tail: upcast(v.tail), len: upcast(v.len), alloc: upcast(v.alloc), marker: upcast(v.marker) }); +{ + open >.own(t, v); + LinkedList_upcast::(v); + assert Allocator(t, ?alloc, _); + std::alloc::Allocator_upcast::(alloc); + + assume(false); + + //close >.own(t, upcast(v)); +} + +lem LinkedList_elems_send(t0: thread_id_t, t1: thread_id_t) + req foreach(?nodes, elem_fbc::(t0)) &*& type_interp::() &*& is_Send(typeid(T)) == true; + ens foreach(nodes, elem_fbc::(t1)) &*& type_interp::(); +{ + open foreach(nodes, elem_fbc::(t0)); + match nodes { + nil => {} + cons(n, nodes0) => { + open elem_fbc::(t0)(n); + Send::send(t0, t1, (*NonNull_ptr(n)).element); + close elem_fbc::(t1)(n); + LinkedList_elems_send::(t0, t1); + } + } + close foreach(nodes, elem_fbc::(t1)); +} + +lem LinkedList_send(t1: thread_id_t) + req type_interp::() &*& type_interp::() &*& is_Send(typeid(T)) == true &*& is_Send(typeid(A)) == true &*& LinkedList_own::(?t0, ?v); + ens type_interp::() &*& type_interp::() &*& LinkedList_own::(t1, v); +{ + open >.own(t0, v); + assert Allocator(t0, ?alloc, _); + std::alloc::Allocator_send(t1, alloc); + LinkedList_elems_send::(t0, t1); + close >.own(t1, v); +} + +pred Nodes1(alloc_id: any, n: Option>>, prev: Option>>, last: Option>>, next: Option>>, nodes: list>>; prevs: list>>>, nexts: list>>>) = + match nodes { + nil => + n == next &*& last == prev &*& prevs == nil &*& nexts == nil, + cons(n_, nodes0) => + n == Option::Some(n_) &*& + alloc_block_in(alloc_id, NonNull_ptr(n_) as *u8, Layout::new_::>()) &*& struct_Node_padding(NonNull_ptr(n_)) &*& + (*NonNull_ptr(n_)).prev |-> prev &*& + (*NonNull_ptr(n_)).next |-> ?next0 &*& + pointer_within_limits(&(*NonNull_ptr(n_)).element) == true &*& + Nodes1(alloc_id, next0, n, last, next, nodes0, ?prevs0, ?nexts0) &*& + prevs == cons(prev, prevs0) &*& + nexts == cons(next0, nexts0) + }; + +lem_auto Nodes1_inv() + req [?f]Nodes1::(?alloc_id, ?head, ?prev, ?last, ?next, ?nodes, ?prevs, ?nexts); + ens [f]Nodes1::(alloc_id, head, prev, last, next, nodes, prevs, nexts) &*& length(prevs) == length(nodes) &*& length(nexts) == length(nodes); +{ + open [f]Nodes1::(alloc_id, head, prev, last, next, nodes, prevs, nexts); + match nodes { + nil => {} + cons(n, nodes0) => { + Nodes1_inv::(); + } + } + close [f]Nodes1::(alloc_id, head, prev, last, next, nodes, prevs, nexts); +} + +lem Nodes1_append(head: Option>>) + req [?f]Nodes1::(?alloc_id, head, ?prev, ?n1, ?n2, ?nodes1, ?prevs1, ?nexts1) &*& [f]Nodes1::(alloc_id, n2, n1, ?tail, ?next, ?nodes2, ?prevs2, ?nexts2); + ens [f]Nodes1::(alloc_id, head, prev, tail, next, append(nodes1, nodes2), append(prevs1, prevs2), append(nexts1, nexts2)); +{ + open Nodes1::(alloc_id, head, prev, n1, n2, nodes1, prevs1, nexts1); + match nodes1 { + nil => {} + cons(n, nodes10) => { + Nodes1_append::((*NonNull_ptr(n)).next); + close [f]Nodes1::(alloc_id, head, prev, tail, next, append(nodes1, nodes2), append(prevs1, prevs2), append(nexts1, nexts2)); + } + } +} + +lem Nodes1_split( + nodes1: list>>, + nodes2: list>>, + prevs1: list>>>, + prevs2: list>>>, + nexts1: list>>>, + nexts2: list>>>) + req [?f]Nodes1::(?alloc_id, ?head, ?prev, ?tail, ?next, append(nodes1, nodes2), append(prevs1, prevs2), append(nexts1, nexts2)) &*& length(prevs1) == length(nodes1) &*& length(nexts1) == length(nodes1); + ens [f]Nodes1::(alloc_id, head, prev, ?n2, ?n1, nodes1, prevs1, nexts1) &*& [f]Nodes1::(alloc_id, n1, n2, tail, next, nodes2, prevs2, nexts2); +{ + match nodes1 { + nil => { + match prevs1 { nil => {} cons(h, t) => {} } + match nexts1 { nil => {} cons(h, t) => {} } + open [f]Nodes1::(alloc_id, head, prev, tail, next, append(nodes1, nodes2), append(prevs1, prevs2), append(nexts1, nexts2)); + close [f]Nodes1::(alloc_id, head, prev, tail, next, nodes2, prevs2, nexts2); + close [f]Nodes1::(alloc_id, head, prev, prev, head, nil, nil, nil); + } + cons(n, nodes10) => { + match prevs1 { nil => {} cons(h, t) => {} } + match nexts1 { nil => {} cons(h, t) => {} } + open [f]Nodes1::(alloc_id, head, prev, tail, next, append(nodes1, nodes2), append(prevs1, prevs2), append(nexts1, nexts2)); + Nodes1_split(nodes10, nodes2, tail(prevs1), prevs2, tail(nexts1), nexts2); + assert [f]Nodes1::(alloc_id, _, _, ?n2, ?n1, nodes10, tail(prevs1), tail(nexts1)); + close [f]Nodes1::(alloc_id, head, prev, n2, n1, nodes1, prevs1, nexts1); + } + } +} + +lem Nodes_to_Nodes1() + req Nodes::(?alloc_id, ?n, ?prev, ?last, ?next, ?nodes); + ens Nodes1::(alloc_id, n, prev, last, next, nodes, _, _); +{ + open Nodes::(alloc_id, n, prev, last, next, nodes); + if n == next { + } else { + Nodes_to_Nodes1::(); + } + close Nodes1::(alloc_id, n, prev, last, next, nodes, _, _); +} + +lem Nodes1_to_Nodes() + req Nodes1::(?alloc_id, ?n, ?prev, ?last, None, ?nodes, _, _); + ens Nodes::(alloc_id, n, prev, last, None, nodes); +{ + open Nodes1::(alloc_id, n, prev, last, None, nodes, _, _); + match nodes { + nil => {} + cons(n_, nodes0) => { + Nodes1_to_Nodes::(); + } + } + close Nodes::(alloc_id, n, prev, last, None, nodes); +} + +pred_ctor LinkedList_frac_borrow_content(alloc_id: any, l: *LinkedList, head: Option>>, tail: Option>>, nodes: list>>, prevs: list>>>, nexts: list>>>)(;) = + (*l).head |-> head &*& (*l).tail |-> tail &*& Nodes1(alloc_id, head, None, tail, None, nodes, prevs, nexts) &*& + (*l).len |-> length(nodes) &*& struct_LinkedList_padding(l); + +inductive LinkedList_share_info = LinkedList_share_info(alloc_id: any, head: Option>>, tail: Option>>, nodes: list>>, prevs: list>>>, nexts: list>>>); + +pred_ctor elem_share(k: lifetime_t, t: thread_id_t)(node: NonNull>) = [_](.share(k, t, &(*NonNull_ptr(node)).element)); + +pred >.share(k, t, l) = + exists(LinkedList_share_info(?alloc_id, ?head, ?tail, ?nodes, ?prevs, ?nexts)) &*& + [_]frac_borrow(k, LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts)) &*& + [_](.share(k, t, &(*l).alloc)) &*& + [_]foreach(nodes, elem_share::(k, t)); + +pred True() = true; + +fix elem_fbcs(t: thread_id_t, nodes: list>>) -> pred() { + match nodes { + nil => True, + cons(n, nodes0) => sep(.full_borrow_content(t, &(*NonNull_ptr(n)).element), elem_fbcs(t, nodes0)) + } +} + +lem LinkedList_share_full(k: lifetime_t, t: thread_id_t, l: *LinkedList) + req type_interp::() &*& type_interp::() &*& atomic_mask(Nlft) &*& full_borrow(k, LinkedList_full_borrow_content::(t, l)) &*& [?q]lifetime_token(k); + ens type_interp::() &*& type_interp::() &*& atomic_mask(Nlft) &*& [_]LinkedList_share::(k, t, l) &*& [q]lifetime_token(k); +{ + let klong = open_full_borrow_strong_m(k, LinkedList_full_borrow_content::(t, l), q); + open LinkedList_full_borrow_content::(t, l)(); + open >.own(t, ?self_); + assert Nodes(?alloc_id, ?head, None, ?tail, None, ?nodes); + Nodes_to_Nodes1::(); + assert Nodes1(alloc_id, head, None, tail, None, nodes, ?prevs, ?nexts); + close LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts)(); + { + lem iter(nodes_left: list>>) + req foreach(nodes_left, elem_fbc::(t)); + ens elem_fbcs::(t, nodes_left)(); + { + open foreach(nodes_left, elem_fbc::(t)); + match nodes_left { + nil => { + close True(); + } + cons(n, nodes_left0) => { + iter(nodes_left0); + open elem_fbc::(t)(n); + close_full_borrow_content::(t, &(*NonNull_ptr(n)).element); + close sep(.full_borrow_content(t, &(*NonNull_ptr(n)).element), elem_fbcs(t, nodes_left0))(); + assert sep(.full_borrow_content(t, &(*NonNull_ptr(n)).element), elem_fbcs(t, nodes_left0)) == elem_fbcs::(t, nodes_left); + } + } + } + iter(nodes); + } + close sep(LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts), elem_fbcs::(t, nodes))(); + std::alloc::close_Allocator_full_borrow_content_::(t, &(*l).alloc); + { + pred Ctx() = (*l).marker |-> ?_; + close sep(std::alloc::Allocator_full_borrow_content_::(t, &(*l).alloc, alloc_id), sep(LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts), elem_fbcs::(t, nodes)))(); + produce_lem_ptr_chunk full_borrow_convert_strong(Ctx, sep(std::alloc::Allocator_full_borrow_content_::(t, &(*l).alloc, alloc_id), sep(LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts), elem_fbcs::(t, nodes))), klong, LinkedList_full_borrow_content::(t, l))() { + open Ctx(); + open sep(std::alloc::Allocator_full_borrow_content_::(t, &(*l).alloc, alloc_id), sep(LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts), elem_fbcs::(t, nodes)))(); + open sep(LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts), elem_fbcs::(t, nodes))(); + open LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts)(); + { + lem iter(nodes_left: list>>) + req elem_fbcs::(t, nodes_left)(); + ens foreach(nodes_left, elem_fbc::(t)); + { + match nodes_left { + nil => { open True(); } + cons(n, nodes_left0) => { + open sep(.full_borrow_content(t, &(*NonNull_ptr(n)).element), elem_fbcs::(t, nodes_left0))(); + iter(nodes_left0); + open_full_borrow_content::(t, &(*NonNull_ptr(n)).element); + close elem_fbc::(t)(n); + } + } + close foreach(nodes_left, elem_fbc::(t)); + } + iter(nodes); + } + Nodes1_to_Nodes::(); + std::alloc::open_Allocator_full_borrow_content_::(t, &(*l).alloc, alloc_id); + + close >.own(t, *l); + close LinkedList_full_borrow_content::(t, l)(); + } { + close Ctx(); + close_full_borrow_strong_m(klong, LinkedList_full_borrow_content::(t, l), sep(std::alloc::Allocator_full_borrow_content_::(t, &(*l).alloc, alloc_id), sep(LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts), elem_fbcs::(t, nodes)))); + } + } + full_borrow_mono(klong, k, sep(std::alloc::Allocator_full_borrow_content_::(t, &(*l).alloc, alloc_id), sep(LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts), elem_fbcs::(t, nodes)))); + full_borrow_split_m(k, std::alloc::Allocator_full_borrow_content_::(t, &(*l).alloc, alloc_id), sep(LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts), elem_fbcs::(t, nodes))); + full_borrow_split_m(k, LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts), elem_fbcs::(t, nodes)); + full_borrow_into_frac_m(k, LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts)); + { + lem iter(nodes_left: list>>) + req type_interp::() &*& atomic_mask(Nlft) &*& [q]lifetime_token(k) &*& full_borrow(k, elem_fbcs::(t, nodes_left)); + ens type_interp::() &*& atomic_mask(Nlft) &*& [q]lifetime_token(k) &*& foreach(nodes_left, elem_share::(k, t)); + { + match nodes_left { + nil => { + leak full_borrow(_, _); + close foreach(nodes_left, elem_share::(k, t)); + } + cons(n, nodes_left0) => { + full_borrow_split_m(k, .full_borrow_content(t, &(*NonNull_ptr(n)).element), elem_fbcs::(t, nodes_left0)); + share_full_borrow_m::(k, t, &(*NonNull_ptr(n)).element); + iter(nodes_left0); + close elem_share::(k, t)(n); + close foreach(nodes_left, elem_share::(k, t)); + } + } + } + iter(nodes); + } + close exists(LinkedList_share_info(alloc_id, head, tail, nodes, prevs, nexts)); + std::alloc::share_Allocator_full_borrow_content_::(k, t, &(*l).alloc, alloc_id); + leak foreach(nodes, _); + close >.share()(k, t, l); + leak >.share(k, t, l); +} + +lem LinkedList_share_mono(k: lifetime_t, k1: lifetime_t, t: thread_id_t, l: *LinkedList) + req type_interp::() &*& type_interp::() &*& lifetime_inclusion(k1, k) == true &*& [_]LinkedList_share::(k, t, l); + ens type_interp::() &*& type_interp::() &*& [_]LinkedList_share::(k1, t, l); +{ + open >.share(k, t, l); + assert [_]exists(LinkedList_share_info(?alloc_id, ?head, ?tail, ?nodes, ?prevs, ?nexts)); + close exists(LinkedList_share_info(alloc_id, head, tail, nodes, prevs, nexts)); + frac_borrow_mono(k, k1, LinkedList_frac_borrow_content::(alloc_id, l, head, tail, nodes, prevs, nexts)); + { + lem iter() + req [_]foreach(?nodes1, elem_share::(k, t)) &*& type_interp::(); + ens foreach(nodes1, elem_share::(k1, t)) &*& type_interp::(); + { + open foreach(nodes1, elem_share::(k, t)); + match nodes1 { + nil => { + open foreach(nil, _); + } + cons(n, nodes0) => { + open elem_share::(k, t)(n); + share_mono::(k, k1, t, &(*NonNull_ptr(n)).element); + close elem_share::(k1, t)(n); + iter(); + } + } + close foreach(nodes1, elem_share::(k1, t)); + } + iter(); + } + share_mono::(k, k1, t, &(*l).alloc); + leak foreach(nodes, _); + close >.share(k1, t, l); + leak >.share(k1, t, l); +} + +pred ref_end_token_Option_NonNull(p: *Option>, x: *Option>, f: real, v: Option>) = + [f/2](*x |-> v) &*& ref_end_token(p, x, f/2) &*& (if v != Option::None { ref_end_token(std::option::Option_Some_0_ptr(p), std::option::Option_Some_0_ptr(x), f/2) } else { true }); + +lem init_ref_Option_NonNull(p: *Option>) + req ref_init_perm(p, ?x) &*& [?f](*x |-> ?v); + ens [f/2](*p |-> v) &*& ref_initialized(p) &*& ref_end_token_Option_NonNull(p, x, f, v); +{ + match v { + Option::None => { + std::option::init_ref_Option_None(p, 1/2); + } + Option::Some(v0) => { + std::option::open_points_to_Option_Some(x); + std::option::open_ref_init_perm_Option_Some(p); + std::ptr::init_ref_NonNull(std::option::Option_Some_0_ptr(p), 1/2); + std::option::init_ref_Option_Some(p, 1/2); + std::option::close_points_to_Option_Some(p); + std::option::close_points_to_Option_Some(x); + } + } + close ref_end_token_Option_NonNull(p, x, f, v); +} + +lem end_ref_Option_NonNull(p: *Option>) + req ref_initialized(p) &*& ref_end_token_Option_NonNull(p, ?x, ?f, ?v) &*& [f/2](*p |-> v); + ens [f](*x |-> v); +{ + open ref_end_token_Option_NonNull(p, x, f, v); + match v { + Option::None => { + std::option::end_ref_Option_None(p); + } + Option::Some(v0) => { + std::option::open_points_to_Option_Some(p); + std::option::end_ref_Option_Some(p); + std::ptr::end_ref_NonNull(std::option::Option_Some_0_ptr(p)); + std::option::close_points_to_Option_Some(x); + } + } +} + +lem init_ref_LinkedList(p: *LinkedList) + req type_interp::() &*& type_interp::() &*& atomic_mask(Nlft) &*& ref_init_perm(p, ?x) &*& [_]LinkedList_share::(?k, ?t, x) &*& [?q]lifetime_token(k); + ens type_interp::() &*& type_interp::() &*& atomic_mask(Nlft) &*& [q]lifetime_token(k) &*& [_]LinkedList_share::(k, t, p) &*& [_]frac_borrow(k, ref_initialized_(p)); +{ + open >.share(k, t, x); + assert [_]exists(LinkedList_share_info(?alloc_id, ?head, ?tail, ?nodes, ?prevs, ?nexts)); + close exists(LinkedList_share_info(alloc_id, head, tail, nodes, prevs, nexts)); + open_ref_init_perm_LinkedList(p); + leak ref_init_perm(&(*p).marker, _); + + { + pred R(;) = ref_initialized(&(*p).head) &*& ref_initialized(&(*p).tail) &*& ref_initialized(&(*p).len) &*& ref_padding_initialized(p); + { + let klong = open_frac_borrow_strong_m(k, LinkedList_frac_borrow_content::(alloc_id, x, head, tail, nodes, prevs, nexts), q); + open [?f]LinkedList_frac_borrow_content::(alloc_id, x, head, tail, nodes, prevs, nexts)(); + init_ref_Option_NonNull(&(*p).head); + init_ref_Option_NonNull(&(*p).tail); + init_ref_padding_LinkedList(p, 1/2); + std::num::init_ref_usize(&(*p).len, 1/2); + close [f/2]LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts)(); + close scaledp(f/2, LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts))(); + close R(); + { + pred Ctx() = + ref_end_token_Option_NonNull(&(*p).head, &(*x).head, f, head) &*& + ref_end_token_Option_NonNull(&(*p).tail, &(*x).tail, f, tail) &*& + [f/2]Nodes1(alloc_id, head, None, tail, None, nodes, prevs, nexts) &*& + [f/2](*x).len |-> length(nodes) &*& ref_end_token(&(*p).len, &(*x).len, f/2) &*& + [f/2]struct_LinkedList_padding(x) &*& ref_padding_end_token(p, x, f/2); + close Ctx(); + close sep(scaledp(f/2, LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts)), R)(); + produce_lem_ptr_chunk frac_borrow_convert_strong(Ctx, sep(scaledp(f/2, LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts)), R), klong, f, LinkedList_frac_borrow_content::(alloc_id, x, head, tail, nodes, prevs, nexts))() { + open Ctx(); + open sep(scaledp(f/2, LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts)), R)(); + open scaledp(f/2, LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts))(); + open [f/2]LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts)(); + open R(); + end_ref_Option_NonNull(&(*p).head); + end_ref_Option_NonNull(&(*p).tail); + std::num::end_ref_usize(&(*p).len); + end_ref_padding_LinkedList(p); + close [f]LinkedList_frac_borrow_content::(alloc_id, x, head, tail, nodes, prevs, nexts)(); + } { + close_frac_borrow_strong_m(); + full_borrow_mono(klong, k, sep(scaledp(f/2, LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts)), R)); + full_borrow_split_m(k, scaledp(f/2, LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts)), R); + full_borrow_into_frac_m(k, scaledp(f/2, LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts))); + frac_borrow_implies_scaled(k, f/2, LinkedList_frac_borrow_content::(alloc_id, p, head, tail, nodes, prevs, nexts)); + full_borrow_into_frac_m(k, R); + } + } + } + + init_ref_share_m::(k, t, &(*p).alloc); + close >.share(k, t, p); + leak >.share(k, t, p); + + frac_borrow_sep(k, ref_initialized_(&(*p).alloc), R); + produce_lem_ptr_chunk implies_frac(sep_(ref_initialized_(&(*p).alloc), R), ref_initialized_(p))() { + open [?f]sep_(ref_initialized_(&(*p).alloc), R)(); + open [f]ref_initialized_::(&(*p).alloc)(); + open [f]R(); + std::marker::close_ref_initialized_PhantomData(&(*p).marker, f); + close_ref_initialized_LinkedList(p); + close [f]ref_initialized_::>(p)(); + } { + produce_lem_ptr_chunk implies_frac(ref_initialized_(p), sep_(ref_initialized_(&(*p).alloc), R))() { + open [?f]ref_initialized_::>(p)(); + open_ref_initialized_LinkedList(p); + close [f]ref_initialized_::(&(*p).alloc)(); + close [f]R(); + close [f]sep_(ref_initialized_(&(*p).alloc), R)(); + leak [f]ref_initialized(&(*p).marker); + } { + frac_borrow_implies(k, sep_(ref_initialized_(&(*p).alloc), R), ref_initialized_(p)); + } + } + } +} + +lem LinkedList_sync(t1: thread_id_t) + req type_interp::() &*& type_interp::() &*& is_Sync(typeid(T)) == true &*& is_Sync(typeid(A)) == true &*& [_]LinkedList_share::(?k, ?t0, ?l); + ens type_interp::() &*& type_interp::() &*& [_]LinkedList_share::(k, t1, l); +{ + open >.share(k, t0, l); + assert [_]exists(LinkedList_share_info(?alloc_id, ?head, ?tail, ?nodes_, ?prevs, ?nexts)); + close exists(LinkedList_share_info(alloc_id, head, tail, nodes_, prevs, nexts)); + { + lem iter() + req [_]foreach(?nodes, elem_share::(k, t0)) &*& type_interp::(); + ens foreach(nodes, elem_share::(k, t1)) &*& type_interp::(); + { + open foreach(nodes, elem_share::(k, t0)); + match nodes { + nil => {} + cons(n, nodes0) => { + open elem_share::(k, t0)(n); + Sync::sync::(k, t0, t1, &(*NonNull_ptr(n)).element); + close elem_share::(k, t1)(n); + iter(); + } + } + close foreach(nodes, elem_share::(k, t1)); + } + iter(); + } + Sync::sync::(k, t0, t1, &(*l).alloc); + leak foreach(_, _); + close >.share(k, t1, l); + leak >.share(k, t1, l); +} + +@*/ + +/// An iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by [`LinkedList::iter()`]. See its +/// documentation for more. +#[must_use = "iterators are lazy and do nothing unless consumed"] +//#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, T: 'a> { + head: Option>>, + tail: Option>>, + len: usize, + marker: PhantomData<&'a Node>, +} + +/*@ + +inductive Iter_info = Iter_info( + alloc_id: any, + head0: Option>>, + prev: Option>>, + next: Option>>, + tail0: Option>>, + nodes_before: list>>, + nodes: list>>, + nodes_after: list>>, + prevs_before: list>>>, + prevs: list>>>, + prevs_after: list>>>, + nexts_before: list>>>, + nexts: list>>>, + nexts_after: list>>>); + +pred_ctor Iter_frac_borrow_content( + alloc_id: any, + head0: Option>>, + head: Option>>, + prev: Option>>, + tail: Option>>, + next: Option>>, + tail0: Option>>, + nodes_before: list>>, + nodes: list>>, + nodes_after: list>>, + prevs_before: list>>>, + prevs: list>>>, + prevs_after: list>>>, + nexts_before: list>>>, + nexts: list>>>, + nexts_after: list>>> + )(;) = + Nodes1(alloc_id, head0, None, prev, head, nodes_before, prevs_before, nexts_before) &*& + Nodes1(alloc_id, head, prev, tail, next, nodes, prevs, nexts) &*& + Nodes1(alloc_id, next, tail, tail0, None, nodes_after, prevs_after, nexts_after); + +pred<'a, T> >.own(t, iter) = + exists(Iter_info(?alloc_id, ?head0, ?prev, ?next, ?tail0, ?nodes_before, ?nodes, ?nodes_after, ?prevs_before, ?prevs, ?prevs_after, ?nexts_before, ?nexts, ?nexts_after)) &*& + [_]frac_borrow('a, Iter_frac_borrow_content::(alloc_id, head0, iter.head, prev, iter.tail, next, tail0, nodes_before, nodes, nodes_after, prevs_before, prevs, prevs_after, nexts_before, nexts, nexts_after)) &*& + iter.len == length(nodes) &*& + [_]foreach(nodes, elem_share::('a, t)); + +lem Iter_own_mono<'a0, 'a1, T0, T1>() + req type_interp::() &*& type_interp::() &*& Iter_own::<'a0, T0>(?t, ?v) &*& lifetime_inclusion('a1, 'a0) == true &*& is_subtype_of::() == true; + ens type_interp::() &*& type_interp::() &*& Iter_own::<'a1, T1>(t, Iter::<'a1, T1> { head: upcast(v.head), tail: upcast(v.tail), len: upcast(v.len), marker: upcast(v.marker) }); +{ + assume(false); +} + +lem Iter_send<'a, T>(t1: thread_id_t) + req type_interp::() &*& Iter_own::<'a, T>(?t0, ?v) &*& is_Sync(typeid(T)) == true; + ens type_interp::() &*& Iter_own::<'a, T>(t1, v); +{ + open >.own(t0, v); + let k = 'a; + { + lem iter() + req [_]foreach(?nodes, elem_share::(k, t0)) &*& type_interp::(); + ens foreach(nodes, elem_share::(k, t1)) &*& type_interp::(); + { + open foreach(nodes, elem_share::(k, t0)); + match nodes { + nil => {} + cons(n, nodes0) => { + open elem_share::(k, t0)(n); + Sync::sync::(k, t0, t1, &(*NonNull_ptr(n)).element); + close elem_share::(k, t1)(n); + iter(); + } + } + close foreach(nodes, elem_share::(k, t1)); + } + iter(); + } + leak foreach(_, _); + close >.own(t1, v); +} + +@*/ + +//#[stable(feature = "collection_debug", since = "1.17.0")] +// impl fmt::Debug for Iter<'_, T> { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// f.debug_tuple("Iter") +// .field(&*mem::ManuallyDrop::new(LinkedList { +// head: self.head, +// tail: self.tail, +// len: self.len, +// alloc: Global, +// marker: PhantomData, +// })) +// .field(&self.len) +// .finish() +// } +// } + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +//#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { + Iter { ..*self } + } +} + +/// A mutable iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by [`LinkedList::iter_mut()`]. See its +/// documentation for more. +#[must_use = "iterators are lazy and do nothing unless consumed"] +//#[stable(feature = "rust1", since = "1.0.0")] +pub struct IterMut<'a, T: 'a> { + head: Option>>, + tail: Option>>, + len: usize, + marker: PhantomData<&'a mut Node>, +} + +//#[stable(feature = "collection_debug", since = "1.17.0")] +// impl fmt::Debug for IterMut<'_, T> { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// f.debug_tuple("IterMut") +// .field(&*mem::ManuallyDrop::new(LinkedList { +// head: self.head, +// tail: self.tail, +// len: self.len, +// alloc: Global, +// marker: PhantomData, +// })) +// .field(&self.len) +// .finish() +// } +// } + +/// An owning iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`into_iter`] method on [`LinkedList`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// +/// [`into_iter`]: LinkedList::into_iter +#[derive(Clone)] +//#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoIter< + T, + /*#[unstable(feature = "allocator_api", issue = "32838")]*/ A: Allocator = Global, +> { + list: LinkedList, +} + +//#[stable(feature = "collection_debug", since = "1.17.0")] +// impl fmt::Debug for IntoIter { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// f.debug_tuple("IntoIter").field(&self.list).finish() +// } +// } + +impl Node { + unsafe fn new(element: T) -> Self + //@ req true; + //@ ens result == Node:: { next: None, prev: None, element }; + { + Node { next: None, prev: None, element } + } + + unsafe fn into_element(self: Box) -> T + //@ req thread_token(?t) &*& Box_in::, A>(t, self, ?alloc_id, ?node); + //@ ens thread_token(t) &*& result == node.element &*& Allocator::(t, _, alloc_id); + { + Box::into_inner(self).element // self.element + } +} + +// private methods +impl LinkedList { + /// Adds the given node to the front of the list. + /// + /// # Safety + /// `node` must point to a valid node that was boxed and leaked using the list's allocator. + /// This method takes ownership of the node, so the pointer should not be used again. + #[inline] + unsafe fn push_front_node(&mut self, node: NonNull>) + /*@ + req thread_token(?t) &*& *self |-> ?self0 &*& Allocator(t, self0.alloc, ?alloc_id) &*& Nodes(alloc_id, self0.head, None, self0.tail, None, ?nodes) &*& + length(nodes) == self0.len &*& foreach(nodes, elem_fbc::(t)) &*& + *NonNull_ptr(node) |-> ?n &*& .own(t, n.element) &*& alloc_block_in(alloc_id, NonNull_ptr(node) as *u8, Layout::new_::>()); + @*/ + //@ ens thread_token(t) &*& *self |-> ?self1 &*& >.own(t, self1); + { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. + unsafe { + //@ open_points_to(self); + (*node.as_ptr()).next = self.head; + (*node.as_ptr()).prev = None; + let node_ = Some(node); + + //@ open Nodes(_, _, _, _, _, _); + match self.head { + None => { + //@ close Nodes::(alloc_id, None, None, None, None, nil); + self.tail = node_ + } + // Not creating new mutable (unique!) references overlapping `element`. + Some(head) => { + (*head.as_ptr()).prev = node_; + //@ close Nodes(alloc_id, self0.head, node_, self0.tail, None, nodes); + } + } + + self.head = node_; + //@ assume(self0.len < usize::MAX); + self.len += 1; + //@ close_points_to(self); + //@ assert *self |-> ?self1; + //@ points_to_limits(&(*NonNull_ptr(node)).element); + //@ close Nodes(alloc_id, node_, None, self1.tail, None, cons(node, nodes)); + //@ close elem_fbc::(t)(node); + //@ close foreach(cons(node, nodes), elem_fbc::(t)); + //@ close >.own(t, self1); + } + } + + /// Removes and returns the node at the front of the list. + #[inline] + unsafe fn pop_front_node<'a>(&'a mut self) -> Option, &'a A>> + /*@ + req thread_token(?t) &*& + *self |-> ?self0 &*& + Allocator(t, self0.alloc, ?alloc_id) &*& + Nodes(alloc_id, self0.head, None, self0.tail, None, ?nodes0) &*& + length(nodes0) == self0.len &*& + foreach(nodes0, elem_fbc::(t)); + @*/ + /*@ + ens thread_token(t) &*& + (*self).head |-> ?head1 &*& + (*self).tail |-> ?tail1 &*& + Nodes(alloc_id, head1, None, tail1, None, ?nodes1) &*& + (*self).len |-> length(nodes1) &*& + struct_LinkedList_padding::(self) &*& + foreach(nodes1, elem_fbc::(t)) &*& + match result { + Option::None => (*self).alloc |-> ?alloc1 &*& Allocator(t, alloc1, alloc_id), + Option::Some(b) => std::alloc::ref_Allocator_end_token::(?p, &(*self).alloc, alloc_id) &*& ref_initialized(p) &*& Box_in::, &'a A>(t, b, alloc_id, ?node) &*& .own(t, node.element) + }; + // *NonNull_ptr(node) |-> ?n &*& .own(t, n.element) &*& alloc_block_in(alloc_id, NonNull_ptr(node) as *u8, Layout::new_::>()); + @*/ + { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. + //@ open_points_to(self); + match self.head { + None => None, + Some(node) => unsafe { + //@ open Nodes(_, _, _, _, _, _); + //@ open foreach(nodes0, elem_fbc::(t)); + //@ open elem_fbc::(t)(node); + //@ let alloc_ref = precreate_ref(&(*self).alloc); + //@ std::alloc::init_ref_Allocator::<'static, A>(alloc_ref); + self.head = (*node.as_ptr()).next; + let node_ = Box::from_raw_in(node.as_ptr(), &self.alloc); + + //@ open Nodes(_, ?next, _, ?tail, _, _); + match self.head { + None => self.tail = None, + // Not creating new mutable (unique!) references overlapping `element`. + Some(head) => (*head.as_ptr()).prev = None, + } + //@ close Nodes(alloc_id, next, None, (*self).tail, None, _); + + self.len -= 1; + Some(node_) + } + } + } + + /// Adds the given node to the back of the list. + /// + /// # Safety + /// `node` must point to a valid node that was boxed and leaked using the list's allocator. + /// This method takes ownership of the node, so the pointer should not be used again. + #[inline] + unsafe fn push_back_node(&mut self, node: NonNull>) { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. + unsafe { + (*node.as_ptr()).next = None; + (*node.as_ptr()).prev = self.tail; + let node_ = Some(node); + + match self.tail { + None => self.head = node_, + // Not creating new mutable (unique!) references overlapping `element`. + Some(tail) => (*tail.as_ptr()).next = node_, + } + + self.tail = node_; + self.len += 1; + } + } + + /// Removes and returns the node at the back of the list. + #[inline] + fn pop_back_node(&mut self) -> Option, &A>> { + // This method takes care not to create mutable references to whole nodes, + // to maintain validity of aliasing pointers into `element`. + match self.tail { + None => None, + Some(node) => unsafe { + let node_ = Box::from_raw_in(node.as_ptr(), &self.alloc); + self.tail = node_.prev; + + match self.tail { + None => self.head = None, + // Not creating new mutable (unique!) references overlapping `element`. + Some(tail) => (*tail.as_ptr()).next = None, + } + + self.len -= 1; + Some(node_) + } + } + } + + /// Unlinks the specified node from the current list. + /// + /// Warning: this will not check that the provided node belongs to the current list. + /// + /// This method takes care not to create mutable references to `element`, to + /// maintain validity of aliasing pointers. + #[inline] + unsafe fn unlink_node(&mut self, mut node: NonNull>) + /*@ + req (*self).head |-> ?head &*& (*self).tail |-> ?tail &*& + Nodes::(?alloc_id, head, None, ?prev_, Some(node), ?nodes1) &*& + alloc_block_in(alloc_id, NonNull_ptr(node) as *u8, Layout::new_::>()) &*& + (*NonNull_ptr(node)).next |-> ?next_ &*& + (*NonNull_ptr(node)).prev |-> prev_ &*& + struct_Node_padding(NonNull_ptr(node)) &*& + Nodes::(alloc_id, next_, Some(node), tail, None, ?nodes2) &*& + (*self).len |-> length(nodes1) + 1 + length(nodes2); + @*/ + /*@ + ens (*self).head |-> ?head1 &*& (*self).tail |-> ?tail1 &*& + Nodes::(alloc_id, head1, None, prev_, next_, nodes1) &*& + alloc_block_in(alloc_id, NonNull_ptr(node) as *u8, Layout::new_::>()) &*& + (*NonNull_ptr(node)).next |-> next_ &*& + (*NonNull_ptr(node)).prev |-> prev_ &*& + struct_Node_padding(NonNull_ptr(node)) &*& + Nodes::(alloc_id, next_, prev_, tail1, None, nodes2) &*& + (*self).len |-> length(nodes1) + length(nodes2); + @*/ + { + let node_ = unsafe { node.as_mut() }; // this one is ours now, we can create an &mut. + + // Not creating new mutable (unique!) references overlapping `element`. + match node_.prev { + Some(prev) => unsafe { + //@ Nodes_last_lemma(head); + //@ Nodes_split_off_last(head); + //@ assert Nodes(_, head, None, ?pprev, prev_, ?nodes10); + (*prev.as_ptr()).next = node_.next; + //@ open Nodes(alloc_id, next_, Some(node), tail, None, nodes2); + //@ close Nodes(alloc_id, next_, Some(node), tail, None, nodes2); + //@ close Nodes::(alloc_id, next_, prev_, prev_, next_, []); + //@ close Nodes::(alloc_id, prev_, pprev, prev_, next_, [prev]); + //@ Nodes_append_(head); + }, + // this node is the head node + None => { + //@ Nodes_last_lemma(head); + //@ open Nodes(alloc_id, head, _, _, _, nodes1); + //@ close Nodes(alloc_id, next_, None, None, next_, []); + self.head = node_.next + } + }; + + match node_.next { + Some(next) => unsafe { + //@ open Nodes(alloc_id, next_, Some(node), tail, None, nodes2); + (*next.as_ptr()).prev = node_.prev; + //@ close Nodes(alloc_id, next_, prev_, tail, None, nodes2); + }, + // this node is the tail node + None => { + //@ open Nodes(alloc_id, next_, Some(node), _, _, nodes2); + //@ close Nodes(alloc_id, next_, prev_, prev_, next_, []); + self.tail = node_.prev; + + } + }; + + self.len -= 1; + } + + /// Splices a series of nodes between two existing nodes. + /// + /// Warning: this will not check that the provided node belongs to the two existing lists. + #[inline] + unsafe fn splice_nodes( + &mut self, + existing_prev: Option>>, + existing_next: Option>>, + mut splice_start: NonNull>, + mut splice_end: NonNull>, + splice_length: usize, + ) { + // This method takes care not to create multiple mutable references to whole nodes at the same time, + // to maintain validity of aliasing pointers into `element`. + if let Some(mut existing_prev_) = existing_prev { + unsafe { + existing_prev_.as_mut().next = Some(splice_start); + } + } else { + self.head = Some(splice_start); + } + if let Some(mut existing_next_) = existing_next { + unsafe { + existing_next_.as_mut().prev = Some(splice_end); + } + } else { + self.tail = Some(splice_end); + } + unsafe { + splice_start.as_mut().prev = existing_prev; + splice_end.as_mut().next = existing_next; + } + + self.len += splice_length; + } + + /// Detaches all nodes from a linked list as a series of nodes. + #[inline] + fn detach_all_nodes(mut self) -> Option<(NonNull>, NonNull>, usize)> { + let head = self.head.take(); + let tail = self.tail.take(); + let len = mem::replace(&mut self.len, 0); + if let Some(head) = head { + // SAFETY: In a LinkedList, either both the head and tail are None because + // the list is empty, or both head and tail are Some because the list is populated. + // Since we have verified the head is Some, we are sure the tail is Some too. + let tail = unsafe { tail.unwrap_unchecked() }; + Some((head, tail, len)) + } else { + None + } + } + + #[inline] + unsafe fn split_off_before_node( + &mut self, + split_node: Option>>, + at: usize, + ) -> Self + where + A: Clone, + { + // The split node is the new head node of the second part + if let Some(mut split_node) = split_node { + let first_part_head; + let first_part_tail; + unsafe { + first_part_tail = split_node.as_mut().prev.take(); + } + if let Some(mut tail) = first_part_tail { + unsafe { + tail.as_mut().next = None; + } + first_part_head = self.head; + } else { + first_part_head = None; + } + + let first_part = LinkedList { + head: first_part_head, + tail: first_part_tail, + len: at, + alloc: self.alloc.clone(), + marker: PhantomData, + }; + + // Fix the head ptr of the second part + self.head = Some(split_node); + self.len = self.len - at; + + first_part + } else { + mem::replace(self, LinkedList::new_in(self.alloc.clone())) + } + } + + #[inline] + unsafe fn split_off_after_node( + &mut self, + split_node: Option>>, + at: usize, + ) -> Self + where + A: Clone, + /*@ + req thread_token(?t) &*& + (*self).alloc |-> ?alloc0 &*& Allocator::(t, alloc0, ?alloc_id) &*& + (*self).head |-> ?head0 &*& + (*self).tail |-> ?tail0 &*& + struct_LinkedList_padding(self) &*& + Nodes::(alloc_id, head0, None, split_node, ?next0, ?nodes1) &*& + Nodes::(alloc_id, next0, split_node, tail0, None, ?nodes2) &*& + foreach(nodes1, elem_fbc::(t)) &*& + foreach(nodes2, elem_fbc::(t)) &*& + (*self).len |-> length(nodes1) + length(nodes2) &*& + length(nodes1) == at; + @*/ + /*@ + ens thread_token(t) &*& + *self |-> ?self1 &*& >.own(t, self1) &*& + >.own(t, result); + @*/ + { + // The split node is the new tail node of the first part and owns + // the head of the second part. + if let Some(mut split_node_) = split_node { + //@ Nodes_last_lemma(head0); + //@ Nodes_split_off_last(head0); + //@ assert Nodes(alloc_id, head0, None, ?prev0, split_node, ?nodes10); + let second_part_head; + let second_part_tail; + unsafe { + second_part_head = split_node_.as_mut().next.take(); + } + //@ open Nodes(_, next0, split_node, tail0, None, nodes2); + if let Some(mut head) = second_part_head { + unsafe { + head.as_mut().prev = None; + } + second_part_tail = self.tail; + //@ close Nodes::(alloc_id, next0, None, tail0, None, nodes2); + } else { + //@ close Nodes::(alloc_id, next0, None, None, None, nodes2); + second_part_tail = None; + } + + //@ let alloc_ref = precreate_ref(&(*self).alloc); + //@ std::alloc::init_ref_Allocator::<'static, A>(alloc_ref); + let second_part = LinkedList { + head: second_part_head, + tail: second_part_tail, + len: self.len - at, + alloc: clone_allocator(&self.alloc), + marker: PhantomData, + }; + //@ std::alloc::end_ref_Allocator::<'static, A>(); + + // Fix the tail ptr of the first part + self.tail = Some(split_node_); + self.len = at; + //@ close Nodes::(alloc_id, None, split_node, split_node, None, []); + //@ close Nodes::(alloc_id, split_node, prev0, split_node, None, [split_node_]); + //@ Nodes_append(head0); + //@ close_points_to(self); + //@ close >.own(t, *self); + //@ assert Nodes(_, _, _, _, _, nodes2); + //@ assert length(nodes2) == second_part.len; + //@ close >.own(t, second_part); + second_part + } else { + //@ let alloc_ref = precreate_ref(&(*self).alloc); + //@ std::alloc::init_ref_Allocator::<'static, A>(alloc_ref); + let alloc = clone_allocator(&self.alloc); + //@ std::alloc::end_ref_Allocator::<'static, A>(); + //@ std::alloc::Allocator_to_own::(alloc); + //@ close_points_to(self); + //@ Nodes_append(head0); + //@ foreach_append(nodes1, nodes2); + //@ close >.own(t, *self); + let r = LinkedList::new_in(alloc); + mem::replace(self, r) + } + } +} + +unsafe fn clone_allocator<'a, A: Allocator + Clone>(alloc: &'a A) -> A +//@ req thread_token(?t) &*& Allocator::<&'a A>(t, alloc, ?alloc_id); +//@ ens thread_token(t) &*& Allocator::<&'a A>(t, _, alloc_id) &*& Allocator::(t, result, alloc_id); +{ + //@ assume(false); //~allow_dead_code + alloc.clone() //~allow_dead_code +} //~allow_dead_code + +//#[stable(feature = "rust1", since = "1.0.0")] +impl Default for LinkedList { + /// Creates an empty `LinkedList`. + #[inline] + fn default() -> Self { + Self::new() + } +} + +impl LinkedList { + /// Creates an empty `LinkedList`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let list: LinkedList = LinkedList::new(); + /// ``` + #[inline] + /*#[rustc_const_stable(feature = "const_linked_list_new", since = "1.39.0")]*/ + //#[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + pub const fn new() -> Self + //@ req thread_token(?t); + //@ ens thread_token(t) &*& >.own(t, result); + { + let r = LinkedList { head: None, tail: None, len: 0, alloc: Global, marker: PhantomData }; + //@ close foreach(nil, elem_fbc::(t)); + //@ std::alloc::produce_Allocator_Global(t); + //@ close >.own(t, r); + r + } + + /// Moves all elements from `other` to the end of the list. + /// + /// This reuses all the nodes from `other` and moves them into `self`. After + /// this operation, `other` becomes empty. + /// + /// This operation should compute in *O*(1) time and *O*(1) memory. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list1 = LinkedList::new(); + /// list1.push_back('a'); + /// + /// let mut list2 = LinkedList::new(); + /// list2.push_back('b'); + /// list2.push_back('c'); + /// + /// list1.append(&mut list2); + /// + /// let mut iter = list1.iter(); + /// assert_eq!(iter.next(), Some(&'a')); + /// assert_eq!(iter.next(), Some(&'b')); + /// assert_eq!(iter.next(), Some(&'c')); + /// assert!(iter.next().is_none()); + /// + /// assert!(list2.is_empty()); + /// ``` + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn append(&mut self, other: &mut Self) { + match self.tail { + None => mem::swap(self, other), + Some(mut tail) => { + // `as_mut` is okay here because we have exclusive access to the entirety + // of both lists. + if let Some(mut other_head) = other.head.take() { + unsafe { + tail.as_mut().next = Some(other_head); + other_head.as_mut().prev = Some(tail); + } + + self.tail = other.tail.take(); + self.len += mem::replace(&mut other.len, 0); + } + } + } + } +} + +impl LinkedList { + /// Constructs an empty `LinkedList`. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// use std::collections::LinkedList; + /// + /// let list: LinkedList = LinkedList::new_in(System); + /// ``` + #[inline] + /*#[unstable(feature = "allocator_api", issue = "32838")]*/ + pub const fn new_in(alloc: A) -> Self + //@ req thread_token(?t) &*& .own(t, alloc); + //@ ens thread_token(t) &*& >.own(t, result); + { + let r = LinkedList { head: None, tail: None, len: 0, alloc, marker: PhantomData }; + //@ std::alloc::open_Allocator_own::(alloc); + //@ close foreach(nil, elem_fbc::(t)); + //@ close >.own(t, r); + r + } + /// Provides a forward iterator. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// let mut iter = list.iter(); + /// assert_eq!(iter.next(), Some(&0)); + /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn iter<'a>(&'a self) -> Iter<'a, T> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& [_](>.share('a, t, self)); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& >.own(t, result); + { + //@ open >.share('a, t, self); + //@ assert [_]exists(LinkedList_share_info(?alloc_id, ?head, ?tail, ?nodes, ?prevs, ?nexts)); + //@ open_frac_borrow('a, LinkedList_frac_borrow_content::(alloc_id, self, head, tail, nodes, prevs, nexts), q); + //@ open [?qll]LinkedList_frac_borrow_content::(alloc_id, self, head, tail, nodes, prevs, nexts)(); + let r = Iter { head: self.head, tail: self.tail, len: self.len, marker: PhantomData }; + //@ close [qll]LinkedList_frac_borrow_content::(alloc_id, self, head, tail, nodes, prevs, nexts)(); + //@ close_frac_borrow(qll, LinkedList_frac_borrow_content::(alloc_id, self, head, tail, nodes, prevs, nexts)); + //@ close exists(Iter_info(alloc_id, head, None, None, tail, nil, nodes, nil, nil, prevs, nil, nil, nexts, nil)); + /*@ + { + pred R(;) = (*self).head |-> head &*& (*self).tail |-> tail &*& (*self).len |-> length(nodes) &*& struct_LinkedList_padding(self); + produce_lem_ptr_chunk implies_frac(LinkedList_frac_borrow_content::(alloc_id, self, head, tail, nodes, prevs, nexts), sep_(R, Iter_frac_borrow_content(alloc_id, head, head, None, tail, None, tail, nil, nodes, nil, nil, prevs, nil, nil, nexts, nil)))() { + open [?f]LinkedList_frac_borrow_content::(alloc_id, self, head, tail, nodes, prevs, nexts)(); + close [f]R(); + close [f]Iter_frac_borrow_content::(alloc_id, head, head, None, tail, None, tail, nil, nodes, nil, nil, prevs, nil, nil, nexts, nil)(); + close [f]sep_(R, Iter_frac_borrow_content::(alloc_id, head, head, None, tail, None, tail, nil, nodes, nil, nil, prevs, nil, nil, nexts, nil))(); + } { + produce_lem_ptr_chunk implies_frac(sep_(R, Iter_frac_borrow_content(alloc_id, head, head, None, tail, None, tail, nil, nodes, nil, nil, prevs, nil, nil, nexts, nil)), LinkedList_frac_borrow_content::(alloc_id, self, head, tail, nodes, prevs, nexts))() { + open [?f]sep_(R, Iter_frac_borrow_content::(alloc_id, head, head, None, tail, None, tail, nil, nodes, nil, nil, prevs, nil, nil, nexts, nil))(); + open [f]R(); + open [f]Iter_frac_borrow_content::(alloc_id, head, head, None, tail, None, tail, nil, nodes, nil, nil, prevs, nil, nil, nexts, nil)(); + close [f]LinkedList_frac_borrow_content::(alloc_id, self, head, tail, nodes, prevs, nexts)(); + } { + frac_borrow_implies('a, LinkedList_frac_borrow_content::(alloc_id, self, head, tail, nodes, prevs, nexts), sep_(R, Iter_frac_borrow_content(alloc_id, head, head, None, tail, None, tail, nil, nodes, nil, nil, prevs, nil, nil, nexts, nil))); + } + } + frac_borrow_split('a, R, Iter_frac_borrow_content(alloc_id, head, head, None, tail, None, tail, nil, nodes, nil, nil, prevs, nil, nil, nexts, nil)); + } + @*/ + //@ close >.own(t, r); + r + } + + /// Provides a forward iterator with mutable references. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// for element in list.iter_mut() { + /// *element += 10; + /// } + /// + /// let mut iter = list.iter(); + /// assert_eq!(iter.next(), Some(&10)); + /// assert_eq!(iter.next(), Some(&11)); + /// assert_eq!(iter.next(), Some(&12)); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn iter_mut(&mut self) -> IterMut<'_, T> { + IterMut { head: self.head, tail: self.tail, len: self.len, marker: PhantomData } + } + + /// Provides a cursor at the front element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. + #[inline] + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn cursor_front(&self) -> Cursor<'_, T, A> { + Cursor { index: 0, current: self.head, list: self } + } + + /// Provides a cursor with editing operations at the front element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. + #[inline] + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn cursor_front_mut<'a>(&'a mut self) -> CursorMut<'a, T, A> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, >.full_borrow_content(t, self)); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& >.own(t, result); + { + //@ let t1 = if is_Send(typeid(T)) && is_Send(typeid(A)) { default_tid } else { t }; + //@ let klong = open_full_borrow_strong('a, >.full_borrow_content(t, self), q); + //@ open >.full_borrow_content(t, self)(); + //@ let current = (*self).head; + let r = CursorMut { index: 0, current: self.head, list: self }; + //@ open >.own(t, *self); + //@ assert (*self).alloc |-> ?alloc &*& Allocator::(t, alloc, ?alloc_id); + //@ close Nodes(alloc_id, current, None, None, current, nil); + //@ close foreach(nil, elem_fbc::(t1)); + //@ let ghost_cell_id = create_ghost_cell::>>>>(pair(0, current)); + //@ produce_type_interp::(); + //@ produce_type_interp::(); + /*@ + if t1 != t { + std::alloc::Allocator_send(t1, alloc); + LinkedList_elems_send::(t, t1); + } + @*/ + //@ close CursorMut_fbc::(t1, ghost_cell_id, self)(); + /*@ + { + pred Ctx() = type_interp::() &*& type_interp::(); + produce_lem_ptr_chunk full_borrow_convert_strong(Ctx, CursorMut_fbc::(t1, ghost_cell_id, self), klong, >.full_borrow_content(t, self))() { + open Ctx(); + open CursorMut_fbc::(t1, ghost_cell_id, self)(); + assert [1/2]ghost_cell(ghost_cell_id, pair(?index1, ?current1)); + let head = (*self).head; + assert Nodes(_, head, None, ?before_current, current1, ?nodes1) &*& Nodes(_, current1, before_current, ?tail, None, ?nodes2); + Nodes_append::((*self).head); + foreach_append(nodes1, nodes2); + if t1 != t { + assert Allocator(_, ?alloc1, _); + std::alloc::Allocator_send(t, alloc1); + LinkedList_elems_send::(t1, t); + } + close >.own(t, *self); + close >.full_borrow_content(t, self)(); + leak [1/2]ghost_cell(_, _) &*& type_interp::() &*& type_interp::(); + } { + close Ctx(); + close_full_borrow_strong(klong, >.full_borrow_content(t, self), CursorMut_fbc::(t1, ghost_cell_id, self)); + full_borrow_mono(klong, 'a, CursorMut_fbc::(t1, ghost_cell_id, self)); + } + } + @*/ + //@ close >.own(t, r); + r + } + + /// Provides a cursor at the back element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. + #[inline] + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn cursor_back(&self) -> Cursor<'_, T, A> { + Cursor { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self } + } + + /// Provides a cursor with editing operations at the back element. + /// + /// The cursor is pointing to the "ghost" non-element if the list is empty. + #[inline] + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn cursor_back_mut<'a>(&'a mut self) -> CursorMut<'a, T, A> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, >.full_borrow_content(t, self)); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& >.own(t, result); + { + //@ let t1 = if is_Send(typeid(T)) && is_Send(typeid(A)) { default_tid } else { t }; + //@ let klong = open_full_borrow_strong('a, >.full_borrow_content(t, self), q); + //@ open >.full_borrow_content(t, self)(); + let r = CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }; + //@ open >.own(t, *self); + //@ assert (*self).alloc |-> ?alloc &*& Allocator::(t, alloc, ?alloc_id) &*& (*self).head |-> ?head_; + //@ Nodes_last_lemma(head_); + //@ produce_type_interp::(); + //@ produce_type_interp::(); + /*@ + if t1 != t { + std::alloc::Allocator_send::(t1, alloc); + LinkedList_elems_send::(t, t1); + } + @*/ + /*@ + match r.current { + Option::None => { + close Nodes::(alloc_id, None, None, None, None, []); + close foreach([], elem_fbc::(t1)); + } + Option::Some(tail_) => { + Nodes_split_off_last(head_); + assert Nodes(alloc_id, head_, _, _, _, ?nodes0); + close Nodes::(alloc_id, None, r.current, r.current, None, []); + close Nodes::(alloc_id, r.current, _, r.current, None, [tail_]); + foreach_unappend(nodes0, [tail_], elem_fbc::(t1)); + } + } + @*/ + //@ let ghost_cell_id = create_ghost_cell::>>>>(pair(r.index, r.current)); + //@ close CursorMut_fbc::(t1, ghost_cell_id, self)(); + /*@ + { + pred Ctx() = type_interp::() &*& type_interp::(); + produce_lem_ptr_chunk full_borrow_convert_strong(Ctx, CursorMut_fbc::(t1, ghost_cell_id, self), klong, >.full_borrow_content(t, self))() { + open Ctx(); + open CursorMut_fbc::(t1, ghost_cell_id, self)(); + assert [1/2]ghost_cell(ghost_cell_id, pair(?index1, ?current1)); + let head = (*self).head; + assert Nodes(_, head, None, ?before_current, current1, ?nodes1) &*& Nodes(_, current1, before_current, ?tail, None, ?nodes2); + Nodes_append::((*self).head); + foreach_append(nodes1, nodes2); + if t1 != t { + assert Allocator(_, ?alloc1, _); + std::alloc::Allocator_send(t, alloc1); + LinkedList_elems_send::(t1, t); + } + close >.own(t, *self); + close >.full_borrow_content(t, self)(); + leak [1/2]ghost_cell(_, _) &*& type_interp::() &*& type_interp::(); + } { + close Ctx(); + close_full_borrow_strong(klong, >.full_borrow_content(t, self), CursorMut_fbc::(t1, ghost_cell_id, self)); + full_borrow_mono(klong, 'a, CursorMut_fbc::(t1, ghost_cell_id, self)); + } + } + @*/ + //@ close >.own(t, r); + r + } + + /// Returns `true` if the `LinkedList` is empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert!(dl.is_empty()); + /// + /// dl.push_front("foo"); + /// assert!(!dl.is_empty()); + /// ``` + #[inline] + #[must_use] + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + self.head.is_none() + } + + /// Returns the length of the `LinkedList`. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// + /// dl.push_front(2); + /// assert_eq!(dl.len(), 1); + /// + /// dl.push_front(1); + /// assert_eq!(dl.len(), 2); + /// + /// dl.push_back(3); + /// assert_eq!(dl.len(), 3); + /// ``` + #[inline] + #[must_use] + //#[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("length", "size")] + pub fn len(&self) -> usize { + self.len + } + + /// Removes all elements from the `LinkedList`. + /// + /// This operation should compute in *O*(*n*) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// + /// dl.push_front(2); + /// dl.push_front(1); + /// assert_eq!(dl.len(), 2); + /// assert_eq!(dl.front(), Some(&1)); + /// + /// dl.clear(); + /// assert_eq!(dl.len(), 0); + /// assert_eq!(dl.front(), None); + /// ``` + #[inline] + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn clear(&mut self) + //@ req thread_token(?t) &*& *self |-> ?self0 &*& >.own(t, self0); + //@ ens thread_token(t) &*& *self |-> ?self1 &*& >.own(t, self1); + { + //@ open_points_to(self); + //@ open >.own(t, self0); + //@ let alloc_ref = precreate_ref(&(*self).alloc); + // We need to drop the nodes while keeping self.alloc + // We can do this by moving (head, tail, len) into a new list that borrows self.alloc + //@ let k = begin_lifetime(); + { + //@ let_lft 'a = k; + //@ std::alloc::init_ref_Allocator_at_lifetime::<'a, A>(alloc_ref); + let ll = LinkedList { + head: self.head.take(), + tail: self.tail.take(), + len: mem::replace(&mut self.len, 0), //mem::take(&mut self.len), + alloc: &self.alloc, + marker: PhantomData, + }; + //@ close >.own(t, ll); + drop/*@::> @*/(ll); + } + //@ end_lifetime(k); + //@ std::alloc::end_ref_Allocator_at_lifetime::(); + //@ close_points_to(self); + //@ close foreach(nil, elem_fbc::(t)); + //@ close >.own(t, *self); + } + + /// Returns `true` if the `LinkedList` contains an element equal to the + /// given value. + /// + /// This operation should compute linearly in *O*(*n*) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut list: LinkedList = LinkedList::new(); + /// + /// list.push_back(0); + /// list.push_back(1); + /// list.push_back(2); + /// + /// assert_eq!(list.contains(&0), true); + /// assert_eq!(list.contains(&10), false); + /// ``` + //#[stable(feature = "linked_list_contains", since = "1.12.0")] + pub fn contains(&self, x: &T) -> bool + where + T: PartialEq, + { + self.iter().any(|e| e == x) + } + + /// Provides a reference to the front element, or `None` if the list is + /// empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.front(), None); + /// + /// dl.push_front(1); + /// assert_eq!(dl.front(), Some(&1)); + /// ``` + #[inline] + #[must_use] + //#[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("first")] + pub fn front(&self) -> Option<&T> { + unsafe { self.head.as_ref().map(|node| &node.as_ref().element) } + } + + /// Provides a mutable reference to the front element, or `None` if the list + /// is empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.front(), None); + /// + /// dl.push_front(1); + /// assert_eq!(dl.front(), Some(&1)); + /// + /// match dl.front_mut() { + /// None => {}, + /// Some(x) => *x = 5, + /// } + /// assert_eq!(dl.front(), Some(&5)); + /// ``` + #[inline] + #[must_use] + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn front_mut(&mut self) -> Option<&mut T> { + unsafe { self.head.as_mut().map(|node| &mut node.as_mut().element) } + } + + /// Provides a reference to the back element, or `None` if the list is + /// empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.back(), None); + /// + /// dl.push_back(1); + /// assert_eq!(dl.back(), Some(&1)); + /// ``` + #[inline] + #[must_use] + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn back(&self) -> Option<&T> { + unsafe { self.tail.as_ref().map(|node| &node.as_ref().element) } + } + + /// Provides a mutable reference to the back element, or `None` if the list + /// is empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// assert_eq!(dl.back(), None); + /// + /// dl.push_back(1); + /// assert_eq!(dl.back(), Some(&1)); + /// + /// match dl.back_mut() { + /// None => {}, + /// Some(x) => *x = 5, + /// } + /// assert_eq!(dl.back(), Some(&5)); + /// ``` + #[inline] + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn back_mut(&mut self) -> Option<&mut T> { + unsafe { self.tail.as_mut().map(|node| &mut node.as_mut().element) } + } + + /// Adds an element first in the list. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut dl = LinkedList::new(); + /// + /// dl.push_front(2); + /// assert_eq!(dl.front().unwrap(), &2); + /// + /// dl.push_front(1); + /// assert_eq!(dl.front().unwrap(), &1); + /// ``` + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn push_front(&mut self, elt: T) + //@ req thread_token(?t) &*& *self |-> ?ll0 &*& >.own(t, ll0) &*& .own(t, elt); + //@ ens thread_token(t) &*& *self |-> ?ll1 &*& >.own(t, ll1); + { + unsafe { + //@ open_points_to(self); + //@ open >.own(t, ll0); + //@ let alloc_ref = precreate_ref(&(*self).alloc); + //@ std::alloc::init_ref_Allocator::<'static, A>(alloc_ref); + let node = Box::new_in(Node::new(elt), &self.alloc); + let node_ptr = NonNull::new_unchecked(Box::leak(node) as *mut Node); //NonNull::from(Box::leak(node)); + //@ std::alloc::end_ref_Allocator::<'static, A>(); + //@ close_points_to(self); + // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked + self.push_front_node(node_ptr); + } + } + + /// Removes the first element and returns it, or `None` if the list is + /// empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// assert_eq!(d.pop_front(), None); + /// + /// d.push_front(1); + /// d.push_front(3); + /// assert_eq!(d.pop_front(), Some(3)); + /// assert_eq!(d.pop_front(), Some(1)); + /// assert_eq!(d.pop_front(), None); + /// ``` + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn pop_front(&mut self) -> Option + //@ req thread_token(?t) &*& *self |-> ?self0 &*& >.own(t, self0); + //@ ens thread_token(t) &*& *self |-> ?self1 &*& >.own(t, self1) &*& >.own(t, result); + { + unsafe { + //@ open >.own(t, self0); + match self.pop_front_node() { //.map(Node::into_element) + None => { + //@ close_points_to(self); + //@ close >.own(t, *self); + //@ close >.own(t, None); + None + } + Some(node) => { + let r = Some(node.into_element()); + //@ std::alloc::end_ref_Allocator::<'static, A>(); + //@ close_points_to(self); + //@ close >.own(t, *self); + //@ close >.own(t, r); + r + } + } + } + } + + /// Appends an element to the back of a list. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// d.push_back(1); + /// d.push_back(3); + /// assert_eq!(3, *d.back().unwrap()); + /// ``` + //#[stable(feature = "rust1", since = "1.0.0")] + #[rustc_confusables("push", "append")] + pub fn push_back(&mut self, elt: T) { + unsafe { + let node = Box::new_in(Node::new(elt), &self.alloc); + let node_ptr = NonNull::from(Box::leak(node)); + // SAFETY: node_ptr is a unique pointer to a node we boxed with self.alloc and leaked + self.push_back_node(node_ptr); + } + } + + /// Removes the last element from a list and returns it, or `None` if + /// it is empty. + /// + /// This operation should compute in *O*(1) time. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// assert_eq!(d.pop_back(), None); + /// d.push_back(1); + /// d.push_back(3); + /// assert_eq!(d.pop_back(), Some(3)); + /// ``` + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn pop_back(&mut self) -> Option { + unsafe { + match self.pop_back_node() { //.map(Node::into_element) + None => None, + Some(node) => Some(node.into_element()) + } + } + } + + /// Splits the list into two at the given index. Returns everything after the given index, + /// including the index. + /// + /// This operation should compute in *O*(*n*) time. + /// + /// # Panics + /// + /// Panics if `at > len`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// let mut split = d.split_off(2); + /// + /// assert_eq!(split.pop_front(), Some(1)); + /// assert_eq!(split.pop_front(), None); + /// ``` + //#[stable(feature = "rust1", since = "1.0.0")] + pub fn split_off(&mut self, at: usize) -> LinkedList + where + A: Clone, + //@ req thread_token(?t) &*& *self |-> ?self0 &*& >.own(t, self0); + //@ ens thread_token(t) &*& *self |-> ?self1 &*& >.own(t, self1) &*& >.own(t, result); + { + unsafe { + //@ open >.own(t, self0); + //@ open_points_to(self); + let len = self.len; + //@ assert (*self).head |-> ?head &*& (*self).tail |-> ?tail &*& Nodes(?alloc_id, _, _, _, _, _); + assert!(at <= len, "Cannot split off at a nonexistent index"); + if at == 0 { + //@ let alloc_ref = precreate_ref(&(*self).alloc); + //@ std::alloc::init_ref_Allocator::<'static, A>(alloc_ref); + let alloc1 = clone_allocator(&self.alloc); + //@ std::alloc::end_ref_Allocator::<'static, A>(); + //@ std::alloc::Allocator_to_own::(alloc1); + //@ close_points_to(self); + //@ assert *self |-> ?self1; + //@ close >.own(t, self1); + return mem::replace(self, Self::new_in(alloc1)); + } else if at == len { + //@ let alloc_ref = precreate_ref(&(*self).alloc); + //@ std::alloc::init_ref_Allocator::<'static, A>(alloc_ref); + let alloc2 = clone_allocator(&self.alloc); + //@ std::alloc::end_ref_Allocator::<'static, A>(); + //@ std::alloc::Allocator_to_own::(alloc2); + //@ close_points_to(self); + //@ assert *self |-> ?self1; + //@ close >.own(t, self1); + return Self::new_in(alloc2); + } + + // Below, we iterate towards the `i-1`th node, either from the start or the end, + // depending on which would be faster. + let mut iter; + let mut i; + //@ assert Nodes(alloc_id, head, None, tail, None, ?nodes); + let split_node = if at - 1 <= len - 1 - (at - 1) { + iter = self.head; + i = 0; + //@ close Nodes(alloc_id, head, None, None, head, []); + loop { + /*@ + inv Nodes(alloc_id, head, None, ?prev, iter, ?nodes1) &*& Nodes(alloc_id, iter, prev, tail, None, ?nodes2) &*& + length(nodes1) == i &*& append(nodes1, nodes2) == nodes &*& i < at &*& at < length(nodes); + @*/ + if i == at - 1 { + break; + } + //@ open Nodes(alloc_id, iter, prev, tail, None, nodes2); + //@ assert iter == Option::Some(?iter_); + //@ open Nodes(alloc_id, ?next, iter, tail, None, tail(nodes2)); + //@ close Nodes(alloc_id, next, iter, tail, None, tail(nodes2)); + iter = (*iter.unwrap_unchecked().as_ptr()).next; + //@ close Nodes(alloc_id, next, Some(iter_), Some(iter_), next, []); + //@ close Nodes(alloc_id, Some(iter_), prev, Some(iter_), next, [iter_]); + //@ Nodes_append_(head); + //@ append_assoc(nodes1, [iter_], tail(nodes2)); + i += 1; + } + //@ open Nodes(alloc_id, iter, prev, tail, None, nodes2); + //@ assert iter == Option::Some(?iter_); + //@ open Nodes(alloc_id, ?next, iter, tail, None, tail(nodes2)); + //@ close Nodes(alloc_id, next, iter, tail, None, tail(nodes2)); + //@ close Nodes::(alloc_id, next, iter, iter, next, []); + //@ close Nodes::(alloc_id, iter, prev, iter, next, [iter_]); + //@ Nodes_append_(head); + //@ append_assoc(nodes1, [iter_], tail(nodes2)); + //@ foreach_unappend(append(nodes1, [iter_]), tail(nodes2), elem_fbc::(t)); + iter + } else { + // better off starting from the end + iter = self.tail; + i = 0; + //@ close Nodes(alloc_id, None, iter, iter, None, []); + loop { // for _ in 0..len - 1 - (at - 1) { + /*@ + inv Nodes(alloc_id, head, None, iter, ?next, ?nodes1) &*& Nodes(alloc_id, next, iter, tail, None, ?nodes2) &*& + length(nodes2) == i &*& append(nodes1, nodes2) == nodes &*& i <= len - at; + @*/ + if i == len - 1 - (at - 1) { + break; + } + //@ Nodes_last_lemma(head); + //@ Nodes_split_off_last(head); + //@ let old_iter = iter; + //@ assert iter == Option::Some(?iter_); + iter = (*iter.unwrap_unchecked().as_ptr()).prev; + //@ assert Nodes(_, head, _, ?last, old_iter, ?nodes11); + //@ close Nodes(alloc_id, old_iter, last, tail, None, _); + //@ append_assoc(nodes11, [iter_], nodes2); + i += 1; + } + //@ foreach_unappend(nodes1, nodes2, elem_fbc::(t)); + iter + }; + unsafe { self.split_off_after_node(split_node, at) } + } + } + + /// Removes the element at the given index and returns it. + /// + /// This operation should compute in *O*(*n*) time. + /// + /// # Panics + /// Panics if at >= len + /// + /// # Examples + /// + /// ``` + /// #![feature(linked_list_remove)] + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// assert_eq!(d.remove(1), 2); + /// assert_eq!(d.remove(0), 3); + /// assert_eq!(d.remove(0), 1); + /// ``` + /*#[unstable(feature = "linked_list_remove", issue = "69210")]*/ + #[rustc_confusables("delete", "take")] + pub fn remove(&mut self, at: usize) -> T { + let len = self.len(); + assert!(at < len, "Cannot remove at an index outside of the list bounds"); + + // Below, we iterate towards the node at the given index, either from + // the start or the end, depending on which would be faster. + let offset_from_end = len - at - 1; + if at <= offset_from_end { + let mut cursor = self.cursor_front_mut(); + for _ in 0..at { + cursor.move_next(); + } + cursor.remove_current().unwrap() + } else { + let mut cursor = self.cursor_back_mut(); + for _ in 0..offset_from_end { + cursor.move_prev(); + } + cursor.remove_current().unwrap() + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` for which `f(&e)` returns false. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + /// + /// # Examples + /// + /// ``` + /// #![feature(linked_list_retain)] + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// d.retain(|&x| x % 2 == 0); + /// + /// assert_eq!(d.pop_front(), Some(2)); + /// assert_eq!(d.pop_front(), None); + /// ``` + /// + /// Because the elements are visited exactly once in the original order, + /// external state may be used to decide which elements to keep. + /// + /// ``` + /// #![feature(linked_list_retain)] + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// let keep = [false, true, false]; + /// let mut iter = keep.iter(); + /// d.retain(|_| *iter.next().unwrap()); + /// assert_eq!(d.pop_front(), Some(2)); + /// assert_eq!(d.pop_front(), None); + /// ``` + /*#[unstable(feature = "linked_list_retain", issue = "114135")]*/ + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + self.retain_mut(|elem| f(elem)); + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` for which `f(&e)` returns false. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. + /// + /// # Examples + /// + /// ``` + /// #![feature(linked_list_retain)] + /// use std::collections::LinkedList; + /// + /// let mut d = LinkedList::new(); + /// + /// d.push_front(1); + /// d.push_front(2); + /// d.push_front(3); + /// + /// d.retain_mut(|x| if *x % 2 == 0 { + /// *x += 1; + /// true + /// } else { + /// false + /// }); + /// assert_eq!(d.pop_front(), Some(3)); + /// assert_eq!(d.pop_front(), None); + /// ``` + /*#[unstable(feature = "linked_list_retain", issue = "114135")]*/ + pub fn retain_mut(&mut self, mut f: F) + where + F: FnMut(&mut T) -> bool, + { + let mut cursor = self.cursor_front_mut(); + while let Some(node) = cursor.current() { + if !f(node) { + cursor.remove_current().unwrap(); + } else { + cursor.move_next(); + } + } + } + + /// Creates an iterator which uses a closure to determine if an element should be removed. + /// + /// If the closure returns true, then the element is removed and yielded. + /// If the closure returns false, the element will remain in the list and will not be yielded + /// by the iterator. + /// + /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating + /// or the iteration short-circuits, then the remaining elements will be retained. + /// Use `extract_if().for_each(drop)` if you do not need the returned iterator. + /// + /// Note that `extract_if` lets you mutate every element in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// # Examples + /// + /// Splitting a list into evens and odds, reusing the original list: + /// + /// ``` + /// #![feature(extract_if)] + /// use std::collections::LinkedList; + /// + /// let mut numbers: LinkedList = LinkedList::new(); + /// numbers.extend(&[1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]); + /// + /// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::>(); + /// let odds = numbers; + /// + /// assert_eq!(evens.into_iter().collect::>(), vec![2, 4, 6, 8, 14]); + /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 9, 11, 13, 15]); + /// ``` + /*#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]*/ + pub fn extract_if<'a, F>(&'a mut self, filter: F) -> ExtractIf<'a, T, F, A> + where + F: FnMut(&mut T) -> bool, + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& full_borrow('a, >.full_borrow_content(t, self)) &*& .own(t, filter); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& >.own(t, result); + { + //@ let klong = open_full_borrow_strong('a, >.full_borrow_content(t, self), q); + //@ open >.full_borrow_content(t, self)(); + //@ open >.own(t, ?self0); + //@ open_points_to(self); + //@ assert Nodes(?alloc_id, _, _, _, _, _); + + // avoid borrow issues. + let it = self.head; + let old_len = self.len; + + //@ let ghost_cell_id = create_ghost_cell::>>, usize>>(pair(it, 0)); + + /*@ + { + pred Ctx() = struct_LinkedList_padding(self); + produce_lem_ptr_chunk full_borrow_convert_strong(Ctx, ExtractIf_fbc(t, self, ghost_cell_id, self0.len), klong, >.full_borrow_content(t, self))() { + open Ctx(); + open ExtractIf_fbc::(t, self, ghost_cell_id, self0.len)(); + let head1 = (*self).head; + assert Nodes(_, head1, None, _, _, ?nodes1) &*& Nodes(_, _, _, _, _, ?nodes2); + Nodes_append((*self).head); + foreach_append(nodes1, nodes2); + close >.own(t, *self); + close_points_to(self); + close >.full_borrow_content(t, self)(); + leak [1/2]ghost_cell(_, _); + } { + close Ctx(); + close Nodes::(alloc_id, it, None, None, it, []); + close foreach([], elem_fbc::(t)); + close ExtractIf_fbc::(t, self, ghost_cell_id, self0.len)(); + close_full_borrow_strong(klong, >.full_borrow_content(t, self), ExtractIf_fbc(t, self, ghost_cell_id, self0.len)); + full_borrow_mono(klong, 'a, ExtractIf_fbc(t, self, ghost_cell_id, self0.len)); + } + } + @*/ + + let r = ExtractIf { list: self, it, pred: filter, idx: 0, old_len }; + //@ close >.own(t, r); + r + } +} + +struct DropGuard<'a, T, A: Allocator>(&'a mut LinkedList); + +/*@ + +pred<'a, T, A> >.own(t, guard) = true; + +lem DropGuard_own_mono<'a0, 'a1, T, A>() + req type_interp::() &*& type_interp::() &*& DropGuard_own::<'a0, T, A>(?t, ?v) &*& lifetime_inclusion('a1, 'a0) == true; + ens type_interp::() &*& type_interp::() &*& DropGuard_own::<'a1, T, A>(t, DropGuard::<'a1, T, A> { 0: v.0 as *_ }); +{ + open >.own(t, v); + close >.own(t, v); +} + +@*/ + +impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { + fn drop(&mut self) { + unsafe { + // Continue the same loop we do below. This only runs when a destructor has + // panicked. If another one panics this will abort. + while self.0.pop_front_node().is_some() {} + } + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T, A: Allocator> Drop for LinkedList { + fn drop(&mut self) + //@ req thread_token(?t) &*& >.full_borrow_content(t, self)(); + /*@ + ens thread_token(t) &*& + (*self).head |-> ?head &*& > >>.own(t, head) &*& + (*self).tail |-> ?tail &*& > >>.own(t, tail) &*& + (*self).len |-> ?_ &*& + (*self).alloc |-> ?alloc &*& .own(t, alloc) &*& + (*self).marker |-> ?marker &*& , A>>>.own(t, marker) &*& + struct_LinkedList_padding::(self); + @*/ + { + unsafe { + // Wrap self so that if a destructor panics, we can try to keep looping + let guard = DropGuard(self); + //@ open_full_borrow_content(t, self); + loop { + //@ inv thread_token(t) &*& *self |-> ?self0 &*& >.own(t, self0) &*& [1/2]guard.0 |-> self &*& [1/2]element |-> _; + match guard.0.pop_front() { + None => { break; } + Some(element) => { + //@ open >.own(t, _); + } + } + } + //@ close >.own(t, guard); + mem::forget(guard); + //@ let head = (*self).head; + //@ match head { Option::None => {} Option::Some(head_) => { std::ptr::close_NonNull_own::>(t, head_); } } + //@ close >>>.own(t, head); + //@ match (*self).tail { Option::None => {} Option::Some(tail_) => { std::ptr::close_NonNull_own::>(t, tail_); } } + //@ close >>>.own(t, (*self).tail); + //@ open >.own(t, ?ll); + //@ std::alloc::Allocator_to_own::(ll.alloc); + //@ assert (*self).marker |-> ?marker; + //@ std::marker::close_PhantomData_own::, A>>()(t, marker); + //@ leak Nodes(_, _, _, _, _, _); + //@ leak foreach(_, _); + //@ leak >.own(t, None); + } + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + #[inline] + fn next(&mut self) -> Option<&'a T> + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& *self |-> ?self0 &*& >.own(t, self0); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& *self |-> ?self1 &*& >.own(t, self1) &*& >.own(t, result); + { + if self.len == 0 { + //@ close std::option::Option_own::<&'a T>(t, Option::None); + None + } else { + match self.head { //.map(|node| unsafe { + None => { + //@ close std::option::Option_own::<&'a T>(t, Option::None); + None + } + Some(node_) => unsafe { + //@ open >.own(t, self0); + //@ open exists(Iter_info(?alloc_id, ?head0, ?prev, ?next, ?tail0, ?nodes_before, ?nodes, ?nodes_after, ?prevs_before, ?prevs, ?prevs_after, ?nexts_before, ?nexts, ?nexts_after)); + //@ open_frac_borrow('a, Iter_frac_borrow_content::(alloc_id, head0, self0.head, prev, self0.tail, next, tail0, nodes_before, nodes, nodes_after, prevs_before, prevs, prevs_after, nexts_before, nexts, nexts_after), q); + //@ open [?f]Iter_frac_borrow_content::(alloc_id, head0, self0.head, prev, self0.tail, next, tail0, nodes_before, nodes, nodes_after, prevs_before, prevs, prevs_after, nexts_before, nexts, nexts_after)(); + //@ open Nodes1::(alloc_id, self0.head, prev, self0.tail, next, nodes, prevs, nexts); + // Need an unbound lifetime to get 'a + let node = node_.as_ptr(); //&*node_.as_ptr(); + let len = self.len; + //@ produce_limits(len); + self.len = len - 1; + self.head = (*node).next; + //@ let self1 = *self; + //@ close [f]Nodes1::(alloc_id, self0.head, prev, self0.tail, next, nodes, prevs, nexts); + //@ close [f]Iter_frac_borrow_content::(alloc_id, head0, self0.head, prev, self0.tail, next, tail0, nodes_before, nodes, nodes_after, prevs_before, prevs, prevs_after, nexts_before, nexts, nexts_after)(); + //@ close_frac_borrow(f, Iter_frac_borrow_content::(alloc_id, head0, self0.head, prev, self0.tail, next, tail0, nodes_before, nodes, nodes_after, prevs_before, prevs, prevs_after, nexts_before, nexts, nexts_after)); + /*@ + produce_lem_ptr_chunk implies_frac(Iter_frac_borrow_content::(alloc_id, head0, self0.head, prev, self0.tail, next, tail0, nodes_before, nodes, nodes_after, prevs_before, prevs, prevs_after, nexts_before, nexts, nexts_after), Iter_frac_borrow_content::(alloc_id, head0, self1.head, self0.head, self1.tail, next, tail0, append(nodes_before, [node_]), tail(nodes), nodes_after, append(prevs_before, [prev]), tail(prevs), prevs_after, append(nexts_before, [self1.head]), tail(nexts), nexts_after))() { + open [?f1]Iter_frac_borrow_content::(alloc_id, head0, self0.head, prev, self0.tail, next, tail0, nodes_before, nodes, nodes_after, prevs_before, prevs, prevs_after, nexts_before, nexts, nexts_after)(); + open Nodes1::(alloc_id, self0.head, prev, self0.tail, next, nodes, prevs, nexts); + close [f1]Nodes1::(alloc_id, self1.head, self0.head, self0.head, self1.head, [], [], []); + assert self0.head == Option::Some(node_) &*& [f1](*NonNull_ptr(node_)).next |-> self1.head; + close [f1]Nodes1::(alloc_id, self0.head, prev, self0.head, self1.head, [node_], [prev], [self1.head]); + Nodes1_append::(head0); + close [f1]Iter_frac_borrow_content::(alloc_id, head0, self1.head, self0.head, self1.tail, next, tail0, append(nodes_before, [node_]), tail(nodes), nodes_after, append(prevs_before, [prev]), tail(prevs), prevs_after, append(nexts_before, [self1.head]), tail(nexts), nexts_after)(); + } { + produce_lem_ptr_chunk implies_frac(Iter_frac_borrow_content::(alloc_id, head0, self1.head, self0.head, self1.tail, next, tail0, append(nodes_before, [node_]), tail(nodes), nodes_after, append(prevs_before, [prev]), tail(prevs), prevs_after, append(nexts_before, [self1.head]), tail(nexts), nexts_after), Iter_frac_borrow_content::(alloc_id, head0, self0.head, prev, self0.tail, next, tail0, nodes_before, nodes, nodes_after, prevs_before, prevs, prevs_after, nexts_before, nexts, nexts_after))() { + open [?f1]Iter_frac_borrow_content::(alloc_id, head0, self1.head, self0.head, self1.tail, next, tail0, append(nodes_before, [node_]), tail(nodes), nodes_after, append(prevs_before, [prev]), tail(prevs), prevs_after, append(nexts_before, [self1.head]), tail(nexts), nexts_after)(); + Nodes1_split::(nodes_before, [node_], prevs_before, [prev], nexts_before, [self1.head]); + open Nodes1::(alloc_id, _, _, _, _, [node_], [prev], [self1.head]); + open Nodes1::(alloc_id, self1.head, _, _, _, [], [], []); + close [f1]Nodes1::(alloc_id, self0.head, prev, self0.tail, next, nodes, prevs, nexts); + close [f1]Iter_frac_borrow_content::(alloc_id, head0, self0.head, prev, self0.tail, next, tail0, nodes_before, nodes, nodes_after, prevs_before, prevs, prevs_after, nexts_before, nexts, nexts_after)(); + } { + frac_borrow_implies('a, Iter_frac_borrow_content::(alloc_id, head0, self0.head, prev, self0.tail, next, tail0, nodes_before, nodes, nodes_after, prevs_before, prevs, prevs_after, nexts_before, nexts, nexts_after), Iter_frac_borrow_content::(alloc_id, head0, self1.head, self0.head, self1.tail, next, tail0, append(nodes_before, [node_]), tail(nodes), nodes_after, append(prevs_before, [prev]), tail(prevs), prevs_after, append(nexts_before, [self1.head]), tail(nexts), nexts_after)); + } + } + @*/ + //@ close exists(Iter_info(alloc_id, head0, self0.head, next, tail0, append(nodes_before, [node_]), tail(nodes), nodes_after, append(prevs_before, [prev]), tail(prevs), prevs_after, append(nexts_before, [self1.head]), tail(nexts), nexts_after)); + //@ open foreach(_, _); + //@ close >.own(t, *self); + //@ open elem_share::('a, t)(node_); + //@ let elem_ref = precreate_ref(&(*node).element); + //@ produce_type_interp::(); + //@ init_ref_share::('a, t, elem_ref); + //@ leak type_interp::(); + //@ close_ref_own::<'a, T>(elem_ref); + //@ close >.own(t, Option::Some(elem_ref)); + //@ open_frac_borrow('a, ref_initialized_(elem_ref), q); + //@ open [?fr]ref_initialized_::(elem_ref)(); + let r = &(*node).element; + //@ close [fr]ref_initialized_::(elem_ref)(); + //@ close_frac_borrow(fr, ref_initialized_(elem_ref)); + Some(r) + } + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } + + #[inline] + fn last(mut self) -> Option<&'a T> { + self.next_back() + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Iter<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a T> { + if self.len == 0 { + None + } else { + self.tail.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &*node.as_ptr(); + self.len -= 1; + self.tail = node.prev; + &node.element + }) + } + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Iter<'_, T> {} + +//#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Iter<'_, T> {} + +//#[stable(feature = "default_iters", since = "1.70.0")] +impl Default for Iter<'_, T> { + /// Creates an empty `linked_list::Iter`. + /// + /// ``` + /// # use std::collections::linked_list; + /// let iter: linked_list::Iter<'_, u8> = Default::default(); + /// assert_eq!(iter.len(), 0); + /// ``` + fn default() -> Self { + Iter { head: None, tail: None, len: 0, marker: Default::default() } + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + #[inline] + fn next(&mut self) -> Option<&'a mut T> { + if self.len == 0 { + None + } else { + self.head.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &mut *node.as_ptr(); + self.len -= 1; + self.head = node.next; + &mut node.element + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.len, Some(self.len)) + } + + #[inline] + fn last(mut self) -> Option<&'a mut T> { + self.next_back() + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut T> { + if self.len == 0 { + None + } else { + self.tail.map(|node| unsafe { + // Need an unbound lifetime to get 'a + let node = &mut *node.as_ptr(); + self.len -= 1; + self.tail = node.prev; + &mut node.element + }) + } + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IterMut<'_, T> {} + +//#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IterMut<'_, T> {} + +//#[stable(feature = "default_iters", since = "1.70.0")] +impl Default for IterMut<'_, T> { + fn default() -> Self { + IterMut { head: None, tail: None, len: 0, marker: Default::default() } + } +} + +/// A cursor over a `LinkedList`. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth. +/// +/// Cursors always rest between two elements in the list, and index in a logically circular way. +/// To accommodate this, there is a "ghost" non-element that yields `None` between the head and +/// tail of the list. +/// +/// When created, cursors start at the front of the list, or the "ghost" non-element if the list is empty. +/*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +pub struct Cursor< + 'a, + T: 'a, + /*#[unstable(feature = "allocator_api", issue = "32838")]*/ A: Allocator = Global, +> { + index: usize, + current: Option>>, + list: &'a LinkedList, +} + +/*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +impl Clone for Cursor<'_, T, A> { + fn clone(&self) -> Self { + let Cursor { index, current, list } = *self; + Cursor { index, current, list } + } +} + +/*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +impl fmt::Debug for Cursor<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Cursor").field(&self.list).field(&self.index()).finish() + } +} + +/// A cursor over a `LinkedList` with editing operations. +/// +/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can +/// safely mutate the list during iteration. This is because the lifetime of its yielded +/// references is tied to its own lifetime, instead of just the underlying list. This means +/// cursors cannot yield multiple elements at once. +/// +/// Cursors always rest between two elements in the list, and index in a logically circular way. +/// To accommodate this, there is a "ghost" non-element that yields `None` between the head and +/// tail of the list. +/*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +pub struct CursorMut< + 'a, + T: 'a, + /*#[unstable(feature = "allocator_api", issue = "32838")]*/ A: Allocator = Global, +> { + index: usize, + current: Option>>, + list: &'a mut LinkedList, +} + +/*@ + +pred_ctor CursorMut_fbc(t: thread_id_t, ghost_cell_id: i32, list: *LinkedList)() = + [1/2]ghost_cell::>>>>(ghost_cell_id, pair(?index, ?current)) &*& + (*list).alloc |-> ?alloc &*& + Allocator::(t, alloc, ?alloc_id) &*& + (*list).head |-> ?head &*& + (*list).tail |-> ?tail &*& + Nodes::(alloc_id, head, None, ?before_current, current, ?nodes1) &*& + Nodes::(alloc_id, current, before_current, tail, None, ?nodes2) &*& + foreach(nodes1, elem_fbc::(t)) &*& + foreach(nodes2, elem_fbc::(t)) &*& + (*list).len |-> length(nodes1) + length(nodes2) &*& + index == length(nodes1) &*& + (*list).marker |-> ?_ &*& + struct_LinkedList_padding(list); + +pred<'a, T, A> >.own(t, cursor) = + [1/2]ghost_cell::>>>>(?ghost_cell_id, pair(cursor.index, cursor.current)) &*& + full_borrow('a, CursorMut_fbc::(if is_Send(typeid(T)) && is_Send(typeid(A)) { default_tid } else { t }, ghost_cell_id, cursor.list)); + +lem CursorMut_own_mono<'a0, 'a1, T, A>() + req type_interp::() &*& type_interp::() &*& CursorMut_own::<'a0, T, A>(?t, ?v) &*& lifetime_inclusion('a1, 'a0) == true; + ens type_interp::() &*& type_interp::() &*& CursorMut_own::<'a1, T, A>(t, CursorMut::<'a1, T, A> { index: upcast(v.index), current: upcast(v.current), list: v.list as *_ }); +{ + assume(false); +} + +lem CursorMut_send<'a, T, A>(t1: thread_id_t) + req type_interp::() &*& type_interp::() &*& is_Send(typeid(T)) == true &*& is_Send(typeid(A)) == true &*& CursorMut_own::<'a, T, A>(?t0, ?v); + ens type_interp::() &*& type_interp::() &*& CursorMut_own::<'a, T, A>(t1, v); +{ + open >.own(t0, v); + close >.own(t1, v); +} + +@*/ + +/*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +impl fmt::Debug for CursorMut<'_, T, A> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("CursorMut").field(&self.list).field(&self.index()).finish() + } +} + +impl<'a, T, A: Allocator> Cursor<'a, T, A> { + /// Returns the cursor position index within the `LinkedList`. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn index(&self) -> Option { + let _ = self.current?; + Some(self.index) + } + + /// Moves the cursor to the next element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this will move it to the "ghost" non-element. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn move_next(&mut self) { + match self.current.take() { + // We had no current element; the cursor was sitting at the start position + // Next element should be the head of the list + None => { + self.current = self.list.head; + self.index = 0; + } + // We had a previous element, so let's go to its next + Some(current) => unsafe { + self.current = current.as_ref().next; + self.index += 1; + }, + } + } + + /// Moves the cursor to the previous element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this will move it to the "ghost" non-element. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn move_prev(&mut self) { + match self.current.take() { + // No current. We're at the start of the list. Yield None and jump to the end. + None => { + self.current = self.list.tail; + self.index = self.list.len().checked_sub(1).unwrap_or(0); + } + // Have a prev. Yield it and go to the previous element. + Some(current) => unsafe { + self.current = current.as_ref().prev; + self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); + }, + } + } + + /// Returns a reference to the element that the cursor is currently + /// pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn current(&self) -> Option<&'a T> { + unsafe { self.current.map(|current| &(*current.as_ptr()).element) } + } + + /// Returns a reference to the next element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this returns `None`. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn peek_next(&self) -> Option<&'a T> { + unsafe { + let next = match self.current { + None => self.list.head, + Some(current) => current.as_ref().next, + }; + next.map(|next| &(*next.as_ptr()).element) + } + } + + /// Returns a reference to the previous element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this returns `None`. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn peek_prev(&self) -> Option<&'a T> { + unsafe { + let prev = match self.current { + None => self.list.tail, + Some(current) => current.as_ref().prev, + }; + prev.map(|prev| &(*prev.as_ptr()).element) + } + } + + /// Provides a reference to the front element of the cursor's parent list, + /// or None if the list is empty. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + #[rustc_confusables("first")] + pub fn front(&self) -> Option<&'a T> { + self.list.front() + } + + /// Provides a reference to the back element of the cursor's parent list, + /// or None if the list is empty. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + #[rustc_confusables("last")] + pub fn back(&self) -> Option<&'a T> { + self.list.back() + } +} + +impl<'a, T, A: Allocator> CursorMut<'a, T, A> { + /// Returns the cursor position index within the `LinkedList`. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn index(&self) -> Option { + let _ = self.current?; + Some(self.index) + } + + /// Moves the cursor to the next element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this will move it to the "ghost" non-element. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn move_next(&mut self) + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& *self |-> ?self0 &*& >.own(t, self0); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& *self |-> ?self1 &*& >.own(t, self1); + { + //@ open_points_to(self); + //@ open >.own(t, self0); + //@ let t1 = if is_Send(typeid(T)) && is_Send(typeid(A)) { default_tid } else { t }; + //@ assert [1/2]ghost_cell(?ghost_cell_id, _); + //@ open_full_borrow(q, 'a, CursorMut_fbc::(t1, ghost_cell_id, self0.list)); + //@ open CursorMut_fbc::(t1, ghost_cell_id, self0.list)(); + //@ let head = (*self0.list).head; + //@ let tail = (*self0.list).tail; + match self.current.take() { + // We had no current element; the cursor was sitting at the start position + // Next element should be the head of the list + None => { + //@ close CursorMut_current(self, _); + self.current = self.list.head; + self.index = 0; + //@ open Nodes(?alloc_id, None, ?before_current, tail, None, ?nodes2); + //@ close Nodes(alloc_id, head, None, None, head, nil); + } + // We had a previous element, so let's go to its next + Some(current) => unsafe { + //@ open Nodes(?alloc_id, self0.current, ?before_current, tail, None, ?nodes2); + //@ close CursorMut_current(self, _); + self.current = (*current.as_ptr()).next; //current.as_ref().next; + self.index += 1; + //@ let self1_= *self; + //@ assert Nodes(alloc_id, head, None, _, _, ?nodes1); + //@ open Nodes(alloc_id, self1_.current, self0.current, tail, None, tail(nodes2)); + //@ close Nodes(alloc_id, self1_.current, self0.current, tail, None, tail(nodes2)); + //@ close Nodes(alloc_id, self1_.current, self0.current, self0.current, self1_.current, nil); + //@ close Nodes(alloc_id, self0.current, before_current, self0.current, self1_.current, [current]); + //@ Nodes_append_(head); + //@ open foreach(nodes2, _); + //@ close foreach([], elem_fbc::(t1)); + //@ close foreach([current], elem_fbc::(t1)); + //@ foreach_append(nodes1, [current]); + }, + }; + //@ let self1 = *self; + //@ ghost_cell_mutate(ghost_cell_id, pair(self1.index, self1.current)); + //@ close CursorMut_fbc::(t1, ghost_cell_id, self1.list)(); + //@ close_full_borrow(CursorMut_fbc::(t1, ghost_cell_id, self1.list)); + //@ close >.own(t, self1); + } + + /// Moves the cursor to the previous element of the `LinkedList`. + /// + /// If the cursor is pointing to the "ghost" non-element then this will move it to + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this will move it to the "ghost" non-element. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn move_prev(&mut self) + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& *self |-> ?self0 &*& >.own(t, self0); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& *self |-> ?self1 &*& >.own(t, self1); + { + //@ let t1 = if is_Send(typeid(T)) && is_Send(typeid(A)) { default_tid } else { t }; + //@ open_points_to(self); + //@ open >.own(t, self0); + //@ assert [1/2]ghost_cell(?ghost_cell_id, _); + //@ open_full_borrow(q, 'a, CursorMut_fbc::(t1, ghost_cell_id, self0.list)); + //@ open CursorMut_fbc::(t1, ghost_cell_id, self0.list)(); + //@ let head = (*self0.list).head; + //@ let tail = (*self0.list).tail; + //@ let len = (*self0.list).len; + //@ open Nodes(?alloc_id, self0.current, ?before_current, tail, None, ?nodes2); + match self.current.take() { + // No current. We're at the start of the list. Yield None and jump to the end. + None => { + //@ close CursorMut_current(self, _); + self.current = self.list.tail; + self.index = self.list.len.checked_sub(1).unwrap_or(0); + //@ assert nodes2 == []; + //@ open foreach([], elem_fbc::(t1)); + /*@ + match tail { + Option::None => { + Nodes_last_lemma(head); + close Nodes(alloc_id, self0.current, tail, tail, None, nodes2); + close foreach([], elem_fbc::(t1)); + assert len == 0; + } + Option::Some(tail_) => { + Nodes_last_lemma(head); + Nodes_split_off_last(head); + assert Nodes(alloc_id, head, None, ?before_tail, tail, ?nodes10); + close Nodes::(alloc_id, None, tail, tail, None, []); + close Nodes::(alloc_id, tail, _, tail, None, [tail_]); + foreach_unappend(nodes10, [tail_], elem_fbc::(t1)); + } + } + @*/ + } + // Have a prev. Yield it and go to the previous element. + Some(current) => unsafe { + //@ close CursorMut_current(self, _); + self.current = (*current.as_ptr()).prev; //current.as_ref().prev; + match self.index.checked_sub(1) { // self.index = self.index.checked_sub(1).unwrap_or_else(|| self.list.len()); + None => { + //@ open Nodes(_, head, None, _, _, ?nodes1); + //@ assert nodes1 == []; + self.index = self.list.len; + //@ close Nodes(alloc_id, self0.current, before_current, tail, None, nodes2); + //@ close Nodes::(alloc_id, None, tail, tail, None, []); + } + Some(index1) => { + //@ close Nodes(alloc_id, self0.current, before_current, tail, None, nodes2); + //@ Nodes_last_lemma(head); + //@ Nodes_split_off_last(head); + //@ assert before_current == Option::Some(?current1); + //@ assert Nodes(_, head, None, ?last, before_current, ?nodes10); + //@ close Nodes::(alloc_id, before_current, last, tail, None, cons(current1, nodes2)); + //@ foreach_unappend(nodes10, [current1], elem_fbc::(t1)); + //@ foreach_append([current1], nodes2); + self.index = index1; + } + } + }, + } + //@ let self1 = *self; + //@ ghost_cell_mutate(ghost_cell_id, pair(self1.index, self1.current)); + //@ close CursorMut_fbc::(t1, ghost_cell_id, self1.list)(); + //@ close_full_borrow(CursorMut_fbc::(t1, ghost_cell_id, self1.list)); + //@ close >.own(t, self1); + } + + /// Returns a reference to the element that the cursor is currently + /// pointing to. + /// + /// This returns `None` if the cursor is currently pointing to the + /// "ghost" non-element. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn current<'b>(&'b mut self) -> Option<&'b mut T> + //@ req thread_token(?t) &*& [?qa]lifetime_token('a) &*& [?qb]lifetime_token('b) &*& full_borrow('b, >.full_borrow_content(t, self)) &*& lifetime_inclusion('b, 'a) == true; + //@ ens thread_token(t) &*& [qa]lifetime_token('a) &*& [qb]lifetime_token('b) &*& >.own(t, result); + { + unsafe { + //@ let t1 = if is_Send(typeid(T)) && is_Send(typeid(A)) { default_tid } else { t }; + //@ let klongb = open_full_borrow_strong('b, >.full_borrow_content(t, self), qb); + //@ open >.full_borrow_content(t, self)(); + match self.current { //self.current.map(|current| &mut (*current.as_ptr()).element) + None => { + /*@ + { + pred Ctx() = true; + produce_lem_ptr_chunk full_borrow_convert_strong(Ctx, >.full_borrow_content(t, self), klongb, >.full_borrow_content(t, self))() { + open Ctx(); + } { + close Ctx(); + close >.full_borrow_content(t, self)(); + close_full_borrow_strong(klongb, >.full_borrow_content(t, self), >.full_borrow_content(t, self)); + leak full_borrow(_, _); + } + } + @*/ + //@ close >.own(t, None); + None + } + Some(current) => { + //@ open >.own(t, ?self0); + //@ let list = self0.list; + //@ assert [1/2]ghost_cell(?ghost_cell_id, pair(?index, ?current_)); + /*@ + { + pred Ctx1() = + *self |-> self0 &*& + [1/2]ghost_cell(ghost_cell_id, pair(index, current_)); + { + pred Ctx() = true; + produce_lem_ptr_chunk full_borrow_convert_strong(Ctx, sep(Ctx1, full_borrow_('a, CursorMut_fbc::(t1, ghost_cell_id, list))), klongb, >.full_borrow_content(t, self))() { + open Ctx(); + open sep(Ctx1, full_borrow_('a, CursorMut_fbc::(t1, ghost_cell_id, list)))(); + open Ctx1(); + close >.own(t, self0); + close >.full_borrow_content(t, self)(); + } { + close Ctx(); + close Ctx1(); + close sep(Ctx1, full_borrow_('a, CursorMut_fbc::(t1, ghost_cell_id, list)))(); + close_full_borrow_strong(klongb, >.full_borrow_content(t, self), sep(Ctx1, full_borrow_('a, CursorMut_fbc::(t1, ghost_cell_id, list)))); + } + full_borrow_mono(klongb, 'b, sep(Ctx1, full_borrow_('a, CursorMut_fbc::(t1, ghost_cell_id, list)))); + full_borrow_split('b, Ctx1, full_borrow_('a, CursorMut_fbc::(t1, ghost_cell_id, list))); + full_borrow_unnest('b, 'a, CursorMut_fbc::(t1, ghost_cell_id, list)); + lifetime_inclusion_refl('b); + lifetime_inclusion_glb('b, 'b, 'a); + full_borrow_mono(lifetime_intersection('b, 'a), 'b, CursorMut_fbc::(t1, ghost_cell_id, list)); + } + open_full_borrow(qb/2, 'b, Ctx1); + open Ctx1(); + let klongb2 = open_full_borrow_strong('b, CursorMut_fbc::(t1, ghost_cell_id, list), qb/2); + open CursorMut_fbc::(t1, ghost_cell_id, list)(); + close Ctx1(); + close_full_borrow(Ctx1); + leak full_borrow('b, Ctx1); + open Nodes::(?alloc_id, Some(current), ?before_current, ?tail, None, ?nodes2); + close Nodes::(alloc_id, Some(current), before_current, tail, None, nodes2); + open foreach(nodes2, elem_fbc::(t1)); + open elem_fbc::(t1)(current); + produce_type_interp::(); + if t1 != t { + Send::send(t1, t, (*NonNull_ptr(current)).element); + } + close_full_borrow_content::(t, &(*NonNull_ptr(current)).element); + assert + (*list).alloc |-> ?alloc &*& + Allocator::(t1, alloc, alloc_id) &*& + (*list).head |-> ?head &*& + (*list).tail |-> tail &*& + Nodes::(alloc_id, head, None, before_current, current_, ?nodes1); + { + pred Ctx() = + type_interp::() &*& + [1/2]ghost_cell::>>>>(ghost_cell_id, pair(index, current_)) &*& + (*list).alloc |-> alloc &*& + Allocator::(t1, alloc, alloc_id) &*& + (*list).head |-> head &*& + (*list).tail |-> tail &*& + Nodes::(alloc_id, head, None, before_current, current_, nodes1) &*& + Nodes::(alloc_id, current_, before_current, tail, None, nodes2) &*& + foreach(nodes1, elem_fbc::(t1)) &*& + foreach(tail(nodes2), elem_fbc::(t1)) &*& + (*list).len |-> length(nodes1) + length(nodes2) &*& + index == length(nodes1) &*& + (*list).marker |-> ?_ &*& + struct_LinkedList_padding(list); + produce_lem_ptr_chunk full_borrow_convert_strong(Ctx, .full_borrow_content(t, &(*NonNull_ptr(current)).element), klongb2, CursorMut_fbc::(t1, ghost_cell_id, self0.list))() { + open Ctx(); + open_full_borrow_content::(t, &(*NonNull_ptr(current)).element); + if t1 != t { + Send::send(t, t1, (*NonNull_ptr(current)).element); + } + leak type_interp::(); + close elem_fbc::(t1)(current); + close foreach(nodes2, elem_fbc::(t1)); + close CursorMut_fbc::(t1, ghost_cell_id, self0.list)(); + } { + close Ctx(); + close_full_borrow_strong(klongb2, CursorMut_fbc::(t1, ghost_cell_id, self0.list), .full_borrow_content(t, &(*NonNull_ptr(current)).element)); + full_borrow_mono(klongb2, 'b, .full_borrow_content(t, &(*NonNull_ptr(current)).element)); + } + } + } + @*/ + //@ close_ref_mut_own::<'b, T>(t, &(*NonNull_ptr(current)).element); + //@ close >.own(t, Some(&(*NonNull_ptr(current)).element)); + Some(&mut (*current.as_ptr()).element) + } + } + } + } + + /// Returns a reference to the next element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the first element of the `LinkedList`. If it is pointing to the last + /// element of the `LinkedList` then this returns `None`. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn peek_next(&mut self) -> Option<&mut T> { + unsafe { + let next = match self.current { + None => self.list.head, + Some(current) => current.as_ref().next, + }; + next.map(|next| &mut (*next.as_ptr()).element) + } + } + + /// Returns a reference to the previous element. + /// + /// If the cursor is pointing to the "ghost" non-element then this returns + /// the last element of the `LinkedList`. If it is pointing to the first + /// element of the `LinkedList` then this returns `None`. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn peek_prev(&mut self) -> Option<&mut T> { + unsafe { + let prev = match self.current { + None => self.list.tail, + Some(current) => current.as_ref().prev, + }; + prev.map(|prev| &mut (*prev.as_ptr()).element) + } + } + + /// Returns a read-only cursor pointing to the current element. + /// + /// The lifetime of the returned `Cursor` is bound to that of the + /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the + /// `CursorMut` is frozen for the lifetime of the `Cursor`. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn as_cursor(&self) -> Cursor<'_, T, A> { + Cursor { list: self.list, current: self.current, index: self.index } + } +} + +// Now the list editing operations + +impl<'a, T> CursorMut<'a, T> { + /// Inserts the elements from the given `LinkedList` after the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new elements are + /// inserted at the start of the `LinkedList`. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn splice_after(&mut self, list: LinkedList) { + unsafe { + let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { + Some(parts) => parts, + _ => return, + }; + let node_next = match self.current { + None => self.list.head, + Some(node) => node.as_ref().next, + }; + self.list.splice_nodes(self.current, node_next, splice_head, splice_tail, splice_len); + if self.current.is_none() { + // The "ghost" non-element's index has changed. + self.index = self.list.len; + } + } + } + + /// Inserts the elements from the given `LinkedList` before the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new elements are + /// inserted at the end of the `LinkedList`. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn splice_before(&mut self, list: LinkedList) { + unsafe { + let (splice_head, splice_tail, splice_len) = match list.detach_all_nodes() { + Some(parts) => parts, + _ => return, + }; + let node_prev = match self.current { + None => self.list.tail, + Some(node) => node.as_ref().prev, + }; + self.list.splice_nodes(node_prev, self.current, splice_head, splice_tail, splice_len); + self.index += splice_len; + } + } +} + +impl<'a, T, A: Allocator> CursorMut<'a, T, A> { + /// Inserts a new element into the `LinkedList` after the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new element is + /// inserted at the front of the `LinkedList`. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn insert_after(&mut self, item: T) { + unsafe { + let spliced_node = Box::leak(Box::new_in(Node::new(item), &self.list.alloc)).into(); + let node_next = match self.current { + None => self.list.head, + Some(node) => node.as_ref().next, + }; + self.list.splice_nodes(self.current, node_next, spliced_node, spliced_node, 1); + if self.current.is_none() { + // The "ghost" non-element's index has changed. + self.index = self.list.len; + } + } + } + + /// Inserts a new element into the `LinkedList` before the current one. + /// + /// If the cursor is pointing at the "ghost" non-element then the new element is + /// inserted at the end of the `LinkedList`. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn insert_before(&mut self, item: T) { + unsafe { + let spliced_node = Box::leak(Box::new_in(Node::new(item), &self.list.alloc)).into(); + let node_prev = match self.current { + None => self.list.tail, + Some(node) => node.as_ref().prev, + }; + self.list.splice_nodes(node_prev, self.current, spliced_node, spliced_node, 1); + self.index += 1; + } + } + + /// Removes the current element from the `LinkedList`. + /// + /// The element that was removed is returned, and the cursor is + /// moved to point to the next element in the `LinkedList`. + /// + /// If the cursor is currently pointing to the "ghost" non-element then no element + /// is removed and `None` is returned. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn remove_current(&mut self) -> Option + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& *self |-> ?self0 &*& >.own(t, self0); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& *self |-> ?self1 &*& >.own(t, self1) &*& >.own(t, result); + { + //let unlinked_node = self.current?; + match self.current { + None => { + //@ close >.own(t, None); + None + } + Some(unlinked_node) => unsafe { + //@ open >.own(t, self0); + //@ assert [1/2]ghost_cell(?ghost_cell_id, _); + //@ let t1 = if is_Send(typeid(T)) && is_Send(typeid(A)) { default_tid } else { t }; + //@ open_full_borrow(q, 'a, CursorMut_fbc::(t1, ghost_cell_id, self0.list)); + //@ open CursorMut_fbc::(t1, ghost_cell_id, self0.list)(); + //@ open Nodes::(?alloc_id, self0.current, ?before_current, ?tail, None, ?nodes2); + + self.current = (*unlinked_node.as_ptr()).next; //unlinked_node.as_ref().next; + //@ let current1 = (*self).current; + //@ open foreach(nodes2, elem_fbc::(t1)); + //@ open elem_fbc::(t1)(unlinked_node); + self.list.unlink_node(unlinked_node); + /*@ + if t1 != t { + std::alloc::Allocator_send(t, (*self0.list).alloc); + } + @*/ + //@ let alloc_ref = precreate_ref(&(*self0.list).alloc); + //@ std::alloc::init_ref_Allocator::<'static, A>(alloc_ref); + let unlinked_node_ = Box::from_raw_in(unlinked_node.as_ptr(), &self.list.alloc); + let r = Some(Box::into_inner(unlinked_node_).element); // Some(unlinked_node_.element) + //@ std::alloc::end_ref_Allocator::<'static, A>(); + //@ ghost_cell_mutate(ghost_cell_id, pair(self0.index, current1)); + /*@ + if t1 != t { + std::alloc::Allocator_send(t1, (*self0.list).alloc); + assert r == Option::Some(?e); + produce_type_interp::(); + Send::send(t1, t, e); + leak type_interp::(); + } + @*/ + //@ close CursorMut_fbc::(t1, ghost_cell_id, self0.list)(); + //@ close_full_borrow(CursorMut_fbc::(t1, ghost_cell_id, self0.list)); + //@ close >.own(t, *self); + //@ close >.own(t, r); + r + } + } + } + + /// Removes the current element from the `LinkedList` without deallocating the list node. + /// + /// The node that was removed is returned as a new `LinkedList` containing only this node. + /// The cursor is moved to point to the next element in the current `LinkedList`. + /// + /// If the cursor is currently pointing to the "ghost" non-element then no element + /// is removed and `None` is returned. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn remove_current_as_list(&mut self) -> Option> + where + A: Clone, + { + let mut unlinked_node = self.current?; + unsafe { + self.current = unlinked_node.as_ref().next; + self.list.unlink_node(unlinked_node); + + unlinked_node.as_mut().prev = None; + unlinked_node.as_mut().next = None; + Some(LinkedList { + head: Some(unlinked_node), + tail: Some(unlinked_node), + len: 1, + alloc: self.list.alloc.clone(), + marker: PhantomData, + }) + } + } + + /// Splits the list into two after the current element. This will return a + /// new list consisting of everything after the cursor, with the original + /// list retaining everything before. + /// + /// If the cursor is pointing at the "ghost" non-element then the entire contents + /// of the `LinkedList` are moved. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn split_after(&mut self) -> LinkedList + where + A: Clone, + { + let split_off_idx = if self.index == self.list.len { 0 } else { self.index + 1 }; + if self.index == self.list.len { + // The "ghost" non-element's index has changed to 0. + self.index = 0; + } + unsafe { self.list.split_off_after_node(self.current, split_off_idx) } + } + + /// Splits the list into two before the current element. This will return a + /// new list consisting of everything before the cursor, with the original + /// list retaining everything after. + /// + /// If the cursor is pointing at the "ghost" non-element then the entire contents + /// of the `LinkedList` are moved. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn split_before(&mut self) -> LinkedList + where + A: Clone, + { + let split_off_idx = self.index; + self.index = 0; + unsafe { self.list.split_off_before_node(self.current, split_off_idx) } + } + + /// Appends an element to the front of the cursor's parent list. The node + /// that the cursor points to is unchanged, even if it is the "ghost" node. + /// + /// This operation should compute in *O*(1) time. + // `push_front` continues to point to "ghost" when it adds a node to mimic + // the behavior of `insert_before` on an empty list. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn push_front(&mut self, elt: T) { + // Safety: We know that `push_front` does not change the position in + // memory of other nodes. This ensures that `self.current` remains + // valid. + self.list.push_front(elt); + self.index += 1; + } + + /// Appends an element to the back of the cursor's parent list. The node + /// that the cursor points to is unchanged, even if it is the "ghost" node. + /// + /// This operation should compute in *O*(1) time. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + #[rustc_confusables("push", "append")] + pub fn push_back(&mut self, elt: T) { + // Safety: We know that `push_back` does not change the position in + // memory of other nodes. This ensures that `self.current` remains + // valid. + self.list.push_back(elt); + if self.current().is_none() { + // The index of "ghost" is the length of the list, so we just need + // to increment self.index to reflect the new length of the list. + self.index += 1; + } + } + + /// Removes the first element from the cursor's parent list and returns it, + /// or None if the list is empty. The element the cursor points to remains + /// unchanged, unless it was pointing to the front element. In that case, it + /// points to the new front element. + /// + /// This operation should compute in *O*(1) time. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn pop_front(&mut self) -> Option { + // We can't check if current is empty, we must check the list directly. + // It is possible for `self.current == None` and the list to be + // non-empty. + if self.list.is_empty() { + None + } else { + // We can't point to the node that we pop. Copying the behavior of + // `remove_current`, we move on to the next node in the sequence. + // If the list is of length 1 then we end pointing to the "ghost" + // node at index 0, which is expected. + if self.list.head == self.current { + self.move_next(); + } else { + self.index -= 1; + } + self.list.pop_front() + } + } + + /// Removes the last element from the cursor's parent list and returns it, + /// or None if the list is empty. The element the cursor points to remains + /// unchanged, unless it was pointing to the back element. In that case, it + /// points to the "ghost" element. + /// + /// This operation should compute in *O*(1) time. + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + #[rustc_confusables("pop")] + pub fn pop_back(&mut self) -> Option { + if self.list.is_empty() { + None + } else { + if self.list.tail == self.current { + // The index now reflects the length of the list. It was the + // length of the list minus 1, but now the list is 1 smaller. No + // change is needed for `index`. + self.current = None; + } else if self.current.is_none() { + self.index = self.list.len - 1; + } + self.list.pop_back() + } + } + + /// Provides a reference to the front element of the cursor's parent list, + /// or None if the list is empty. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + #[rustc_confusables("first")] + pub fn front(&self) -> Option<&T> { + self.list.front() + } + + /// Provides a mutable reference to the front element of the cursor's + /// parent list, or None if the list is empty. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn front_mut(&mut self) -> Option<&mut T> { + self.list.front_mut() + } + + /// Provides a reference to the back element of the cursor's parent list, + /// or None if the list is empty. + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + #[rustc_confusables("last")] + pub fn back(&self) -> Option<&T> { + self.list.back() + } + + /// Provides a mutable reference to back element of the cursor's parent + /// list, or `None` if the list is empty. + /// + /// # Examples + /// Building and mutating a list with a cursor, then getting the back element: + /// ``` + /// #![feature(linked_list_cursors)] + /// use std::collections::LinkedList; + /// let mut dl = LinkedList::new(); + /// dl.push_front(3); + /// dl.push_front(2); + /// dl.push_front(1); + /// let mut cursor = dl.cursor_front_mut(); + /// *cursor.current().unwrap() = 99; + /// *cursor.back_mut().unwrap() = 0; + /// let mut contents = dl.into_iter(); + /// assert_eq!(contents.next(), Some(99)); + /// assert_eq!(contents.next(), Some(2)); + /// assert_eq!(contents.next(), Some(0)); + /// assert_eq!(contents.next(), None); + /// ``` + #[must_use] + /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ + pub fn back_mut(&mut self) -> Option<&mut T> { + self.list.back_mut() + } +} + +/// An iterator produced by calling `extract_if` on LinkedList. +/*#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]*/ +#[must_use = "iterators are lazy and do nothing unless consumed"] +pub struct ExtractIf< + 'a, + T: 'a, + F: 'a, + /*#[unstable(feature = "allocator_api", issue = "32838")]*/ A: Allocator = Global, +> where + F: FnMut(&mut T) -> bool, +{ + list: &'a mut LinkedList, + it: Option>>, + pred: F, + idx: usize, + old_len: usize, +} + +/*@ + +pred_ctor ExtractIf_fbc(t: thread_id_t, list: *LinkedList, ghost_cell_id: i32, old_len: usize)() = + [1/2]ghost_cell::>>, usize>>(ghost_cell_id, pair(?it, ?idx)) &*& + (*list).alloc |-> ?alloc &*& Allocator::(t, alloc, ?alloc_id) &*& + (*list).head |-> ?head &*& + (*list).tail |-> ?tail &*& + Nodes::(alloc_id, head, None, ?prev, it, ?nodes1) &*& + Nodes::(alloc_id, it, prev, tail, None, ?nodes2) &*& + foreach(nodes1, elem_fbc::(t)) &*& + foreach(nodes2, elem_fbc::(t)) &*& + (*list).len |-> length(append(nodes1, nodes2)) &*& + old_len <= usize::MAX &*& + old_len - idx == length(nodes2); + +pred<'a, T, F, A> >.own(t, ex) = + .own(t, ex.`pred`) &*& 0 <= ex.idx &*& + [1/2]ghost_cell::>>, usize>>(?ghost_cell_id, pair(ex.it, ex.idx)) &*& + full_borrow('a, ExtractIf_fbc::(t, ex.list, ghost_cell_id, ex.old_len)); + +lem ExtractIf_drop<'a, T, F, A>() + req ExtractIf_own::<'a, T, F, A>(?_t, ?_v); + ens .own(_t, _v.`pred`); +{ + open >.own(_t, _v); + leak full_borrow(_, _); + leak [1/2]ghost_cell(_, _); +} + +lem ExtractIf_own_mono<'a0, 'a1, T, F0, F1, A>() + req type_interp::() &*& type_interp::() &*& type_interp::() &*& type_interp::() &*& ExtractIf_own::<'a0, T, F0, A>(?t, ?v) &*& lifetime_inclusion('a1, 'a0) == true &*& is_subtype_of::() == true; + ens type_interp::() &*& type_interp::() &*& type_interp::() &*& type_interp::() &*& ExtractIf_own::<'a1, T, F1, A>(t, ExtractIf::<'a1, T, F1, A> { list: v.list as *_, it: upcast(v.it), `pred`: upcast(v.`pred`), idx: upcast(v.idx), old_len: upcast(v.old_len) }); +{ + assume(false); +} + +@*/ + +fn call_pred bool>(f: &mut F, element: &mut T) -> bool +//@ req thread_token(?t) &*& *f |-> ?f0 &*& .own(t, f0) &*& *element |-> ?element0 &*& .own(t, element0); +//@ ens thread_token(t) &*& *f |-> ?f1 &*& .own(t, f1) &*& *element |-> ?element1 &*& .own(t, element1); +{ + //@ assume(false); //~allow_dead_code + f(element) //~allow_dead_code +} //~allow_dead_code + +/*#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]*/ +impl<'a, T, F, A: Allocator> Iterator for ExtractIf<'a, T, F, A> +where + F: FnMut(&mut T) -> bool, +{ + type Item = T; + + fn next(&mut self) -> Option + //@ req thread_token(?t) &*& [?q]lifetime_token('a) &*& *self |-> ?self0 &*& >.own(t, self0); + //@ ens thread_token(t) &*& [q]lifetime_token('a) &*& *self |-> ?self1 &*& >.own(t, self1) &*& >.own(t, result); + { + loop { //while let Some(mut node) = self.it { + //@ inv thread_token(t) &*& [q]lifetime_token('a) &*& *self |-> ?self1 &*& >.own(t, self1) &*& node |-> _; + //@ open_points_to(self); + match self.it { + None => break, + Some(mut node) => unsafe { + //@ open >.own(t, self1); + //@ assert [1/2]ghost_cell(?ghost_cell_id, _); + //@ open_full_borrow(q, 'a, ExtractIf_fbc(t, self1.list, ghost_cell_id, self1.old_len)); + //@ open ExtractIf_fbc::(t, self1.list, ghost_cell_id, self1.old_len)(); + //@ assert Allocator::(t, ?alloc, _); + //@ open Nodes(?alloc_id, self1.it, ?prev, ?tail, None, ?nodes2); + self.it = (*node.as_ptr()).next; //node.as_ref().next; + self.idx += 1; + //@ ghost_cell_mutate(ghost_cell_id, pair((*self).it, (*self).idx)); + + //@ open foreach(nodes2, elem_fbc::(t)); + //@ open elem_fbc::(t)(node); + + if call_pred(&mut self.pred, &mut node.as_mut().element) { + // `unlink_node` is okay with aliasing `element` references. + self.list.unlink_node(node); + //@ let alloc_ref = precreate_ref(&(*(*self).list).alloc); + //@ std::alloc::init_ref_Allocator::<'static, A>(alloc_ref); + let r = Some(Box::into_inner(Box::from_raw_in(node.as_ptr(), &self.list.alloc)).element); + //@ std::alloc::end_ref_Allocator::<'static, A>(); + //@ close ExtractIf_fbc::(t, self1.list, ghost_cell_id, self1.old_len)(); + //@ close_full_borrow(ExtractIf_fbc(t, self1.list, ghost_cell_id, self1.old_len)); + //@ close >.own(t, *self); + //@ close >.own(t, r); + return r + } + + //@ assert Nodes(_, ?head, None, _, self1.it, ?nodes1); + //@ Nodes_append_one_(head); + //@ close foreach([], elem_fbc::(t)); + //@ close elem_fbc::(t)(node); + //@ close foreach([node], elem_fbc::(t)); + //@ foreach_append(nodes1, [node]); + //@ close ExtractIf_fbc::(t, self1.list, ghost_cell_id, self1.old_len)(); + //@ close_full_borrow(ExtractIf_fbc(t, self1.list, ghost_cell_id, self1.old_len)); + //@ close >.own(t, *self); + } + } + } + //@ close >.own(t, None); + None + } + + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.old_len - self.idx)) + } +} + +/*#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]*/ +impl fmt::Debug for ExtractIf<'_, T, F> +where + F: FnMut(&mut T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("ExtractIf").field(&self.list).finish() + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for IntoIter { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.list.pop_front() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.list.len, Some(self.list.len)) + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + self.list.pop_back() + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for IntoIter {} + +//#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for IntoIter {} + +//#[stable(feature = "default_iters", since = "1.70.0")] +impl Default for IntoIter { + /// Creates an empty `linked_list::IntoIter`. + /// + /// ``` + /// # use std::collections::linked_list; + /// let iter: linked_list::IntoIter = Default::default(); + /// assert_eq!(iter.len(), 0); + /// ``` + fn default() -> Self { + LinkedList::new().into_iter() + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl FromIterator for LinkedList { + fn from_iter>(iter: I) -> Self { + let mut list = Self::new(); + list.extend(iter); + list + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for LinkedList { + type Item = T; + type IntoIter = IntoIter; + + /// Consumes the list into an iterator yielding elements by value. + #[inline] + fn into_iter(self) -> IntoIter { + IntoIter { list: self } + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, A: Allocator> IntoIterator for &'a LinkedList { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, A: Allocator> IntoIterator for &'a mut LinkedList { + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl Extend for LinkedList { + fn extend>(&mut self, iter: I) { + >::spec_extend(self, iter); + } + + #[inline] + fn extend_one(&mut self, elem: T) { + self.push_back(elem); + } +} + +impl SpecExtend for LinkedList { + default fn spec_extend(&mut self, iter: I) { + iter.into_iter().for_each(move |elt| self.push_back(elt)); + } +} + +impl SpecExtend> for LinkedList { + fn spec_extend(&mut self, ref mut other: LinkedList) { + self.append(other); + } +} + +//#[stable(feature = "extend_ref", since = "1.2.0")] +impl<'a, T: 'a + Copy, A: Allocator> Extend<&'a T> for LinkedList { + fn extend>(&mut self, iter: I) { + self.extend(iter.into_iter().cloned()); + } + + #[inline] + fn extend_one(&mut self, &elem: &'a T) { + self.push_back(elem); + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for LinkedList { + fn eq(&self, other: &Self) -> bool { + self.len() == other.len() && self.iter().eq(other) + } + + fn ne(&self, other: &Self) -> bool { + self.len() != other.len() || self.iter().ne(other) + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for LinkedList {} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for LinkedList { + fn partial_cmp(&self, other: &Self) -> Option { + self.iter().partial_cmp(other) + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for LinkedList { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.iter().cmp(other) + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for LinkedList { + fn clone(&self) -> Self { + let mut list = Self::new_in(self.alloc.clone()); + list.extend(self.iter().cloned()); + list + } + + /// Overwrites the contents of `self` with a clone of the contents of `source`. + /// + /// This method is preferred over simply assigning `source.clone()` to `self`, + /// as it avoids reallocation of the nodes of the linked list. Additionally, + /// if the element type `T` overrides `clone_from()`, this will reuse the + /// resources of `self`'s elements as well. + fn clone_from(&mut self, source: &Self) { + let mut source_iter = source.iter(); + if self.len() > source.len() { + self.split_off(source.len()); + } + for (elem, source_elem) in self.iter_mut().zip(&mut source_iter) { + elem.clone_from(source_elem); + } + if !source_iter.is_empty() { + self.extend(source_iter.cloned()); + } + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for LinkedList { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self).finish() + } +} + +//#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for LinkedList { + fn hash(&self, state: &mut H) { + state.write_length_prefix(self.len()); + for elt in self { + elt.hash(state); + } + } +} + +//#[stable(feature = "std_collections_from_array", since = "1.56.0")] +impl From<[T; N]> for LinkedList { + /// Converts a `[T; N]` into a `LinkedList`. + /// + /// ``` + /// use std::collections::LinkedList; + /// + /// let list1 = LinkedList::from([1, 2, 3, 4]); + /// let list2: LinkedList<_> = [1, 2, 3, 4].into(); + /// assert_eq!(list1, list2); + /// ``` + fn from(arr: [T; N]) -> Self { + Self::from_iter(arr) + } +} + +// Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters. +#[allow(dead_code)] +fn assert_covariance_a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> { + x +} + +#[allow(dead_code)] +fn assert_covariance_b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> { + x +} + +#[allow(dead_code)] +fn assert_covariance_c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> { + x +} + +//#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for LinkedList {} + +//#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for LinkedList {} + +//#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Sync> Send for Iter<'a, T> {} + +//#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {} + +//#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Send> Send for IterMut<'a, T> {} + +//#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {} + +/*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +unsafe impl<'a, T: Sync, A: Allocator + Sync> Send for Cursor<'a, T, A> {} + +/*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +unsafe impl<'a, T: Sync, A: Allocator + Sync> Sync for Cursor<'a, T, A> {} + +/*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +unsafe impl<'a, T: Send, A: Allocator + Send> Send for CursorMut<'a, T, A> {} + +/*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ +unsafe impl<'a, T: Sync, A: Allocator + Sync> Sync for CursorMut<'a, T, A> {} diff --git a/verifast-proofs/check-verifast-proofs.mysh b/verifast-proofs/check-verifast-proofs.mysh new file mode 100644 index 0000000000000..6bf4e19c01ba9 --- /dev/null +++ b/verifast-proofs/check-verifast-proofs.mysh @@ -0,0 +1,5 @@ +cd alloc + cd collections + call check-verifast-proofs.mysh + cd .. +cd .. From f0566cb61126e492379cfc7957d60939ef22e67a Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Mon, 20 Jan 2025 17:54:20 +0100 Subject: [PATCH 2/8] Print working directory --- .github/workflows/verifast.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/verifast.yml b/.github/workflows/verifast.yml index c87b7cbe91674..62c09162ab48b 100644 --- a/.github/workflows/verifast.yml +++ b/.github/workflows/verifast.yml @@ -36,6 +36,7 @@ jobs: - name: Run VeriFast Verification run: | + pwd export PATH=~/verifast-24.12/bin:$PATH cd verifast-proofs mysh check-verifast-proofs.mysh From 5bdac9aa397deb4ba6d380cbf4cf7b98946c935f Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Mon, 20 Jan 2025 17:56:03 +0100 Subject: [PATCH 3/8] Simplify checkout --- .github/workflows/verifast.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/verifast.yml b/.github/workflows/verifast.yml index 62c09162ab48b..f1ecd7db71e80 100644 --- a/.github/workflows/verifast.yml +++ b/.github/workflows/verifast.yml @@ -23,9 +23,6 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 - with: - path: head - submodules: true - name: Install VeriFast run: | @@ -36,7 +33,6 @@ jobs: - name: Run VeriFast Verification run: | - pwd export PATH=~/verifast-24.12/bin:$PATH cd verifast-proofs mysh check-verifast-proofs.mysh From e9c244e88b13abf3ac73a0a133f4e5cc5902955a Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Mon, 20 Jan 2025 18:04:01 +0100 Subject: [PATCH 4/8] Use GNU diff, not MacOS diff --- .../collections/linked_list.code-changes.diff | 149 +++++++++--------- 1 file changed, 73 insertions(+), 76 deletions(-) diff --git a/verifast-proofs/alloc/collections/linked_list.code-changes.diff b/verifast-proofs/alloc/collections/linked_list.code-changes.diff index 5302806a2ed5c..8e96a34baebc8 100644 --- a/verifast-proofs/alloc/collections/linked_list.code-changes.diff +++ b/verifast-proofs/alloc/collections/linked_list.code-changes.diff @@ -1,11 +1,11 @@ 0a1,2 > // verifast_options{prover:z3v4.5 skip_specless_fns} > -13c15 +13c15,27 < #![stable(feature = "rust1", since = "1.0.0")] --- > // This is a slightly tweaked version of https://github.com/rust-lang/rust/blob/c290e9de32e8ba6a673ef125fde40eadd395d170/library/alloc/src/collections/linked_list.rs -14a17,28 +> > //#![stable(feature = "rust1", since = "1.0.0")] > #![feature(rustc_attrs)] > #![feature(dropck_eyepatch)] @@ -17,7 +17,6 @@ > #![feature(box_into_inner)] > > use std as core; -> 15a30 > use core::fmt; 16a32 @@ -26,14 +25,13 @@ > use core::mem; 20d36 < use core::{fmt, mem}; -22,24c38,39 +22,24c38,40 < use super::SpecExtend; < use crate::alloc::{Allocator, Global}; < use crate::boxed::Box; --- > use std::alloc::{Allocator, Global}; > use std::boxed::Box; -25a41 > 28a45,48 > trait SpecExtend { @@ -194,7 +192,7 @@ --- > unsafe fn pop_front_node<'a>(&'a mut self) -> Option, &'a A>> > { -197,199c225,229 +197,199c225,235 < self.head.map(|node| unsafe { < let node = Box::from_raw_in(node.as_ptr(), &self.alloc); < self.head = node.next; @@ -204,26 +202,26 @@ > Some(node) => unsafe { > self.head = (*node.as_ptr()).next; > let node_ = Box::from_raw_in(node.as_ptr(), &self.alloc); -201,205c231,235 -< match self.head { -< None => self.tail = None, -< // Not creating new mutable (unique!) references overlapping `element`. -< Some(head) => (*head.as_ptr()).prev = None, -< } ---- +> > match self.head { > None => self.tail = None, > // Not creating new mutable (unique!) references overlapping `element`. > Some(head) => (*head.as_ptr()).prev = None, > } -207,209c237,240 +201,204c237,238 +< match self.head { +< None => self.tail = None, +< // Not creating new mutable (unique!) references overlapping `element`. +< Some(head) => (*head.as_ptr()).prev = None, +--- +> self.len -= 1; +> Some(node_) +206,209c240 +< < self.len -= 1; < node < }) --- -> self.len -= 1; -> Some(node_) -> } > } 224c255 < let node = Some(node); @@ -241,7 +239,7 @@ < self.tail = node; --- > self.tail = node_; -242,244c273,277 +242,244c273,283 < self.tail.map(|node| unsafe { < let node = Box::from_raw_in(node.as_ptr(), &self.alloc); < self.tail = node.prev; @@ -251,26 +249,26 @@ > Some(node) => unsafe { > let node_ = Box::from_raw_in(node.as_ptr(), &self.alloc); > self.tail = node_.prev; -246,250c279,283 -< match self.tail { -< None => self.head = None, -< // Not creating new mutable (unique!) references overlapping `element`. -< Some(tail) => (*tail.as_ptr()).next = None, -< } ---- +> > match self.tail { > None => self.head = None, > // Not creating new mutable (unique!) references overlapping `element`. > Some(tail) => (*tail.as_ptr()).next = None, > } -252,254c285,288 +246,249c285,286 +< match self.tail { +< None => self.head = None, +< // Not creating new mutable (unique!) references overlapping `element`. +< Some(tail) => (*tail.as_ptr()).next = None, +--- +> self.len -= 1; +> Some(node_) +251,254c288 +< < self.len -= 1; < node < }) --- -> self.len -= 1; -> Some(node_) -> } > } 264,265c298,300 < unsafe fn unlink_node(&mut self, mut node: NonNull>) { @@ -543,7 +541,7 @@ < #[stable(feature = "rust1", since = "1.0.0")] --- > //#[stable(feature = "rust1", since = "1.0.0")] -955,971c1036,1044 +955,982c1036,1076 < let len = self.len(); < assert!(at <= len, "Cannot split off at a nonexistent index"); < if at == 0 { @@ -561,17 +559,7 @@ < // depending on implementation details of Skip < for _ in 0..at - 1 { < iter.next(); ---- -> unsafe { -> let len = self.len; -> assert!(at <= len, "Cannot split off at a nonexistent index"); -> if at == 0 { -> let alloc1 = clone_allocator(&self.alloc); -> return mem::replace(self, Self::new_in(alloc1)); -> } else if at == len { -> let alloc2 = clone_allocator(&self.alloc); -> return Self::new_in(alloc2); -973,982c1046,1076 +< } < iter.head < } else { < // better off starting from the end @@ -583,6 +571,16 @@ < }; < unsafe { self.split_off_after_node(split_node, at) } --- +> unsafe { +> let len = self.len; +> assert!(at <= len, "Cannot split off at a nonexistent index"); +> if at == 0 { +> let alloc1 = clone_allocator(&self.alloc); +> return mem::replace(self, Self::new_in(alloc1)); +> } else if at == len { +> let alloc2 = clone_allocator(&self.alloc); +> return Self::new_in(alloc2); +> } > > // Below, we iterate towards the `i-1`th node, either from the start or the end, > // depending on which would be faster. @@ -645,35 +643,29 @@ --- > let r = ExtractIf { list: self, it, pred: filter, idx: 0, old_len }; > r -1168,1171c1265 +1168,1169c1265,1267 < #[stable(feature = "rust1", since = "1.0.0")] < unsafe impl<#[may_dangle] T, A: Allocator> Drop for LinkedList { -< fn drop(&mut self) { -< struct DropGuard<'a, T, A: Allocator>(&'a mut LinkedList); --- > struct DropGuard<'a, T, A: Allocator>(&'a mut LinkedList); -1173,1178c1267,1272 -< impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { -< fn drop(&mut self) { -< // Continue the same loop we do below. This only runs when a destructor has -< // panicked. If another one panics this will abort. -< while self.0.pop_front_node().is_some() {} -< } ---- +> > impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { -> fn drop(&mut self) { +1171c1269,1275 +< struct DropGuard<'a, T, A: Allocator>(&'a mut LinkedList); +--- > unsafe { > // Continue the same loop we do below. This only runs when a destructor has > // panicked. If another one panics this will abort. > while self.0.pop_front_node().is_some() {} -1179a1274,1275 +> } > } > } -1181,1184c1277,1292 -< // Wrap self so that if a destructor panics, we can try to keep looping -< let guard = DropGuard(self); -< while guard.0.pop_front_node().is_some() {} -< mem::forget(guard); +1173,1177c1277,1289 +< impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { +< fn drop(&mut self) { +< // Continue the same loop we do below. This only runs when a destructor has +< // panicked. If another one panics this will abort. +< while self.0.pop_front_node().is_some() {} --- > //#[stable(feature = "rust1", since = "1.0.0")] > unsafe impl<#[may_dangle] T, A: Allocator> Drop for LinkedList { @@ -688,9 +680,14 @@ > Some(element) => { > } > } -> } +1178a1291 > mem::forget(guard); -> } +1180,1184d1292 +< +< // Wrap self so that if a destructor panics, we can try to keep looping +< let guard = DropGuard(self); +< while guard.0.pop_front_node().is_some() {} +< mem::forget(guard); 1188c1296 < #[stable(feature = "rust1", since = "1.0.0")] --- @@ -901,8 +898,7 @@ < #[unstable(feature = "linked_list_cursors", issue = "58533")] --- > /*#[unstable(feature = "linked_list_cursors", issue = "58533")]*/ -1614,1625d1740 -< } +1615,1626d1741 < < /// Provides a read-only reference to the cursor's parent list. < /// @@ -914,6 +910,7 @@ < #[unstable(feature = "linked_list_cursors", issue = "58533")] < pub fn as_list(&self) -> &LinkedList { < self.list +< } 1636c1751 < #[unstable(feature = "linked_list_cursors", issue = "58533")] --- @@ -1019,12 +1016,17 @@ > > /*#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]*/ > impl<'a, T, F, A: Allocator> Iterator for ExtractIf<'a, T, F, A> -1959,1963c2087,2095 +1959,1968c2087,2103 < fn next(&mut self) -> Option { < while let Some(mut node) = self.it { < unsafe { < self.it = node.as_ref().next; < self.idx += 1; +< +< if (self.pred)(&mut node.as_mut().element) { +< // `unlink_node` is okay with aliasing `element` references. +< self.list.unlink_node(node); +< return Some(Box::from_raw_in(node.as_ptr(), &self.list.alloc).element); --- > fn next(&mut self) -> Option > { @@ -1035,12 +1037,7 @@ > self.it = (*node.as_ptr()).next; //node.as_ref().next; > self.idx += 1; > -1965,1968c2097,2103 -< if (self.pred)(&mut node.as_mut().element) { -< // `unlink_node` is okay with aliasing `element` references. -< self.list.unlink_node(node); -< return Some(Box::from_raw_in(node.as_ptr(), &self.list.alloc).element); ---- +> > if call_pred(&mut self.pred, &mut node.as_mut().element) { > // `unlink_node` is okay with aliasing `element` references. > self.list.unlink_node(node); @@ -1130,7 +1127,7 @@ < #[stable(feature = "std_collections_from_array", since = "1.56.0")] --- > //#[stable(feature = "std_collections_from_array", since = "1.56.0")] -2203,2212c2337,2338 +2203,2212c2337,2348 < fn assert_covariance() { < fn a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> { < x @@ -1144,9 +1141,8 @@ --- > fn assert_covariance_a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> { > x -2215c2341,2351 -< #[stable(feature = "rust1", since = "1.0.0")] ---- +> } +> > #[allow(dead_code)] > fn assert_covariance_b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> { > x @@ -1155,8 +1151,9 @@ > #[allow(dead_code)] > fn assert_covariance_c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> { > x -> } -> +2215c2351 +< #[stable(feature = "rust1", since = "1.0.0")] +--- > //#[stable(feature = "rust1", since = "1.0.0")] 2218c2354 < #[stable(feature = "rust1", since = "1.0.0")] From ba5fd04ced0a0a89bacb2c3e500ba95ada2239fb Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Mon, 20 Jan 2025 18:08:11 +0100 Subject: [PATCH 5/8] Install Rust toolchain used by VeriFast --- .github/workflows/verifast.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/verifast.yml b/.github/workflows/verifast.yml index f1ecd7db71e80..02b375d8c8791 100644 --- a/.github/workflows/verifast.yml +++ b/.github/workflows/verifast.yml @@ -31,6 +31,9 @@ jobs: echo '51bebf990f31666abcd3675000e7714ef79b417390e930953ef25383e8d59421 verifast-24.12-linux.tar.gz' | shasum -a 256 -c tar xf verifast-24.12-linux.tar.gz + - name: Install the Rust toolchain used by VeriFast + run: rustup toolchain install nightly-2024-11-24 + - name: Run VeriFast Verification run: | export PATH=~/verifast-24.12/bin:$PATH From 945153ef8e89f492b9682f18c998a3b37e57f7b5 Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Mon, 20 Jan 2025 18:10:04 +0100 Subject: [PATCH 6/8] Toolchain nightly-2024-11-23 --- .github/workflows/verifast.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verifast.yml b/.github/workflows/verifast.yml index 02b375d8c8791..5921f351b4f4d 100644 --- a/.github/workflows/verifast.yml +++ b/.github/workflows/verifast.yml @@ -32,7 +32,7 @@ jobs: tar xf verifast-24.12-linux.tar.gz - name: Install the Rust toolchain used by VeriFast - run: rustup toolchain install nightly-2024-11-24 + run: rustup toolchain install nightly-2024-11-23 - name: Run VeriFast Verification run: | From 685cb489af61d8839858cbef95bf0f277e70188c Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Tue, 21 Jan 2025 07:11:34 +0100 Subject: [PATCH 7/8] Mention VeriFast build attestation --- .github/workflows/verifast.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/verifast.yml b/.github/workflows/verifast.yml index 5921f351b4f4d..686942e8129c4 100644 --- a/.github/workflows/verifast.yml +++ b/.github/workflows/verifast.yml @@ -28,6 +28,7 @@ jobs: run: | cd ~ curl -OL https://github.com/verifast/verifast/releases/download/24.12/verifast-24.12-linux.tar.gz + # https://github.com/verifast/verifast/attestations/3689894 echo '51bebf990f31666abcd3675000e7714ef79b417390e930953ef25383e8d59421 verifast-24.12-linux.tar.gz' | shasum -a 256 -c tar xf verifast-24.12-linux.tar.gz From e1372106913592b0edd30025a17a89eed82635a2 Mon Sep 17 00:00:00 2001 From: Bart Jacobs Date: Thu, 23 Jan 2025 00:01:02 +0100 Subject: [PATCH 8/8] Add a VeriFast tool chapter to the book --- doc/src/SUMMARY.md | 1 + doc/src/tools.md | 1 + doc/src/tools/verifast.md | 185 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 doc/src/tools/verifast.md diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md index e6b2a9c78e598..fc387ae2e0e6a 100644 --- a/doc/src/SUMMARY.md +++ b/doc/src/SUMMARY.md @@ -8,6 +8,7 @@ - [Verification Tools](./tools.md) - [Kani](./tools/kani.md) + - [VeriFast](./tools/verifast.md) --- diff --git a/doc/src/tools.md b/doc/src/tools.md index 0eaba7c40d4d8..cba0eb74b2606 100644 --- a/doc/src/tools.md +++ b/doc/src/tools.md @@ -12,6 +12,7 @@ please see the [Tool Application](general-rules.md#tool-applications) section. | Tool | CI Status | |---------------------|-------| | Kani Rust Verifier | [![Kani](https://github.com/model-checking/verify-rust-std/actions/workflows/kani.yml/badge.svg)](https://github.com/model-checking/verify-rust-std/actions/workflows/kani.yml) | + | VeriFast for Rust | [![VeriFast](https://github.com/model-checking/verify-rust-std/actions/workflows/verifast.yml/badge.svg)](https://github.com/model-checking/verify-rust-std/actions/workflows/verifast.yml) | diff --git a/doc/src/tools/verifast.md b/doc/src/tools/verifast.md new file mode 100644 index 0000000000000..55aff199be8dc --- /dev/null +++ b/doc/src/tools/verifast.md @@ -0,0 +1,185 @@ +# VeriFast for Rust + +[VeriFast](https://github.com/verifast/verifast) is a tool for verifying the +absence of [undefined +behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) +in single-threaded or multithreaded Rust programs that use `unsafe` blocks, and +for verifying +[soundness](https://doc.rust-lang.org/nomicon/working-with-unsafe.html) of Rust +crates/modules that use `unsafe` blocks. VeriFast performs *modular +verification*: it verifies one function at a time; during the verification of +one function, if that function calls another function, VeriFast uses the +callee's *specification*, not its implementation, to reason about the call. +VeriFast verifies each function against its specification: it verifies that, if +started in a state that satisfies the precondition, the function does not have +undefined behavior and any state in which it returns satisfies the +postcondition. + +Besides requiring that the user annotate each function with a precondition and +a postcondition, VeriFast also requires that the user annotate each loop with a +loop invariant. This enables its modular symbolic execution algorithm to +perform only a single symbolic execution of the loop's body to cover all +possible real executions of the loop. Furthermore, the use of function +specifications means a single symbolic execution of a function covers all +possible real executions, even if the function is recursive. In summary, these +annotations enable VeriFast to perform unbounded verification (i.e. of +arbitrarily long, including infinitely long, executions) in finite time. + +VeriFast function specifications and loop invariants are expressed in a form of +[*separation logic*](https://en.wikipedia.org/wiki/Separation_logic), and it +performs symbolic execution using a separation logic-based representation of +memory. Separation logic addresses the problem of *aliasing*, which is that in +programs involving pointers or references, different expressions can denote the +same variable. By enabling assertions to express exclusive *ownership* of +memory regions, separation logic enables concise specifications, proper +information hiding, and efficient verification for pointer-manipulating +programs. + +## Verifying `unsafe` functions + +Consider, for example, the function `Node::reverse` below that reverses the +given linked list in-place and returns a pointer to the first node (which +was the originally the last node). + +```rust +struct Node { + next: *mut Node, +} + +/*@ + +pred Nodes(n: *mut Node; nodes: list<*mut Node>) = + if n == 0 { + nodes == nil + } else { + (*n).next |-> ?next &*& Nodes(next, ?nodes0) &*& nodes == cons(n, nodes0) + }; + +@*/ + +impl Node { + + unsafe fn reverse(mut n: *mut Node) -> *mut Node + //@ req Nodes(n, ?nodes); + //@ ens Nodes(result, reverse(nodes)); + //@ on_unwind_ens false; + { + let mut m = std::ptr::null_mut(); + loop { + //@ inv Nodes(n, ?n_nodes) &*& Nodes(m, ?m_nodes) &*& reverse(nodes) == append(reverse(n_nodes), m_nodes); + //@ open Nodes(n, _); + if n.is_null() { + return m; + } + let k = (*n).next; + //@ append_assoc(reverse(tail(n_nodes)), [n], m_nodes); + (*n).next = m; + m = n; + n = k; + } + } + +} +``` + +VeriFast interprets comments of the form `/*@ ... @*/` or `//@ ...` as VeriFast annotations. This example illustrates four types of annotations: +- Three *specification clause annotations* specify the function's precondition, postcondition, and unwind postcondition, respectively. The function never unwinds, so its + unwind postcondition is `false`. +- The precondition and postcondition are specified in terms of the separation logic predicate `Nodes`, defined in a *ghost declaration annotation*. This predicate + recursively defines the memory footprint of the linked list starting at a given node `n` and associates it with a mathematical list `nodes` of node locations. + The separating conjunction `&*&` implies that the first node of the linked list is *separate* from the remainder of the linked list. It follows that mutating the first node does not affect + the remainder of the linked list. The *variable pattern* `?next` binds logical variable `next` to the value of field `(*n).next`; its scope extends to the end of the assertion. + If a logical variable is introduced in a precondition, its scope includes the postcondition. +- At the start of the loop body, a *block annotation* specifies the loop invariant, expressing that `n` and `m` point to disjoint linked lists and expressing the relationship between their contents and that of the original linked list. +- *Ghost command annotations* provide hints needed for the symbolic execution algorithm to succeed. `open Nodes(n, _)` unfolds the `Nodes` predicate application whose first argument equals `n`. `append_assoc` invokes a library *lemma* expressing the associativity of the `append` operation on mathematical lists. + +The generic mathematical datatype `list` is defined in file [`list.rsspec`](https://github.com/verifast/verifast/blob/master/bin/rust/list.rsspec), part of VeriFast's *prelude*, as follows: +``` +inductive list = nil | cons(t, list); +``` +A list of `t` values is either empty, denoted by *constructor* `nil`, or nonempty, with first element (or *head*) `v` and remainder (or *tail*) `vs`, denoted by `cons(v, vs)`. + +Mathematical functions `append` and `reverse` are defined in the same file as follows: +``` +fix append(xs: list, ys: list) -> list { + match xs { + nil => ys, + cons(x, xs0) => cons(x, append(xs0, ys)) + } +} + +fix reverse(xs: list) -> list { + match xs { + nil => nil, + cons(x, xs0) => append(reverse(xs0), cons(x, nil)) + } +} +``` +Lemma `append_assoc` is declared (but not proven) in the same file. Here is a proof: +``` +lem append_assoc(xs: list, ys: list, zs: list) + req true; + ens append(append(xs, ys), zs) == append(xs, append(ys, zs)); +{ + match xs { + nil => {} + cons(x, xs0) => { + append_assoc(xs0, ys, zs); + } + } +} +``` +A lemma is like a regular Rust function, except that it is declared inside an annotation. VeriFast checks that it has no side effects and that it terminates. + +## Verifying safe abstractions + +Consider the following broken implementation of [`std::mem::replace`](https://doc.rust-lang.org/std/mem/fn.replace.html): +```rust +fn replace(dest: &mut T, src: T) -> T { + unsafe { + let result = (dest as *mut T).read(); + (dest as *mut T).write(src); + (dest as *mut T).read() // should be `result` + } +} +``` +The Rust compiler accepts it just fine, but VeriFast complains that it cannot prove that when this function returns, the ownership of the value pointed to by `dest` is *separate* from the ownership of the return value. If we replace the final line by `result`, VeriFast accepts the code. + +For a function not marked as `unsafe`, VeriFast generates a specification expressing that the function is *semantically well-typed* per [RustBelt](https://research.ralfj.de/thesis.html)'s definition of what Rust's types mean in separation logic. If no specification clause annotations are provided for the function, VeriFast verifies the function against the generated specification; otherwise, VeriFast first verifies that the provided specification implies the generated one, and then verifies the function against the provided specification. + +The generated specification for `replace` is as follows: +```rust +fn replace(dest: &mut T, src: T) -> T +//@ req thread_token(?_t) &*& *dest |-> ?dest0 &*& .own(_t, dest0) &*& .own(_t, src); +//@ ens thread_token(_t) &*& *dest |-> ?dest1 &*& .own(_t, dest1) &*& .own(_t, result); +``` +The thread token serves as a proof that the function is running in thread `_t`, which is the thread that owns the incoming T values. (This matters in case T is not [Send](https://doc.rust-lang.org/nomicon/send-and-sync.html).) `.own(t, v)` expresses ownership of the T value `v` by thread `t`. + +For more information on how to verify safe abstractions in VeriFast, see the relevant [chapter](https://verifast.github.io/verifast/rust-reference/non-unsafe-funcs.html) in the VeriFast for Rust Reference and the [examples](https://github.com/verifast/verifast/tree/master/tests/rust/safe_abstraction) (in `tests/rust/safe_abstraction` in the VeriFast binary distributions). (See [`testsuite.mysh`](https://github.com/verifast/verifast/blob/master/tests/rust/testsuite.mysh) to learn the command line to use to verify a particular example.) + +## Running VeriFast + +To run VeriFast, download a binary distribution for your platform, either the +[nightly build](https://github.com/verifast/verifast/releases/tag/nightly) or +the [latest named +release](https://github.com/verifast/verifast/releases/latest). Extract the +archive to any folder on your computer. (On Macs, first [remove the quarantine +bit](https://github.com/verifast/verifast?tab=readme-ov-file#binaries).) Then, +either use the VeriFast IDE at `bin/vfide`, the command-line tool at +`bin/verifast`, or the [VSCode +extension](https://marketplace.visualstudio.com/items?itemName=VeriFast.verifast). +In the IDE, open a file and press F5 to verify it. VeriFast will then either +report "0 errors found" or show a debugger-like GUI that allows you to step +through the failed symbolic execution path and inspect the symbolic state at +each step. If verification succeeds, choose Show execution tree to see the tree +of symbolic execution paths traversed for each function that was verified. + +In the IDE, the Verify menu allows you to postpone dealing with certain +complexities of the verification task. Specifically, you can tell VeriFast to +ignore unwind paths, ignore arithmetic overflow, and treat shared reference +creation like raw pointer creation (which ignores the complexities of Rust's +[pointer aliasing +rules](https://marketplace.visualstudio.com/items?itemName=VeriFast.verifast)). +(Many of the other options are only relevant when verifying C programs and have +no effect when verifying Rust programs.) All of these options can also be +specified on the command line.