From e08497dc8f26d52b956621153c03d0d22196ea88 Mon Sep 17 00:00:00 2001 From: Chris Juchem Date: Thu, 29 Aug 2024 20:43:07 -0400 Subject: [PATCH] Replace `bevy_utils::CowArc` with `atomicow` (#14977) # Objective - Fixes https://github.com/bevyengine/bevy/issues/14975 ## Solution - Replace usages of `bevy_utils::CowArc` with `atomicow::CowArc` - Remove bevy_utils::CowArc ## Testing - `bevy_asset` test suite continues to pass. --- ## Migration Guide `bevy_utils::CowArc` has moved to a new crate called [atomicow](https://crates.io/crates/atomicow). --- crates/bevy_asset/Cargo.toml | 1 + crates/bevy_asset/src/io/source.rs | 3 +- crates/bevy_asset/src/loader.rs | 3 +- crates/bevy_asset/src/path.rs | 2 +- crates/bevy_asset/src/saver.rs | 3 +- crates/bevy_asset/src/server/mod.rs | 3 +- crates/bevy_asset/src/transformer.rs | 3 +- crates/bevy_utils/src/cow_arc.rs | 191 --------------------------- crates/bevy_utils/src/lib.rs | 2 - 9 files changed, 12 insertions(+), 199 deletions(-) delete mode 100644 crates/bevy_utils/src/cow_arc.rs diff --git a/crates/bevy_asset/Cargo.toml b/crates/bevy_asset/Cargo.toml index 0b95ab505b..b2348d6509 100644 --- a/crates/bevy_asset/Cargo.toml +++ b/crates/bevy_asset/Cargo.toml @@ -29,6 +29,7 @@ bevy_tasks = { path = "../bevy_tasks", version = "0.15.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" } stackfuture = "0.3" +atomicow = "1.0" async-broadcast = "0.5" async-fs = "2.0" async-lock = "3.0" diff --git a/crates/bevy_asset/src/io/source.rs b/crates/bevy_asset/src/io/source.rs index a979a33277..ec1947a3fe 100644 --- a/crates/bevy_asset/src/io/source.rs +++ b/crates/bevy_asset/src/io/source.rs @@ -2,9 +2,10 @@ use crate::{ io::{processor_gated::ProcessorGatedReader, AssetSourceEvent, AssetWatcher}, processor::AssetProcessorData, }; +use atomicow::CowArc; use bevy_ecs::system::Resource; use bevy_utils::tracing::{error, warn}; -use bevy_utils::{CowArc, Duration, HashMap}; +use bevy_utils::{Duration, HashMap}; use std::{fmt::Display, hash::Hash, sync::Arc}; use thiserror::Error; diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs index 1b444bba8c..f0dce3593d 100644 --- a/crates/bevy_asset/src/loader.rs +++ b/crates/bevy_asset/src/loader.rs @@ -6,8 +6,9 @@ use crate::{ Asset, AssetLoadError, AssetServer, AssetServerMode, Assets, Handle, UntypedAssetId, UntypedHandle, }; +use atomicow::CowArc; use bevy_ecs::world::World; -use bevy_utils::{BoxedFuture, ConditionalSendFuture, CowArc, HashMap, HashSet}; +use bevy_utils::{BoxedFuture, ConditionalSendFuture, HashMap, HashSet}; use downcast_rs::{impl_downcast, Downcast}; use ron::error::SpannedError; use serde::{Deserialize, Serialize}; diff --git a/crates/bevy_asset/src/path.rs b/crates/bevy_asset/src/path.rs index dc7719a25f..67c7c65286 100644 --- a/crates/bevy_asset/src/path.rs +++ b/crates/bevy_asset/src/path.rs @@ -1,6 +1,6 @@ use crate::io::AssetSourceId; +use atomicow::CowArc; use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; -use bevy_utils::CowArc; use serde::{de::Visitor, Deserialize, Serialize}; use std::{ fmt::{Debug, Display}, diff --git a/crates/bevy_asset/src/saver.rs b/crates/bevy_asset/src/saver.rs index 36408dd125..4d5925dc54 100644 --- a/crates/bevy_asset/src/saver.rs +++ b/crates/bevy_asset/src/saver.rs @@ -1,7 +1,8 @@ use crate::transformer::TransformedAsset; use crate::{io::Writer, meta::Settings, Asset, ErasedLoadedAsset}; use crate::{AssetLoader, Handle, LabeledAsset, UntypedHandle}; -use bevy_utils::{BoxedFuture, ConditionalSendFuture, CowArc, HashMap}; +use atomicow::CowArc; +use bevy_utils::{BoxedFuture, ConditionalSendFuture, HashMap}; use serde::{Deserialize, Serialize}; use std::{borrow::Borrow, hash::Hash, ops::Deref}; diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs index ef72d2b404..61c802e505 100644 --- a/crates/bevy_asset/src/server/mod.rs +++ b/crates/bevy_asset/src/server/mod.rs @@ -17,10 +17,11 @@ use crate::{ DeserializeMetaError, ErasedLoadedAsset, Handle, LoadedUntypedAsset, UntypedAssetId, UntypedAssetLoadFailedEvent, UntypedHandle, }; +use atomicow::CowArc; use bevy_ecs::prelude::*; use bevy_tasks::IoTaskPool; use bevy_utils::tracing::{error, info}; -use bevy_utils::{CowArc, HashSet}; +use bevy_utils::HashSet; use crossbeam_channel::{Receiver, Sender}; use futures_lite::{FutureExt, StreamExt}; use info::*; diff --git a/crates/bevy_asset/src/transformer.rs b/crates/bevy_asset/src/transformer.rs index 0ffddc4658..1b2cd92991 100644 --- a/crates/bevy_asset/src/transformer.rs +++ b/crates/bevy_asset/src/transformer.rs @@ -1,5 +1,6 @@ use crate::{meta::Settings, Asset, ErasedLoadedAsset, Handle, LabeledAsset, UntypedHandle}; -use bevy_utils::{ConditionalSendFuture, CowArc, HashMap}; +use atomicow::CowArc; +use bevy_utils::{ConditionalSendFuture, HashMap}; use serde::{Deserialize, Serialize}; use std::{ borrow::Borrow, diff --git a/crates/bevy_utils/src/cow_arc.rs b/crates/bevy_utils/src/cow_arc.rs deleted file mode 100644 index 635d31a583..0000000000 --- a/crates/bevy_utils/src/cow_arc.rs +++ /dev/null @@ -1,191 +0,0 @@ -use std::{ - borrow::Borrow, - fmt::{Debug, Display}, - hash::Hash, - ops::Deref, - path::{Path, PathBuf}, - sync::Arc, -}; - -/// Much like a [`Cow`](std::borrow::Cow), but owned values are Arc-ed to make clones cheap. This should be used for values that -/// are cloned for use across threads and change rarely (if ever). -/// -/// This also makes an opinionated tradeoff by adding a [`CowArc::Static`] and implementing [`From<&'static T>`] instead of -/// [`From<'a T>`]. This preserves the static context and prevents conversion to [`CowArc::Owned`] in cases where a reference -/// is known to be static. This is an optimization that prevents allocations and atomic ref-counting. -/// -/// This means that static references should prefer [`From::from`] or [`CowArc::Static`] and non-static references must -/// use [`CowArc::Borrowed`]. -pub enum CowArc<'a, T: ?Sized + 'static> { - /// A borrowed value - Borrowed(&'a T), - /// A static value reference. This exists to avoid conversion to [`CowArc::Owned`] in cases where a reference is - /// known to be static. This is an optimization that prevents allocations and atomic ref-counting. - Static(&'static T), - /// An owned [`Arc`]-ed value - Owned(Arc), -} - -impl CowArc<'static, T> { - /// Indicates this [`CowArc`] should have a static lifetime. - /// This ensures if this was created with a value `Borrowed(&'static T)`, it is replaced with `Static(&'static T)`. - #[inline] - pub fn as_static(self) -> Self { - match self { - Self::Borrowed(value) | Self::Static(value) => Self::Static(value), - Self::Owned(value) => Self::Owned(value), - } - } -} - -impl<'a, T: ?Sized> Deref for CowArc<'a, T> { - type Target = T; - - #[inline] - fn deref(&self) -> &Self::Target { - match self { - CowArc::Borrowed(v) | CowArc::Static(v) => v, - CowArc::Owned(v) => v, - } - } -} - -impl<'a, T: ?Sized> Borrow for CowArc<'a, T> { - #[inline] - fn borrow(&self) -> &T { - self - } -} - -impl<'a, T: ?Sized> AsRef for CowArc<'a, T> { - #[inline] - fn as_ref(&self) -> &T { - self - } -} - -impl<'a, T: ?Sized> CowArc<'a, T> -where - &'a T: Into>, -{ - /// Converts this into an "owned" value. If internally a value is borrowed, it will be cloned into an "owned [`Arc`]". - /// If it is already a [`CowArc::Owned`] or a [`CowArc::Static`], it will remain unchanged. - #[inline] - pub fn into_owned(self) -> CowArc<'static, T> { - match self { - CowArc::Borrowed(value) => CowArc::Owned(value.into()), - CowArc::Static(value) => CowArc::Static(value), - CowArc::Owned(value) => CowArc::Owned(value), - } - } - - /// Clones into an owned [`CowArc<'static>`]. If internally a value is borrowed, it will be cloned into an "owned [`Arc`]". - /// If it is already a [`CowArc::Owned`] or [`CowArc::Static`], the value will be cloned. - /// This is equivalent to `.clone().into_owned()`. - #[inline] - pub fn clone_owned(&self) -> CowArc<'static, T> { - self.clone().into_owned() - } -} - -impl<'a, T: ?Sized> Clone for CowArc<'a, T> { - #[inline] - fn clone(&self) -> Self { - match self { - Self::Borrowed(value) => Self::Borrowed(value), - Self::Static(value) => Self::Static(value), - Self::Owned(value) => Self::Owned(value.clone()), - } - } -} - -impl<'a, T: PartialEq + ?Sized> PartialEq for CowArc<'a, T> { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.deref().eq(other.deref()) - } -} - -impl<'a, T: PartialEq + ?Sized> Eq for CowArc<'a, T> {} - -impl<'a, T: Hash + ?Sized> Hash for CowArc<'a, T> { - #[inline] - fn hash(&self, state: &mut H) { - self.deref().hash(state); - } -} - -impl<'a, T: Debug + ?Sized> Debug for CowArc<'a, T> { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Debug::fmt(self.deref(), f) - } -} - -impl<'a, T: Display + ?Sized> Display for CowArc<'a, T> { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Display::fmt(self.deref(), f) - } -} - -impl<'a, T: PartialOrd + ?Sized> PartialOrd for CowArc<'a, T> { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - self.deref().partial_cmp(other.deref()) - } -} - -impl Default for CowArc<'static, str> { - fn default() -> Self { - CowArc::Static(Default::default()) - } -} - -impl Default for CowArc<'static, Path> { - fn default() -> Self { - CowArc::Static(Path::new("")) - } -} - -impl<'a, T: Ord + ?Sized> Ord for CowArc<'a, T> { - #[inline] - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.deref().cmp(other.deref()) - } -} - -impl From for CowArc<'static, Path> { - #[inline] - fn from(value: PathBuf) -> Self { - CowArc::Owned(value.into()) - } -} - -impl From<&'static str> for CowArc<'static, Path> { - #[inline] - fn from(value: &'static str) -> Self { - CowArc::Static(Path::new(value)) - } -} - -impl From for CowArc<'static, str> { - #[inline] - fn from(value: String) -> Self { - CowArc::Owned(value.into()) - } -} - -impl<'a> From<&'a String> for CowArc<'a, str> { - #[inline] - fn from(value: &'a String) -> Self { - CowArc::Borrowed(value) - } -} - -impl From<&'static T> for CowArc<'static, T> { - #[inline] - fn from(value: &'static T) -> Self { - CowArc::Static(value) - } -} diff --git a/crates/bevy_utils/src/lib.rs b/crates/bevy_utils/src/lib.rs index a37a6e18ba..772d3fda31 100644 --- a/crates/bevy_utils/src/lib.rs +++ b/crates/bevy_utils/src/lib.rs @@ -21,7 +21,6 @@ pub use short_names::get_short_name; pub mod synccell; pub mod syncunsafecell; -mod cow_arc; mod default; mod object_safe; pub use object_safe::assert_object_safe; @@ -30,7 +29,6 @@ mod parallel_queue; pub use ahash::{AHasher, RandomState}; pub use bevy_utils_proc_macros::*; -pub use cow_arc::*; pub use default::default; pub use hashbrown; pub use parallel_queue::*;