#![allow(clippy::undocumented_unsafe_blocks)]
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
use std::path::PathBuf;
#[cfg(feature = "rayon")]
use rayon::iter::Either;
use crate::sync::Arc;
pub mod helper {
use std::marker::PhantomData;
use super::{Update, update_fallback};
pub struct Dispatch<D>(PhantomData<D>);
#[allow(clippy::new_without_default)]
impl<D> Dispatch<D> {
pub fn new() -> Self {
Dispatch(PhantomData)
}
}
impl<D> Dispatch<D>
where
D: Update,
{
pub unsafe fn maybe_update(old_pointer: *mut D, new_value: D) -> bool {
unsafe { D::maybe_update(old_pointer, new_value) }
}
}
pub unsafe trait Fallback<T> {
unsafe fn maybe_update(old_pointer: *mut T, new_value: T) -> bool;
}
unsafe impl<T: 'static + PartialEq> Fallback<T> for Dispatch<T> {
unsafe fn maybe_update(old_pointer: *mut T, new_value: T) -> bool {
unsafe { update_fallback(old_pointer, new_value) }
}
}
}
pub unsafe fn update_fallback<T>(old_pointer: *mut T, new_value: T) -> bool
where
T: 'static + PartialEq,
{
let old_ref: &mut T = unsafe { &mut *old_pointer };
if *old_ref != new_value {
*old_ref = new_value;
true
} else {
false
}
}
pub unsafe fn always_update<T>(old_pointer: *mut T, new_value: T) -> bool {
unsafe { *old_pointer = new_value };
true
}
pub unsafe trait Update {
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool;
}
unsafe impl Update for std::convert::Infallible {
unsafe fn maybe_update(_old_pointer: *mut Self, new_value: Self) -> bool {
match new_value {}
}
}
macro_rules! maybe_update_vec {
($old_pointer: expr, $new_vec: expr, $elem_ty: ty) => {{
let old_pointer = $old_pointer;
let new_vec = $new_vec;
let old_vec: &mut Self = unsafe { &mut *old_pointer };
if old_vec.len() != new_vec.len() {
old_vec.clear();
old_vec.extend(new_vec);
return true;
}
let mut changed = false;
for (old_element, new_element) in old_vec.iter_mut().zip(new_vec) {
changed |= unsafe { <$elem_ty>::maybe_update(old_element, new_element) };
}
changed
}};
}
unsafe impl<T> Update for Vec<T>
where
T: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_vec: Self) -> bool {
maybe_update_vec!(old_pointer, new_vec, T)
}
}
unsafe impl<T> Update for thin_vec::ThinVec<T>
where
T: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_vec: Self) -> bool {
maybe_update_vec!(old_pointer, new_vec, T)
}
}
unsafe impl<A> Update for smallvec::SmallVec<A>
where
A: smallvec::Array,
A::Item: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_vec: Self) -> bool {
maybe_update_vec!(old_pointer, new_vec, A::Item)
}
}
macro_rules! maybe_update_set {
($old_pointer: expr, $new_set: expr) => {{
let old_pointer = $old_pointer;
let new_set = $new_set;
let old_set: &mut Self = unsafe { &mut *old_pointer };
if *old_set == new_set {
false
} else {
old_set.clear();
old_set.extend(new_set);
return true;
}
}};
}
unsafe impl<K, S> Update for HashSet<K, S>
where
K: Update + Eq + Hash,
S: BuildHasher,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_set: Self) -> bool {
maybe_update_set!(old_pointer, new_set)
}
}
unsafe impl<K> Update for BTreeSet<K>
where
K: Update + Eq + Ord,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_set: Self) -> bool {
maybe_update_set!(old_pointer, new_set)
}
}
macro_rules! maybe_update_map {
($old_pointer: expr, $new_map: expr) => {
'function: {
let old_pointer = $old_pointer;
let new_map = $new_map;
let old_map: &mut Self = unsafe { &mut *old_pointer };
let same_keys =
old_map.len() == new_map.len() && old_map.keys().all(|k| new_map.contains_key(k));
if !same_keys {
old_map.clear();
old_map.extend(new_map);
break 'function true;
}
let mut changed = false;
for (key, new_value) in new_map.into_iter() {
let old_value = old_map.get_mut(&key).unwrap();
changed |= unsafe { V::maybe_update(old_value, new_value) };
}
changed
}
};
}
unsafe impl<K, V, S> Update for HashMap<K, V, S>
where
K: Update + Eq + Hash,
V: Update,
S: BuildHasher,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_map: Self) -> bool {
maybe_update_map!(old_pointer, new_map)
}
}
unsafe impl<K, V, S> Update for hashbrown::HashMap<K, V, S>
where
K: Update + Eq + Hash,
V: Update,
S: BuildHasher,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_map: Self) -> bool {
maybe_update_map!(old_pointer, new_map)
}
}
unsafe impl<K, S> Update for hashbrown::HashSet<K, S>
where
K: Update + Eq + Hash,
S: BuildHasher,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_set: Self) -> bool {
maybe_update_set!(old_pointer, new_set)
}
}
unsafe impl<K, V, S> Update for indexmap::IndexMap<K, V, S>
where
K: Update + Eq + Hash,
V: Update,
S: BuildHasher,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_map: Self) -> bool {
maybe_update_map!(old_pointer, new_map)
}
}
unsafe impl<K, S> Update for indexmap::IndexSet<K, S>
where
K: Update + Eq + Hash,
S: BuildHasher,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_set: Self) -> bool {
maybe_update_set!(old_pointer, new_set)
}
}
#[cfg(feature = "ordermap")]
unsafe impl<K, V, S> Update for ordermap::OrderMap<K, V, S>
where
K: Update + Eq + Hash,
V: Update,
S: BuildHasher,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_map: Self) -> bool {
maybe_update_map!(old_pointer, new_map)
}
}
#[cfg(feature = "ordermap")]
unsafe impl<K, S> Update for ordermap::OrderSet<K, S>
where
K: Update + Eq + Hash,
S: BuildHasher,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_set: Self) -> bool {
maybe_update_set!(old_pointer, new_set)
}
}
unsafe impl<K, V> Update for BTreeMap<K, V>
where
K: Update + Eq + Ord,
V: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_map: Self) -> bool {
maybe_update_map!(old_pointer, new_map)
}
}
unsafe impl<T> Update for Box<T>
where
T: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_box: Self) -> bool {
let old_box: &mut Box<T> = unsafe { &mut *old_pointer };
unsafe { T::maybe_update(&mut **old_box, *new_box) }
}
}
unsafe impl<T> Update for Box<[T]>
where
T: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_box: Self) -> bool {
let old_box: &mut Box<[T]> = unsafe { &mut *old_pointer };
if old_box.len() == new_box.len() {
let mut changed = false;
for (old_element, new_element) in old_box.iter_mut().zip(new_box) {
changed |= unsafe { T::maybe_update(old_element, new_element) };
}
changed
} else {
*old_box = new_box;
true
}
}
}
unsafe impl<T> Update for Arc<T>
where
T: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_arc: Self) -> bool {
let old_arc: &mut Arc<T> = unsafe { &mut *old_pointer };
if Arc::ptr_eq(old_arc, &new_arc) {
return false;
}
if let Some(inner) = Arc::get_mut(old_arc) {
match Arc::try_unwrap(new_arc) {
Ok(new_inner) => unsafe { T::maybe_update(inner, new_inner) },
Err(new_arc) => {
*old_arc = new_arc;
true
}
}
} else {
unsafe { *old_pointer = new_arc };
true
}
}
}
unsafe impl<T, const N: usize> Update for [T; N]
where
T: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_vec: Self) -> bool {
let old_pointer: *mut T = unsafe { std::ptr::addr_of_mut!((*old_pointer)[0]) };
let mut changed = false;
for (new_element, i) in new_vec.into_iter().zip(0..) {
changed |= unsafe { T::maybe_update(old_pointer.add(i), new_element) };
}
changed
}
}
unsafe impl<T, E> Update for Result<T, E>
where
T: Update,
E: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
let old_value = unsafe { &mut *old_pointer };
match (old_value, new_value) {
(Ok(old), Ok(new)) => unsafe { T::maybe_update(old, new) },
(Err(old), Err(new)) => unsafe { E::maybe_update(old, new) },
(old_value, new_value) => {
*old_value = new_value;
true
}
}
}
}
#[cfg(feature = "rayon")]
unsafe impl<L, R> Update for Either<L, R>
where
L: Update,
R: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
let old_value = unsafe { &mut *old_pointer };
match (old_value, new_value) {
(Either::Left(old), Either::Left(new)) => unsafe { L::maybe_update(old, new) },
(Either::Right(old), Either::Right(new)) => unsafe { R::maybe_update(old, new) },
(old_value, new_value) => {
*old_value = new_value;
true
}
}
}
}
macro_rules! fallback_impl {
($($t:ty,)*) => {
$(
unsafe impl Update for $t {
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
unsafe { update_fallback(old_pointer, new_value) }
}
}
)*
}
}
fallback_impl! {
String,
i64,
u64,
i32,
u32,
i16,
u16,
i8,
u8,
bool,
f32,
f64,
usize,
isize,
PathBuf,
}
#[cfg(feature = "compact_str")]
fallback_impl! { compact_str::CompactString, }
macro_rules! tuple_impl {
($($t:ident),*; $($u:ident),*) => {
unsafe impl<$($t),*> Update for ($($t,)*)
where
$($t: Update,)*
{
#[allow(non_snake_case)]
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
let ($($t,)*) = new_value;
let ($($u,)*) = unsafe { &mut *old_pointer };
#[allow(unused_mut)]
let mut changed = false;
$(
unsafe { changed |= Update::maybe_update($u, $t); }
)*
changed
}
}
}
}
tuple_impl!(;);
tuple_impl!(A; a);
tuple_impl!(A, B; a, b);
tuple_impl!(A, B, C; a, b, c);
tuple_impl!(A, B, C, D; a, b, c, d);
tuple_impl!(A, B, C, D, E; a, b, c, d, e);
tuple_impl!(A, B, C, D, E, F; a, b, c, d, e, f);
tuple_impl!(A, B, C, D, E, F, G; a, b, c, d, e, f, g);
tuple_impl!(A, B, C, D, E, F, G, H; a, b, c, d, e, f, g, h);
tuple_impl!(A, B, C, D, E, F, G, H, I; a, b, c, d, e, f, g, h, i);
tuple_impl!(A, B, C, D, E, F, G, H, I, J; a, b, c, d, e, f, g, h, i, j);
tuple_impl!(A, B, C, D, E, F, G, H, I, J, K; a, b, c, d, e, f, g, h, i, j, k);
tuple_impl!(A, B, C, D, E, F, G, H, I, J, K, L; a, b, c, d, e, f, g, h, i, j, k, l);
unsafe impl<T> Update for Option<T>
where
T: Update,
{
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
let old_value = unsafe { &mut *old_pointer };
match (old_value, new_value) {
(Some(old), Some(new)) => unsafe { T::maybe_update(old, new) },
(None, None) => false,
(old_value, new_value) => {
*old_value = new_value;
true
}
}
}
}
unsafe impl<T> Update for PhantomData<T> {
unsafe fn maybe_update(_old_pointer: *mut Self, _new_value: Self) -> bool {
false
}
}