mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-31 21:16:44 +00:00 
			
		
		
		
	 83abb7c18f
			
		
	
	
		83abb7c18f
		
	
	
	
	
		
			
			These guards changed to pointers in #97027, but their `Display` was formatting that field directly, which made it show the raw pointer value. Now we go through `Deref` to display the real value again.
		
			
				
	
	
		
			480 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			480 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use core::cell::*;
 | |
| use core::default::Default;
 | |
| use std::mem::drop;
 | |
| 
 | |
| #[test]
 | |
| fn smoketest_unsafe_cell() {
 | |
|     let mut x = UnsafeCell::new(10);
 | |
|     let ref_mut = &mut x;
 | |
|     unsafe {
 | |
|         // The asserts are repeated in order to ensure that `get()`
 | |
|         // is non-mutating.
 | |
|         assert_eq!(*ref_mut.get(), 10);
 | |
|         assert_eq!(*ref_mut.get(), 10);
 | |
|         *ref_mut.get_mut() += 5;
 | |
|         assert_eq!(*ref_mut.get(), 15);
 | |
|         assert_eq!(*ref_mut.get(), 15);
 | |
|         assert_eq!(x.into_inner(), 15);
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn unsafe_cell_raw_get() {
 | |
|     let x = UnsafeCell::new(10);
 | |
|     let ptr = &x as *const UnsafeCell<i32>;
 | |
|     unsafe {
 | |
|         // The asserts are repeated in order to ensure that `raw_get()`
 | |
|         // is non-mutating.
 | |
|         assert_eq!(*UnsafeCell::raw_get(ptr), 10);
 | |
|         assert_eq!(*UnsafeCell::raw_get(ptr), 10);
 | |
|         *UnsafeCell::raw_get(ptr) += 5;
 | |
|         assert_eq!(*UnsafeCell::raw_get(ptr), 15);
 | |
|         assert_eq!(*UnsafeCell::raw_get(ptr), 15);
 | |
|         assert_eq!(x.into_inner(), 15);
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn smoketest_cell() {
 | |
|     let x = Cell::new(10);
 | |
|     assert_eq!(x, Cell::new(10));
 | |
|     assert_eq!(x.get(), 10);
 | |
|     x.set(20);
 | |
|     assert_eq!(x, Cell::new(20));
 | |
|     assert_eq!(x.get(), 20);
 | |
| 
 | |
|     let y = Cell::new((30, 40));
 | |
|     assert_eq!(y, Cell::new((30, 40)));
 | |
|     assert_eq!(y.get(), (30, 40));
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn cell_update() {
 | |
|     let x = Cell::new(10);
 | |
| 
 | |
|     assert_eq!(x.update(|x| x + 5), 15);
 | |
|     assert_eq!(x.get(), 15);
 | |
| 
 | |
|     assert_eq!(x.update(|x| x / 3), 5);
 | |
|     assert_eq!(x.get(), 5);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn cell_has_sensible_show() {
 | |
|     let x = Cell::new("foo bar");
 | |
|     assert!(format!("{x:?}").contains(x.get()));
 | |
| 
 | |
|     x.set("baz qux");
 | |
|     assert!(format!("{x:?}").contains(x.get()));
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn ref_and_refmut_have_sensible_show() {
 | |
|     let refcell = RefCell::new("foo");
 | |
| 
 | |
|     let refcell_refmut = refcell.borrow_mut();
 | |
|     assert_eq!(format!("{refcell_refmut}"), "foo"); // Display
 | |
|     assert!(format!("{refcell_refmut:?}").contains("foo")); // Debug
 | |
|     drop(refcell_refmut);
 | |
| 
 | |
|     let refcell_ref = refcell.borrow();
 | |
|     assert_eq!(format!("{refcell_ref}"), "foo"); // Display
 | |
|     assert!(format!("{refcell_ref:?}").contains("foo")); // Debug
 | |
|     drop(refcell_ref);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn double_imm_borrow() {
 | |
|     let x = RefCell::new(0);
 | |
|     let _b1 = x.borrow();
 | |
|     x.borrow();
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn no_mut_then_imm_borrow() {
 | |
|     let x = RefCell::new(0);
 | |
|     let _b1 = x.borrow_mut();
 | |
|     assert!(x.try_borrow().is_err());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn no_imm_then_borrow_mut() {
 | |
|     let x = RefCell::new(0);
 | |
|     let _b1 = x.borrow();
 | |
|     assert!(x.try_borrow_mut().is_err());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn no_double_borrow_mut() {
 | |
|     let x = RefCell::new(0);
 | |
|     assert!(x.try_borrow().is_ok());
 | |
|     let _b1 = x.borrow_mut();
 | |
|     assert!(x.try_borrow().is_err());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn imm_release_borrow_mut() {
 | |
|     let x = RefCell::new(0);
 | |
|     {
 | |
|         let _b1 = x.borrow();
 | |
|     }
 | |
|     x.borrow_mut();
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn mut_release_borrow_mut() {
 | |
|     let x = RefCell::new(0);
 | |
|     {
 | |
|         let _b1 = x.borrow_mut();
 | |
|     }
 | |
|     x.borrow();
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn double_borrow_single_release_no_borrow_mut() {
 | |
|     let x = RefCell::new(0);
 | |
|     let _b1 = x.borrow();
 | |
|     {
 | |
|         let _b2 = x.borrow();
 | |
|     }
 | |
|     assert!(x.try_borrow().is_ok());
 | |
|     assert!(x.try_borrow_mut().is_err());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| #[should_panic]
 | |
| fn discard_doesnt_unborrow() {
 | |
|     let x = RefCell::new(0);
 | |
|     let _b = x.borrow();
 | |
|     let _ = _b;
 | |
|     let _b = x.borrow_mut();
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn ref_clone_updates_flag() {
 | |
|     let x = RefCell::new(0);
 | |
|     {
 | |
|         let b1 = x.borrow();
 | |
|         assert!(x.try_borrow().is_ok());
 | |
|         assert!(x.try_borrow_mut().is_err());
 | |
|         {
 | |
|             let _b2 = Ref::clone(&b1);
 | |
|             assert!(x.try_borrow().is_ok());
 | |
|             assert!(x.try_borrow_mut().is_err());
 | |
|         }
 | |
|         assert!(x.try_borrow().is_ok());
 | |
|         assert!(x.try_borrow_mut().is_err());
 | |
|     }
 | |
|     assert!(x.try_borrow().is_ok());
 | |
|     assert!(x.try_borrow_mut().is_ok());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn ref_map_does_not_update_flag() {
 | |
|     let x = RefCell::new(Some(5));
 | |
|     {
 | |
|         let b1: Ref<'_, Option<u32>> = x.borrow();
 | |
|         assert!(x.try_borrow().is_ok());
 | |
|         assert!(x.try_borrow_mut().is_err());
 | |
|         {
 | |
|             let b2: Ref<'_, u32> = Ref::map(b1, |o| o.as_ref().unwrap());
 | |
|             assert_eq!(*b2, 5);
 | |
|             assert!(x.try_borrow().is_ok());
 | |
|             assert!(x.try_borrow_mut().is_err());
 | |
|         }
 | |
|         assert!(x.try_borrow().is_ok());
 | |
|         assert!(x.try_borrow_mut().is_ok());
 | |
|     }
 | |
|     assert!(x.try_borrow().is_ok());
 | |
|     assert!(x.try_borrow_mut().is_ok());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn ref_map_split_updates_flag() {
 | |
|     let x = RefCell::new([1, 2]);
 | |
|     {
 | |
|         let b1 = x.borrow();
 | |
|         assert!(x.try_borrow().is_ok());
 | |
|         assert!(x.try_borrow_mut().is_err());
 | |
|         {
 | |
|             let (_b2, _b3) = Ref::map_split(b1, |slc| slc.split_at(1));
 | |
|             assert!(x.try_borrow().is_ok());
 | |
|             assert!(x.try_borrow_mut().is_err());
 | |
|         }
 | |
|         assert!(x.try_borrow().is_ok());
 | |
|         assert!(x.try_borrow_mut().is_ok());
 | |
|     }
 | |
|     assert!(x.try_borrow().is_ok());
 | |
|     assert!(x.try_borrow_mut().is_ok());
 | |
| 
 | |
|     {
 | |
|         let b1 = x.borrow_mut();
 | |
|         assert!(x.try_borrow().is_err());
 | |
|         assert!(x.try_borrow_mut().is_err());
 | |
|         {
 | |
|             let (_b2, _b3) = RefMut::map_split(b1, |slc| slc.split_at_mut(1));
 | |
|             assert!(x.try_borrow().is_err());
 | |
|             assert!(x.try_borrow_mut().is_err());
 | |
|             drop(_b2);
 | |
|             assert!(x.try_borrow().is_err());
 | |
|             assert!(x.try_borrow_mut().is_err());
 | |
|         }
 | |
|         assert!(x.try_borrow().is_ok());
 | |
|         assert!(x.try_borrow_mut().is_ok());
 | |
|     }
 | |
|     assert!(x.try_borrow().is_ok());
 | |
|     assert!(x.try_borrow_mut().is_ok());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn ref_map_split() {
 | |
|     let x = RefCell::new([1, 2]);
 | |
|     let (b1, b2) = Ref::map_split(x.borrow(), |slc| slc.split_at(1));
 | |
|     assert_eq!(*b1, [1]);
 | |
|     assert_eq!(*b2, [2]);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn ref_mut_map_split() {
 | |
|     let x = RefCell::new([1, 2]);
 | |
|     {
 | |
|         let (mut b1, mut b2) = RefMut::map_split(x.borrow_mut(), |slc| slc.split_at_mut(1));
 | |
|         assert_eq!(*b1, [1]);
 | |
|         assert_eq!(*b2, [2]);
 | |
|         b1[0] = 2;
 | |
|         b2[0] = 1;
 | |
|     }
 | |
|     assert_eq!(*x.borrow(), [2, 1]);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn ref_map_accessor() {
 | |
|     struct X(RefCell<(u32, char)>);
 | |
|     impl X {
 | |
|         fn accessor(&self) -> Ref<'_, u32> {
 | |
|             Ref::map(self.0.borrow(), |tuple| &tuple.0)
 | |
|         }
 | |
|     }
 | |
|     let x = X(RefCell::new((7, 'z')));
 | |
|     let d: Ref<'_, u32> = x.accessor();
 | |
|     assert_eq!(*d, 7);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn ref_mut_map_accessor() {
 | |
|     struct X(RefCell<(u32, char)>);
 | |
|     impl X {
 | |
|         fn accessor(&self) -> RefMut<'_, u32> {
 | |
|             RefMut::map(self.0.borrow_mut(), |tuple| &mut tuple.0)
 | |
|         }
 | |
|     }
 | |
|     let x = X(RefCell::new((7, 'z')));
 | |
|     {
 | |
|         let mut d: RefMut<'_, u32> = x.accessor();
 | |
|         assert_eq!(*d, 7);
 | |
|         *d += 1;
 | |
|     }
 | |
|     assert_eq!(*x.0.borrow(), (8, 'z'));
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn as_ptr() {
 | |
|     let c1: Cell<usize> = Cell::new(0);
 | |
|     c1.set(1);
 | |
|     assert_eq!(1, unsafe { *c1.as_ptr() });
 | |
| 
 | |
|     let c2: Cell<usize> = Cell::new(0);
 | |
|     unsafe {
 | |
|         *c2.as_ptr() = 1;
 | |
|     }
 | |
|     assert_eq!(1, c2.get());
 | |
| 
 | |
|     let r1: RefCell<usize> = RefCell::new(0);
 | |
|     *r1.borrow_mut() = 1;
 | |
|     assert_eq!(1, unsafe { *r1.as_ptr() });
 | |
| 
 | |
|     let r2: RefCell<usize> = RefCell::new(0);
 | |
|     unsafe {
 | |
|         *r2.as_ptr() = 1;
 | |
|     }
 | |
|     assert_eq!(1, *r2.borrow());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn cell_default() {
 | |
|     let cell: Cell<u32> = Default::default();
 | |
|     assert_eq!(0, cell.get());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn cell_set() {
 | |
|     let cell = Cell::new(10);
 | |
|     cell.set(20);
 | |
|     assert_eq!(20, cell.get());
 | |
| 
 | |
|     let cell = Cell::new("Hello".to_owned());
 | |
|     cell.set("World".to_owned());
 | |
|     assert_eq!("World".to_owned(), cell.into_inner());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn cell_replace() {
 | |
|     let cell = Cell::new(10);
 | |
|     assert_eq!(10, cell.replace(20));
 | |
|     assert_eq!(20, cell.get());
 | |
| 
 | |
|     let cell = Cell::new("Hello".to_owned());
 | |
|     assert_eq!("Hello".to_owned(), cell.replace("World".to_owned()));
 | |
|     assert_eq!("World".to_owned(), cell.into_inner());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn cell_into_inner() {
 | |
|     let cell = Cell::new(10);
 | |
|     assert_eq!(10, cell.into_inner());
 | |
| 
 | |
|     let cell = Cell::new("Hello world".to_owned());
 | |
|     assert_eq!("Hello world".to_owned(), cell.into_inner());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn cell_exterior() {
 | |
|     #[derive(Copy, Clone)]
 | |
|     #[allow(dead_code)]
 | |
|     struct Point {
 | |
|         x: isize,
 | |
|         y: isize,
 | |
|         z: isize,
 | |
|     }
 | |
| 
 | |
|     fn f(p: &Cell<Point>) {
 | |
|         assert_eq!(p.get().z, 12);
 | |
|         p.set(Point { x: 10, y: 11, z: 13 });
 | |
|         assert_eq!(p.get().z, 13);
 | |
|     }
 | |
| 
 | |
|     let a = Point { x: 10, y: 11, z: 12 };
 | |
|     let b = &Cell::new(a);
 | |
|     assert_eq!(b.get().z, 12);
 | |
|     f(b);
 | |
|     assert_eq!(a.z, 12);
 | |
|     assert_eq!(b.get().z, 13);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn cell_does_not_clone() {
 | |
|     #[derive(Copy)]
 | |
|     #[allow(dead_code)]
 | |
|     struct Foo {
 | |
|         x: isize,
 | |
|     }
 | |
| 
 | |
|     impl Clone for Foo {
 | |
|         fn clone(&self) -> Foo {
 | |
|             // Using Cell in any way should never cause clone() to be
 | |
|             // invoked -- after all, that would permit evil user code to
 | |
|             // abuse `Cell` and trigger crashes.
 | |
| 
 | |
|             panic!();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     let x = Cell::new(Foo { x: 22 });
 | |
|     let _y = x.get();
 | |
|     let _z = x.clone();
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn refcell_default() {
 | |
|     let cell: RefCell<u64> = Default::default();
 | |
|     assert_eq!(0, *cell.borrow());
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn unsafe_cell_unsized() {
 | |
|     let cell: &UnsafeCell<[i32]> = &UnsafeCell::new([1, 2, 3]);
 | |
|     {
 | |
|         let val: &mut [i32] = unsafe { &mut *cell.get() };
 | |
|         val[0] = 4;
 | |
|         val[2] = 5;
 | |
|     }
 | |
|     let comp: &mut [i32] = &mut [4, 2, 5];
 | |
|     assert_eq!(unsafe { &mut *cell.get() }, comp);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn refcell_unsized() {
 | |
|     let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]);
 | |
|     {
 | |
|         let b = &mut *cell.borrow_mut();
 | |
|         b[0] = 4;
 | |
|         b[2] = 5;
 | |
|     }
 | |
|     let comp: &mut [i32] = &mut [4, 2, 5];
 | |
|     assert_eq!(&*cell.borrow(), comp);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn refcell_ref_coercion() {
 | |
|     let cell: RefCell<[i32; 3]> = RefCell::new([1, 2, 3]);
 | |
|     {
 | |
|         let mut cellref: RefMut<'_, [i32; 3]> = cell.borrow_mut();
 | |
|         cellref[0] = 4;
 | |
|         let mut coerced: RefMut<'_, [i32]> = cellref;
 | |
|         coerced[2] = 5;
 | |
|     }
 | |
|     {
 | |
|         let comp: &mut [i32] = &mut [4, 2, 5];
 | |
|         let cellref: Ref<'_, [i32; 3]> = cell.borrow();
 | |
|         assert_eq!(&*cellref, comp);
 | |
|         let coerced: Ref<'_, [i32]> = cellref;
 | |
|         assert_eq!(&*coerced, comp);
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| #[should_panic]
 | |
| fn refcell_swap_borrows() {
 | |
|     let x = RefCell::new(0);
 | |
|     let _b = x.borrow();
 | |
|     let y = RefCell::new(1);
 | |
|     x.swap(&y);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| #[should_panic]
 | |
| fn refcell_replace_borrows() {
 | |
|     let x = RefCell::new(0);
 | |
|     let _b = x.borrow();
 | |
|     x.replace(1);
 | |
| }
 | |
| 
 | |
| #[test]
 | |
| fn refcell_format() {
 | |
|     let name = RefCell::new("rust");
 | |
|     let what = RefCell::new("rocks");
 | |
|     let msg = format!("{name} {}", &*what.borrow(), name = &*name.borrow());
 | |
|     assert_eq!(msg, "rust rocks".to_string());
 | |
| }
 | |
| 
 | |
| #[allow(dead_code)]
 | |
| fn const_cells() {
 | |
|     const UNSAFE_CELL: UnsafeCell<i32> = UnsafeCell::new(3);
 | |
|     const _: i32 = UNSAFE_CELL.into_inner();
 | |
| 
 | |
|     const REF_CELL: RefCell<i32> = RefCell::new(3);
 | |
|     const _: i32 = REF_CELL.into_inner();
 | |
| 
 | |
|     const CELL: Cell<i32> = Cell::new(3);
 | |
|     const _: i32 = CELL.into_inner();
 | |
| 
 | |
|     const UNSAFE_CELL_FROM: UnsafeCell<i32> = UnsafeCell::from(3);
 | |
|     const _: i32 = UNSAFE_CELL.into_inner();
 | |
| 
 | |
|     const REF_CELL_FROM: RefCell<i32> = RefCell::from(3);
 | |
|     const _: i32 = REF_CELL.into_inner();
 | |
| 
 | |
|     const CELL_FROM: Cell<i32> = Cell::from(3);
 | |
|     const _: i32 = CELL.into_inner();
 | |
| }
 |