···1313as the write locking spins forever.
14141515PRs should keep this state as much as possible.
1616+1717+## std::mem::forget
1818+Forgetting a Read/Write guard could lead to UB, so i detect that and panic if it happens. In order to make
1919+the detection cheap it doesn't differentiate between cases where a forget would lead to UB and cases where
2020+it doesn't. Just don't forget the guards and it won't panic.
+20-8
src/lib.rs
···3636#[derive(Debug)]
3737pub struct Reader<T> {
3838 shared: NonNull<Shared<T>>,
3939+ locked: bool,
3940 /// for drop check
4041 _own: PhantomData<Shared<T>>,
4142}
···49505051 /// this function never blocks. (`fetch_update` loop doesn't count)
5152 pub fn lock(&mut self) -> ReadGuard<'_, T> {
5353+ if self.locked {
5454+ self.locked = false;
5555+ panic!("ReadGuard was forgotten");
5656+ }
5757+ self.locked = true;
5258 // SAFETY: value just locked
5359 let value = unsafe { &*self.shared_ref().lock_read().get() };
5460 ReadGuard {
···6571 fn drop(&mut self) {
6672 // SAFETY: self.shared is valid and not used after this.
6773 unsafe { Shared::drop(self.shared) };
7474+ assert!(!self.locked, "ReadGuard was forgotten");
6875 }
6976}
7077···7481/// Doesn't implement Clone as that would require refcounting to know when to unlock.
7582#[derive(Debug)]
7683pub struct ReadGuard<'a, T> {
7777- reader: &'a Reader<T>,
8484+ reader: &'a mut Reader<T>,
7885 value: &'a T,
7986}
8087···100107 fn drop(&mut self) {
101108 // release the read lock
102109 self.reader.shared_ref().release_read_lock();
110110+ self.reader.locked = false;
103111 }
104112}
105113···112120 write_ptr: Ptr,
113121 // buffer is pushed at the back and popped at the front.
114122 op_buffer: VecDeque<O>,
123123+ locked: bool,
115124 // needed for drop_check
116125 _own: PhantomData<Shared<T>>,
117126}
···152161 Reader {
153162 shared: self.shared,
154163 _own: PhantomData,
164164+ locked: false,
155165 }
156166 })
157167 }
···161171impl<T: Absorb<O>, O> Writer<T, O> {
162172 /// doesn't block. Returns None if the Reader has a `ReadGuard` pointing to the old value.
163173 pub fn try_lock(&mut self) -> Option<WriteGuard<'_, T, O>> {
174174+ if self.locked {
175175+ self.locked = false;
176176+ panic!("WriteGuard was forgotten");
177177+ }
164178 self.shared_ref()
165179 .lock_write(self.write_ptr)
166180 .ok()
167181 // locking was successful
168182 .map(|()| {
169169- // WriteGuard::new(self)
183183+ self.locked = true;
170184 let mut guard = WriteGuard { writer: self };
171185 while let Some(operation) = guard.writer.op_buffer.pop_front() {
172186 guard.get_data_mut().absorb(operation);
···186200 write_ptr,
187201 op_buffer: VecDeque::new(),
188202 _own: PhantomData,
203203+ locked: false,
189204 }
190205 }
191206}
···201216 write_ptr,
202217 op_buffer: VecDeque::new(),
203218 _own: PhantomData,
219219+ locked: false,
204220 }
205221 }
206222}
···229245 fn drop(&mut self) {
230246 // SAFETY: self.shared is valid and not used after this.
231247 unsafe { Shared::drop(self.shared) };
248248+ assert!(!self.locked, "WriteGuard was forgotten");
232249 }
233250}
234251···290307 }
291308}
292309293293-// /// SAFETY: behaves like a &mut T and &mut Vec<O>. https://doc.rust-lang.org/stable/std/marker/trait.Sync.html
294294-// unsafe impl<T: Send, O: Send> Send for WriteGuard<'_, T, O> {}
295295-296296-// /// Safety: can only create shared refs to T, not to O. https://doc.rust-lang.org/stable/std/marker/trait.Sync.html
297297-// unsafe impl<T: Sync, O> Sync for WriteGuard<'_, T, O> {}
298298-299310impl<T, O> Drop for WriteGuard<'_, T, O> {
300311 fn drop(&mut self) {
301312 self.writer.swap();
313313+ self.writer.locked = false;
302314 }
303315}
304316
+2-1
tests/tests.rs
···327327 }
328328329329 #[test]
330330+ #[should_panic]
330331 fn forget_lock() {
331332 let mut writer: Writer<i32, CounterAddOp> = Writer::new(0);
332333 let mut reader = writer.build_reader().unwrap();
333334334335 let write = writer.try_lock().unwrap();
335336 core::mem::forget(write);
336336- let write = writer.try_lock().unwrap();
337337+ let _ = writer.try_lock().unwrap();
337338338339 let read = reader.lock();
339340 core::mem::forget(read);