// Take a look at the license at the top of the repository in the LICENSE file. use std::cell::Cell; use std::cell::RefCell; use std::marker::PhantomData; use std::rc::Rc; use std::sync::atomic::Ordering; use std::sync::Arc; use std::sync::Mutex; use std::sync::RwLock; use crate::HasParamSpec; use crate::IsA; use crate::Object; use crate::SendWeakRef; use crate::WeakRef; // rustdoc-stripper-ignore-next /// A type that can be used as a property. It covers every type which have an associated `ParamSpec` /// (`HasParamSpec`) and some useful types wrapping `HasParamSpec`. /// The definition is recursive, so you can nest many `Property`s together. The final `ParamSpec` will /// be the one of the innermost type pub trait Property { type Value: HasParamSpec; } impl Property for T { type Value = T; } impl Property for PhantomData { type Value = T::Value; } impl Property for RefCell { type Value = T::Value; } impl Property for Cell { type Value = T::Value; } impl Property for Mutex { type Value = T::Value; } impl Property for RwLock { type Value = T::Value; } impl Property for once_cell::sync::OnceCell { type Value = T::Value; } impl Property for once_cell::unsync::OnceCell { type Value = T::Value; } impl Property for std::cell::OnceCell { type Value = T::Value; } impl Property for std::sync::OnceLock { type Value = T::Value; } // Handle smart pointers trasparently impl Property for Rc { type Value = T::Value; } impl Property for Arc { type Value = T::Value; } impl + HasParamSpec> Property for WeakRef { type Value = Option; } impl + HasParamSpec> Property for SendWeakRef { type Value = Option; } // rustdoc-stripper-ignore-next /// A container type implementing this trait can be read by the default getter generated by the `Props` macro. pub trait PropertyGet { type Value; fn get R>(&self, f: F) -> R; } // rustdoc-stripper-ignore-next /// A container type implementing this trait can be written by the default setter generated by the `Props` macro. /// It takes a `FnOnce(&mut Self::Value)` so that the caller may access nested fields of a struct /// by doing `${Self::Value}.member` pub trait PropertySetNested { type SetNestedValue; fn set_nested(&self, f: F); } // rustdoc-stripper-ignore-next /// A container type implementing this trait can be written by the default setter generated by the `Props` macro. pub trait PropertySet { type SetValue; fn set(&self, v: Self::SetValue); } impl PropertySet for T { type SetValue = T::SetNestedValue; fn set(&self, v: Self::SetValue) { self.set_nested(|x| *x = v); } } impl PropertyGet for T { type Value = T; fn get R>(&self, f: F) -> R { f(self) } } impl PropertyGet for Cell { type Value = T; fn get R>(&self, f: F) -> R { f(&Cell::get(self)) } } impl PropertySet for Cell { type SetValue = T; fn set(&self, v: Self::SetValue) { self.set(v); } } impl PropertyGet for RefCell { type Value = T; fn get R>(&self, f: F) -> R { f(&self.borrow()) } } impl PropertySetNested for RefCell { type SetNestedValue = T; fn set_nested(&self, f: F) { f(&mut self.borrow_mut()); } } impl PropertyGet for Mutex { type Value = T; fn get R>(&self, f: F) -> R { f(&self.lock().unwrap()) } } impl PropertySetNested for Mutex { type SetNestedValue = T; fn set_nested(&self, f: F) { f(&mut self.lock().unwrap()); } } impl PropertyGet for RwLock { type Value = T; fn get R>(&self, f: F) -> R { f(&self.read().unwrap()) } } impl PropertySetNested for RwLock { type SetNestedValue = T; fn set_nested(&self, f: F) { f(&mut self.write().unwrap()); } } impl PropertyGet for once_cell::sync::OnceCell { type Value = T; fn get R>(&self, f: F) -> R { f(self.get().unwrap()) } } impl PropertyGet for once_cell::unsync::OnceCell { type Value = T; fn get R>(&self, f: F) -> R { f(self.get().unwrap()) } } impl PropertySet for once_cell::sync::OnceCell { type SetValue = T; fn set(&self, v: Self::SetValue) { // I can't use `unwrap` because I would have to add a `Debug` bound to _v if let Err(_v) = self.set(v) { panic!("can't set value of OnceCell multiple times") }; } } impl PropertySet for once_cell::unsync::OnceCell { type SetValue = T; fn set(&self, v: Self::SetValue) { // I can't use `unwrap` because I would have to add a `Debug` bound to _v if let Err(_v) = self.set(v) { panic!("can't set value of OnceCell multiple times") }; } } impl PropertyGet for std::cell::OnceCell { type Value = T; fn get R>(&self, f: F) -> R { f(self.get().unwrap()) } } impl PropertyGet for std::sync::OnceLock { type Value = T; fn get R>(&self, f: F) -> R { f(self.get().unwrap()) } } impl PropertySet for std::cell::OnceCell { type SetValue = T; fn set(&self, v: Self::SetValue) { // I can't use `unwrap` because I would have to add a `Debug` bound to _v if let Err(_v) = self.set(v) { panic!("can't set value of OnceCell multiple times") }; } } impl PropertySet for std::sync::OnceLock { type SetValue = T; fn set(&self, v: Self::SetValue) { // I can't use `unwrap` because I would have to add a `Debug` bound to _v if let Err(_v) = self.set(v) { panic!("can't set value of OnceCell multiple times") }; } } impl> PropertyGet for WeakRef { type Value = Option; fn get R>(&self, f: F) -> R { f(&self.upgrade()) } } impl> PropertySet for WeakRef { type SetValue = Option; fn set(&self, v: Self::SetValue) { self.set(v.as_ref()) } } impl> PropertyGet for SendWeakRef { type Value = Option; fn get R>(&self, f: F) -> R { f(&self.upgrade()) } } impl> PropertySet for SendWeakRef { type SetValue = Option; fn set(&self, v: Self::SetValue) { WeakRef::set(self, v.as_ref()); } } // Smart pointers wrapping a `PropertyRead`/`PropertyWrite` impl PropertyGet for Rc { type Value = T::Value; fn get R>(&self, f: F) -> R { (**self).get(f) } } impl PropertySetNested for Rc { type SetNestedValue = T::SetNestedValue; fn set_nested(&self, f: F) { (**self).set_nested(f) } } impl PropertyGet for Arc { type Value = T::Value; fn get R>(&self, f: F) -> R { (**self).get(f) } } impl PropertySetNested for Arc { type SetNestedValue = T::SetNestedValue; fn set_nested(&self, f: F) { (**self).set_nested(f) } } macro_rules! impl_atomic { ($atomic:ty, $valuety:ty) => { impl Property for $atomic { type Value = $valuety; } impl PropertyGet for $atomic { type Value = $valuety; fn get R>(&self, f: F) -> R { f(&self.load(Ordering::Acquire)) } } impl PropertySet for $atomic { type SetValue = $valuety; fn set(&self, v: Self::SetValue) { self.store(v, Ordering::Release); } } }; } impl_atomic!(std::sync::atomic::AtomicBool, bool); impl_atomic!(std::sync::atomic::AtomicI8, i8); impl_atomic!(std::sync::atomic::AtomicI32, i32); #[cfg(target_has_atomic = "64")] impl_atomic!(std::sync::atomic::AtomicI64, i64); impl_atomic!(std::sync::atomic::AtomicU8, u8); impl_atomic!(std::sync::atomic::AtomicU32, u32); #[cfg(target_has_atomic = "64")] impl_atomic!(std::sync::atomic::AtomicU64, u64);