|
63 | 63 | //! - You don't need to do anything special in `Drop`. |
64 | 64 |
|
65 | 65 | use parking_lot::{Mutex, RwLock}; |
66 | | -use std::fmt::Debug; |
| 66 | +use std::fmt::{self, Debug, Display}; |
67 | 67 | use std::marker::PhantomData; |
68 | 68 | use std::mem; |
69 | 69 | use std::sync::Arc; |
@@ -145,6 +145,20 @@ pub trait MapMut: UserData { |
145 | 145 | F: FnOnce(&mut Self::Target) -> U; |
146 | 146 | } |
147 | 147 |
|
| 148 | +/// Trait for wrappers that can be mapped once. |
| 149 | +pub trait MapOwned: UserData { |
| 150 | + type Err: Debug; |
| 151 | + |
| 152 | + /// Maps a `T` to `U`. Called for methods that take `self`. This method may fail with |
| 153 | + /// an error if it is called more than once on the same object. |
| 154 | + /// |
| 155 | + /// Implementations of this method must not panic. Failures should be indicated by |
| 156 | + /// returning `Err`. |
| 157 | + fn map_owned<F, U>(&self, op: F) -> Result<U, Self::Err> |
| 158 | + where |
| 159 | + F: FnOnce(Self::Target) -> U; |
| 160 | +} |
| 161 | + |
148 | 162 | /// The default user data wrapper used by derive macro, when no `user_data` attribute is present. |
149 | 163 | /// This may change in the future. |
150 | 164 | pub type DefaultUserData<T> = LocalCellData<T>; |
@@ -732,3 +746,76 @@ where |
732 | 746 | Ok(op(&Default::default())) |
733 | 747 | } |
734 | 748 | } |
| 749 | + |
| 750 | +/// Special user-data wrapper intended for objects that can only be used once. Only |
| 751 | +/// implements `MapOwned`. |
| 752 | +pub struct Once<T>(Arc<atomic_take::AtomicTake<T>>); |
| 753 | + |
| 754 | +impl<T> Clone for Once<T> { |
| 755 | + #[inline] |
| 756 | + fn clone(&self) -> Self { |
| 757 | + Once(Arc::clone(&self.0)) |
| 758 | + } |
| 759 | +} |
| 760 | + |
| 761 | +unsafe impl<T> UserData for Once<T> |
| 762 | +where |
| 763 | + T: NativeClass + Send, |
| 764 | +{ |
| 765 | + type Target = T; |
| 766 | + |
| 767 | + #[inline] |
| 768 | + fn new(val: Self::Target) -> Self { |
| 769 | + Once(Arc::new(atomic_take::AtomicTake::new(val))) |
| 770 | + } |
| 771 | + |
| 772 | + #[inline] |
| 773 | + fn into_user_data(self) -> *const libc::c_void { |
| 774 | + Arc::into_raw(self.0) as *const _ |
| 775 | + } |
| 776 | + |
| 777 | + #[inline] |
| 778 | + unsafe fn consume_user_data_unchecked(ptr: *const libc::c_void) -> Self { |
| 779 | + Once(Arc::from_raw(ptr as *const _)) |
| 780 | + } |
| 781 | + |
| 782 | + #[inline] |
| 783 | + unsafe fn clone_from_user_data_unchecked(ptr: *const libc::c_void) -> Self { |
| 784 | + let borrowed = Arc::from_raw(ptr as *const _); |
| 785 | + let arc = Arc::clone(&borrowed); |
| 786 | + mem::forget(borrowed); |
| 787 | + Once(arc) |
| 788 | + } |
| 789 | +} |
| 790 | + |
| 791 | +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] |
| 792 | +pub struct ValueTaken; |
| 793 | + |
| 794 | +impl std::error::Error for ValueTaken {} |
| 795 | +impl Display for ValueTaken { |
| 796 | + #[inline] |
| 797 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 798 | + write!(f, "this object has already been used once") |
| 799 | + } |
| 800 | +} |
| 801 | + |
| 802 | +impl<T> MapOwned for Once<T> |
| 803 | +where |
| 804 | + T: NativeClass + Send, |
| 805 | +{ |
| 806 | + type Err = ValueTaken; |
| 807 | + |
| 808 | + /// Maps a `T` to `U`. Called for methods that take `self`. This method may fail with |
| 809 | + /// an error if it is called more than once on the same object. |
| 810 | + /// |
| 811 | + /// Implementations of this method must not panic. Failures should be indicated by |
| 812 | + /// returning `Err`. |
| 813 | + #[inline] |
| 814 | + fn map_owned<F, U>(&self, op: F) -> Result<U, Self::Err> |
| 815 | + where |
| 816 | + F: FnOnce(Self::Target) -> U, |
| 817 | + { |
| 818 | + let v = self.0.take().ok_or(ValueTaken)?; |
| 819 | + Ok(op(v)) |
| 820 | + } |
| 821 | +} |
0 commit comments