diff --git a/crates/turbo-tasks-memory/src/cell.rs b/crates/turbo-tasks-memory/src/cell.rs index 7373991086f98..1f82d32dc3661 100644 --- a/crates/turbo-tasks-memory/src/cell.rs +++ b/crates/turbo-tasks-memory/src/cell.rs @@ -151,7 +151,7 @@ impl Cell { CellState::Empty | CellState::Computing { .. } | CellState::TrackedValueless => { CellContent(None) } - CellState::Value { content } => content.clone(), + CellState::Value { content } => content.to_owned(), } } @@ -159,6 +159,10 @@ impl Cell { /// content has changed. /// If clean = true, the task inputs weren't changes since the last /// execution and can be assumed to produce the same content again. + /// + /// Safety: This funtion does not check if the type of the content is the + /// same as the type of the cell. It is the caller's responsibility to + /// ensure that the content is of the correct type. pub fn assign( &mut self, content: CellContent, diff --git a/crates/turbo-tasks-memory/src/memory_backend.rs b/crates/turbo-tasks-memory/src/memory_backend.rs index d4ef3ec10a02e..09086a41b9ec4 100644 --- a/crates/turbo-tasks-memory/src/memory_backend.rs +++ b/crates/turbo-tasks-memory/src/memory_backend.rs @@ -22,7 +22,7 @@ use turbo_prehash::{BuildHasherExt, PassThroughHash, PreHashed}; use turbo_tasks::{ backend::{ Backend, BackendJobId, CellContent, PersistentTaskType, TaskCollectiblesMap, - TaskExecutionSpec, TransientTaskType, + TaskExecutionSpec, TransientTaskType, TypedCellContent, }, event::EventListener, util::{IdFactoryWithReuse, NoMoveVec}, @@ -404,11 +404,13 @@ impl Backend for MemoryBackend { index: CellId, reader: TaskId, turbo_tasks: &dyn TurboTasksBackendApi, - ) -> Result> { + ) -> Result> { if task_id == reader { - Ok(Ok(self.with_task(task_id, |task| { - task.with_cell(index, |cell| cell.read_own_content_untracked()) - }))) + Ok(Ok(self + .with_task(task_id, |task| { + task.with_cell(index, |cell| cell.read_own_content_untracked()) + }) + .into_typed(index.type_id))) } else { Task::add_dependency_to_current(TaskEdge::Cell(task_id, index)); self.with_task(task_id, |task| { @@ -420,7 +422,7 @@ impl Backend for MemoryBackend { self, turbo_tasks, ) { - Ok(content) => Ok(Ok(content)), + Ok(content) => Ok(Ok(content.into_typed(index.type_id))), Err(ReadCellError::Recomputing(listener)) => Ok(Err(listener)), Err(ReadCellError::CellRemoved) => Err(anyhow!("Cell doesn't exist")), } @@ -433,9 +435,10 @@ impl Backend for MemoryBackend { current_task: TaskId, index: CellId, _turbo_tasks: &dyn TurboTasksBackendApi, - ) -> Result { + ) -> Result { Ok(self.with_task(current_task, |task| { task.with_cell(index, |cell| cell.read_own_content_untracked()) + .into_typed(index.type_id) })) } @@ -444,7 +447,7 @@ impl Backend for MemoryBackend { task_id: TaskId, index: CellId, turbo_tasks: &dyn TurboTasksBackendApi, - ) -> Result> { + ) -> Result> { self.with_task(task_id, |task| { match task.read_cell( index, @@ -454,7 +457,7 @@ impl Backend for MemoryBackend { self, turbo_tasks, ) { - Ok(content) => Ok(Ok(content)), + Ok(content) => Ok(Ok(content.into_typed(index.type_id))), Err(ReadCellError::Recomputing(listener)) => Ok(Err(listener)), Err(ReadCellError::CellRemoved) => Err(anyhow!("Cell doesn't exist")), } @@ -497,6 +500,9 @@ impl Backend for MemoryBackend { }); } + /// SAFETY: This function does not validate that the data in `content` is of + /// the same type as in `index`. It is the caller's responsibility to ensure + /// that the content is of the correct type. fn update_task_cell( &self, task: TaskId, diff --git a/crates/turbo-tasks-testing/src/lib.rs b/crates/turbo-tasks-testing/src/lib.rs index 353d0a1b3c7be..f61c04d673ab7 100644 --- a/crates/turbo-tasks-testing/src/lib.rs +++ b/crates/turbo-tasks-testing/src/lib.rs @@ -15,7 +15,7 @@ use std::{ use anyhow::{anyhow, Result}; use futures::FutureExt; use turbo_tasks::{ - backend::{CellContent, TaskCollectiblesMap}, + backend::{CellContent, TaskCollectiblesMap, TypedCellContent}, event::{Event, EventListener}, registry, test_helpers::with_turbo_tasks_for_testing, @@ -189,33 +189,35 @@ impl TurboTasksApi for VcStorage { &self, task: TaskId, index: CellId, - ) -> Result> { + ) -> Result> { let map = self.cells.lock().unwrap(); - if let Some(cell) = map.get(&(task, index)) { - Ok(Ok(cell.clone())) + Ok(Ok(if let Some(cell) = map.get(&(task, index)) { + cell.clone() } else { - Ok(Ok(CellContent::default())) + Default::default() } + .into_typed(index.type_id))) } fn try_read_task_cell_untracked( &self, task: TaskId, index: CellId, - ) -> Result> { + ) -> Result> { let map = self.cells.lock().unwrap(); - if let Some(cell) = map.get(&(task, index)) { - Ok(Ok(cell.clone())) + Ok(Ok(if let Some(cell) = map.get(&(task, index)) { + cell.to_owned() } else { - Ok(Ok(CellContent::default())) + Default::default() } + .into_typed(index.type_id))) } fn try_read_own_task_cell_untracked( &self, current_task: TaskId, index: CellId, - ) -> Result { + ) -> Result { self.read_own_task_cell(current_task, index) } @@ -244,13 +246,14 @@ impl TurboTasksApi for VcStorage { unimplemented!() } - fn read_own_task_cell(&self, task: TaskId, index: CellId) -> Result { + fn read_own_task_cell(&self, task: TaskId, index: CellId) -> Result { let map = self.cells.lock().unwrap(); - if let Some(cell) = map.get(&(task, index)) { - Ok(cell.clone()) + Ok(if let Some(cell) = map.get(&(task, index)) { + cell.to_owned() } else { - Ok(CellContent::default()) + Default::default() } + .into_typed(index.type_id)) } fn update_own_task_cell(&self, task: TaskId, index: CellId, content: CellContent) { diff --git a/crates/turbo-tasks/src/backend.rs b/crates/turbo-tasks/src/backend.rs index 5a683c6b90f4a..bb1572bc3a1de 100644 --- a/crates/turbo-tasks/src/backend.rs +++ b/crates/turbo-tasks/src/backend.rs @@ -9,10 +9,9 @@ use std::{ time::Duration, }; -use anyhow::{anyhow, bail, Result}; +use anyhow::{anyhow, Result}; use auto_hash_map::AutoMap; use rustc_hash::FxHasher; -use serde::{Deserialize, Serialize}; use tracing::Span; pub use crate::id::{BackendJobId, ExecutionId}; @@ -333,10 +332,10 @@ pub struct TaskExecutionSpec<'a> { pub span: Span, } -// TODO technically CellContent is already indexed by the ValueTypeId, so we -// don't need to store it here -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] pub struct CellContent(pub Option); +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct TypedCellContent(pub ValueTypeId, pub CellContent); impl Display for CellContent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -347,9 +346,9 @@ impl Display for CellContent { } } -impl CellContent { +impl TypedCellContent { pub fn cast(self) -> Result> { - let data = self.0.ok_or_else(|| anyhow!("Cell is empty"))?; + let data = self.1 .0.ok_or_else(|| anyhow!("Cell is empty"))?; let data = data .downcast() .map_err(|_err| anyhow!("Unexpected type in cell"))?; @@ -358,24 +357,35 @@ impl CellContent { /// # Safety /// - /// The caller must ensure that the CellContent contains a vc that - /// implements T. + /// The caller must ensure that the TypedCellContent contains a vc + /// that implements T. pub fn cast_trait(self) -> Result> where T: VcValueTrait + ?Sized, { - let shared_reference = self.0.ok_or_else(|| anyhow!("Cell is empty"))?; - if shared_reference.0.is_none() { - bail!("Cell content is untyped"); - } + let shared_reference = self + .1 + .0 + .ok_or_else(|| anyhow!("Cell is empty"))? + .typed(self.0); Ok( - // Safety: We just checked that the content is typed. + // Safety: It is a TypedSharedReference TraitRef::new(shared_reference), ) } pub fn try_cast(self) -> Option> { - Some(ReadRef::new_arc(self.0?.downcast().ok()?)) + Some(ReadRef::new_arc(self.1 .0?.downcast().ok()?)) + } + + pub fn into_untyped(self) -> CellContent { + self.1 + } +} + +impl CellContent { + pub fn into_typed(self, type_id: ValueTypeId) -> TypedCellContent { + TypedCellContent(type_id, self) } } @@ -463,7 +473,7 @@ pub trait Backend: Sync + Send { index: CellId, reader: TaskId, turbo_tasks: &dyn TurboTasksBackendApi, - ) -> Result>; + ) -> Result>; /// INVALIDATION: Be careful with this, it will not track dependencies, so /// using it could break cache invalidation. @@ -472,7 +482,7 @@ pub trait Backend: Sync + Send { task: TaskId, index: CellId, turbo_tasks: &dyn TurboTasksBackendApi, - ) -> Result>; + ) -> Result>; /// INVALIDATION: Be careful with this, it will not track dependencies, so /// using it could break cache invalidation. @@ -481,10 +491,10 @@ pub trait Backend: Sync + Send { current_task: TaskId, index: CellId, turbo_tasks: &dyn TurboTasksBackendApi, - ) -> Result { + ) -> Result { match self.try_read_task_cell_untracked(current_task, index, turbo_tasks)? { Ok(content) => Ok(content), - Err(_) => Ok(CellContent(None)), + Err(_) => Ok(TypedCellContent(index.type_id, CellContent(None))), } } @@ -575,10 +585,7 @@ impl PersistentTaskType { name: Cow<'static, str>, this: RawVc, ) -> Result { - let CellContent(Some(SharedReference(Some(value_type), _))) = this.into_read().await? - else { - bail!("Cell is empty or untyped"); - }; + let TypedCellContent(value_type, _) = this.into_read().await?; Self::resolve_trait_method_from_value(trait_type, value_type, name) } @@ -590,12 +597,7 @@ impl PersistentTaskType { turbo_tasks: Arc>, ) -> Result { let this = this.resolve().await?; - let CellContent(Some(SharedReference(this_ty, _))) = this.into_read().await? else { - bail!("Cell is empty"); - }; - let Some(this_ty) = this_ty else { - bail!("Cell is untyped"); - }; + let TypedCellContent(this_ty, _) = this.into_read().await?; let native_fn = Self::resolve_trait_method_from_value(trait_type, this_ty, name)?; let arg = registry::get_function(native_fn) diff --git a/crates/turbo-tasks/src/manager.rs b/crates/turbo-tasks/src/manager.rs index 0b5b5bfbb2b11..5c0c2f3a5c35c 100644 --- a/crates/turbo-tasks/src/manager.rs +++ b/crates/turbo-tasks/src/manager.rs @@ -26,7 +26,7 @@ use turbo_tasks_malloc::TurboMalloc; use crate::{ backend::{ Backend, CellContent, PersistentTaskType, TaskCollectiblesMap, TaskExecutionSpec, - TransientTaskType, + TransientTaskType, TypedCellContent, }, capture_future::{self, CaptureFuture}, event::{Event, EventListener}, @@ -99,7 +99,7 @@ pub trait TurboTasksApi: TurboTasksCallApi + Sync + Send { &self, task: TaskId, index: CellId, - ) -> Result>; + ) -> Result>; /// INVALIDATION: Be careful with this, it will not track dependencies, so /// using it could break cache invalidation. @@ -107,7 +107,7 @@ pub trait TurboTasksApi: TurboTasksCallApi + Sync + Send { &self, task: TaskId, index: CellId, - ) -> Result>; + ) -> Result>; fn read_task_collectibles(&self, task: TaskId, trait_id: TraitTypeId) -> TaskCollectiblesMap; @@ -121,9 +121,9 @@ pub trait TurboTasksApi: TurboTasksCallApi + Sync + Send { &self, current_task: TaskId, index: CellId, - ) -> Result; + ) -> Result; - fn read_own_task_cell(&self, task: TaskId, index: CellId) -> Result; + fn read_own_task_cell(&self, task: TaskId, index: CellId) -> Result; fn update_own_task_cell(&self, task: TaskId, index: CellId, content: CellContent); fn mark_own_task_as_finished(&self, task: TaskId); @@ -981,7 +981,7 @@ impl TurboTasksApi for TurboTasks { &self, task: TaskId, index: CellId, - ) -> Result> { + ) -> Result> { self.backend .try_read_task_cell(task, index, current_task("reading Vcs"), self) } @@ -990,7 +990,7 @@ impl TurboTasksApi for TurboTasks { &self, task: TaskId, index: CellId, - ) -> Result> { + ) -> Result> { self.backend.try_read_task_cell_untracked(task, index, self) } @@ -998,7 +998,7 @@ impl TurboTasksApi for TurboTasks { &self, current_task: TaskId, index: CellId, - ) -> Result { + ) -> Result { self.backend .try_read_own_task_cell_untracked(current_task, index, self) } @@ -1045,7 +1045,7 @@ impl TurboTasksApi for TurboTasks { } } - fn read_own_task_cell(&self, task: TaskId, index: CellId) -> Result { + fn read_own_task_cell(&self, task: TaskId, index: CellId) -> Result { // INVALIDATION: don't need to track a dependency to itself self.try_read_own_task_cell_untracked(task, index) } @@ -1507,7 +1507,7 @@ pub(crate) async fn read_task_cell( this: &dyn TurboTasksApi, id: TaskId, index: CellId, -) -> Result { +) -> Result { loop { match this.try_read_task_cell(id, index)? { Ok(result) => return Ok(result), @@ -1543,10 +1543,7 @@ impl CurrentCellRef { tt.update_own_task_cell( self.current_task, self.index, - CellContent(Some(SharedReference::new( - Some(self.index.type_id), - triomphe::Arc::new(update), - ))), + CellContent(Some(SharedReference::new(triomphe::Arc::new(update)))), ) } } @@ -1567,18 +1564,15 @@ impl CurrentCellRef { tt.update_own_task_cell( self.current_task, self.index, - CellContent(Some(SharedReference::new( - Some(self.index.type_id), - triomphe::Arc::new(new_content), - ))), + CellContent(Some(SharedReference::new(triomphe::Arc::new(new_content)))), ) } pub fn update_shared_reference(&self, shared_ref: SharedReference) { let tt = turbo_tasks(); let content = tt.read_own_task_cell(self.current_task, self.index).ok(); - let update = if let Some(CellContent(Some(content))) = content { - content != shared_ref + let update = if let Some(TypedCellContent(_, CellContent(shared_ref_exp))) = content { + shared_ref_exp.as_ref().ne(&Some(&shared_ref)) } else { true }; diff --git a/crates/turbo-tasks/src/persisted_graph.rs b/crates/turbo-tasks/src/persisted_graph.rs index dffb1086c79e3..e317dc903714b 100644 --- a/crates/turbo-tasks/src/persisted_graph.rs +++ b/crates/turbo-tasks/src/persisted_graph.rs @@ -1,12 +1,13 @@ use anyhow::Result; -use serde::{Deserialize, Serialize}; +use serde::{ser::SerializeSeq, Deserialize, Serialize}; use crate::{ backend::{CellContent, PersistentTaskType}, + task::shared_reference::TypedSharedReference, CellId, RawVc, TaskId, }; -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Clone, Debug)] pub enum TaskCell { Content(CellContent), NeedComputation, @@ -22,9 +23,63 @@ impl Default for TaskCell { pub struct TaskData { pub children: Vec, pub dependencies: Vec, - pub cells: Vec<(CellId, TaskCell)>, + pub cells: TaskCells, pub output: RawVc, } + +/// A newtype struct that intercepts serde. This is required +/// because for safety reasons, TaskCell<()> is not allowed to +/// be deserialized. We augment it with type data then write +/// it. This is inefficient on disk but could be alleviated later. +#[derive(Debug)] +pub struct TaskCells(pub Vec<(CellId, TaskCell)>); + +// the on-disk representation of a task cell. it is local to this impl +// to prevent users accidentally ser/de the untyped data +#[derive(Serialize, Deserialize)] +struct SerializableTaskCell(Option>); +impl From for TaskCell { + fn from(val: SerializableTaskCell) -> Self { + match val.0 { + Some(d) => TaskCell::Content(CellContent(d.map(|d| d.untyped().1))), + None => TaskCell::NeedComputation, + } + } +} + +impl Serialize for TaskCells { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.0.len()))?; + for (cell_id, cell) in &self.0 { + let task_cell = SerializableTaskCell(match cell { + TaskCell::Content(CellContent(opt)) => { + Some(opt.as_ref().map(|d| d.typed(cell_id.type_id))) + } + TaskCell::NeedComputation => None, + }); + seq.serialize_element(&(cell_id, task_cell))?; + } + seq.end() + } +} + +impl<'de> Deserialize<'de> for TaskCells { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let data: Vec<(CellId, SerializableTaskCell)> = Vec::deserialize(deserializer)?; + Ok(TaskCells( + data.into_iter() + .map(|(id, cell)| (id, cell.into())) + .collect(), + )) + } +} + pub struct ReadTaskState { pub clean: bool, pub keeps_external_active: bool, diff --git a/crates/turbo-tasks/src/raw_vc.rs b/crates/turbo-tasks/src/raw_vc.rs index 582dec5396dcf..ec6fa115fc1ad 100644 --- a/crates/turbo-tasks/src/raw_vc.rs +++ b/crates/turbo-tasks/src/raw_vc.rs @@ -13,14 +13,11 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use crate::{ - backend::CellContent, + backend::{CellContent, TypedCellContent}, event::EventListener, manager::{read_task_cell, read_task_output, TurboTasksApi}, - registry::{ - get_value_type, {self}, - }, - turbo_tasks, CollectiblesSource, SharedReference, TaskId, TraitTypeId, ValueTypeId, Vc, - VcValueTrait, + registry::{self, get_value_type}, + turbo_tasks, CollectiblesSource, TaskId, TraitTypeId, ValueTypeId, Vc, VcValueTrait, }; #[derive(Error, Debug)] @@ -113,15 +110,11 @@ impl RawVc { let content = read_task_cell(&*tt, task, index) .await .map_err(|source| ResolveTypeError::ReadError { source })?; - if let CellContent(Some(shared_reference)) = content { - if let SharedReference(Some(value_type), _) = shared_reference { - if get_value_type(value_type).has_trait(&trait_type) { - return Ok(Some(RawVc::TaskCell(task, index))); - } else { - return Ok(None); - } + if let TypedCellContent(value_type, CellContent(Some(_))) = content { + if get_value_type(value_type).has_trait(&trait_type) { + return Ok(Some(RawVc::TaskCell(task, index))); } else { - return Err(ResolveTypeError::UntypedContent); + return Ok(None); } } else { return Err(ResolveTypeError::NoContent); @@ -149,15 +142,11 @@ impl RawVc { let content = read_task_cell(&*tt, task, index) .await .map_err(|source| ResolveTypeError::ReadError { source })?; - if let CellContent(Some(shared_reference)) = content { - if let SharedReference(Some(cell_value_type), _) = shared_reference { - if cell_value_type == value_type { - return Ok(Some(RawVc::TaskCell(task, index))); - } else { - return Ok(None); - } + if let TypedCellContent(cell_value_type, CellContent(Some(_))) = content { + if cell_value_type == value_type { + return Ok(Some(RawVc::TaskCell(task, index))); } else { - return Err(ResolveTypeError::UntypedContent); + return Ok(None); } } else { return Err(ResolveTypeError::NoContent); @@ -317,7 +306,7 @@ impl ReadRawVcFuture { } impl Future for ReadRawVcFuture { - type Output = Result; + type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { self.turbo_tasks.notify_scheduled_tasks(); diff --git a/crates/turbo-tasks/src/read_ref.rs b/crates/turbo-tasks/src/read_ref.rs index 3c1255a07cd12..df4b6e4f3df2c 100644 --- a/crates/turbo-tasks/src/read_ref.rs +++ b/crates/turbo-tasks/src/read_ref.rs @@ -243,10 +243,7 @@ where /// reference. pub fn cell(read_ref: ReadRef) -> Vc { let local_cell = find_cell_by_type(T::get_value_type_id()); - local_cell.update_shared_reference(SharedReference::new( - Some(T::get_value_type_id()), - read_ref.0, - )); + local_cell.update_shared_reference(SharedReference::new(read_ref.0)); Vc { node: local_cell.into(), _t: PhantomData, diff --git a/crates/turbo-tasks/src/task/shared_reference.rs b/crates/turbo-tasks/src/task/shared_reference.rs index 747f2477c98ca..0194bfdfc597d 100644 --- a/crates/turbo-tasks/src/task/shared_reference.rs +++ b/crates/turbo-tasks/src/task/shared_reference.rs @@ -14,29 +14,42 @@ use crate::{ ValueTypeId, }; -/// A type-erased wrapper for [`triomphe::Arc`]. +/// A reference to a piece of data #[derive(Clone)] -pub struct SharedReference( - pub Option, - pub triomphe::Arc, -); +pub struct SharedReference(pub triomphe::Arc); impl SharedReference { - pub fn new(type_id: Option, data: triomphe::Arc) -> Self { - Self(type_id, data.unsize(coerce_to_any_send_sync())) + pub fn new(data: triomphe::Arc) -> Self { + Self(data.unsize(coerce_to_any_send_sync())) } +} + +/// A reference to a piece of data with type information +#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct TypedSharedReference(pub ValueTypeId, pub SharedReference); +impl SharedReference { pub fn downcast(self) -> Result, Self> { - match downcast_triomphe_arc(self.1) { + match downcast_triomphe_arc(self.0) { Ok(data) => Ok(data), - Err(data) => Err(Self(self.0, data)), + Err(data) => Err(Self(data)), } } + + pub(crate) fn typed(&self, type_id: ValueTypeId) -> TypedSharedReference { + TypedSharedReference(type_id, self.clone()) + } +} + +impl TypedSharedReference { + pub(crate) fn untyped(&self) -> (ValueTypeId, SharedReference) { + (self.0, self.1.clone()) + } } impl Hash for SharedReference { fn hash(&self, state: &mut H) { - Hash::hash(&(&*self.1 as *const (dyn Any + Send + Sync)), state) + Hash::hash(&(&*self.0 as *const (dyn Any + Send + Sync)), state) } } impl PartialEq for SharedReference { @@ -44,57 +57,63 @@ impl PartialEq for SharedReference { // only compares their addresses. #[allow(ambiguous_wide_pointer_comparisons)] fn eq(&self, other: &Self) -> bool { - triomphe::Arc::ptr_eq(&self.1, &other.1) + triomphe::Arc::ptr_eq(&self.0, &other.0) } } impl Eq for SharedReference {} - +impl PartialOrd for SharedReference { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for SharedReference { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + Ord::cmp( + &(&*self.0 as *const (dyn Any + Send + Sync)).cast::<()>(), + &(&*other.0 as *const (dyn Any + Send + Sync)).cast::<()>(), + ) + } +} impl Debug for SharedReference { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("SharedReference") - .field(&self.0) - .field(&self.1) - .finish() + f.debug_tuple("SharedReference").field(&self.0).finish() } } -impl Serialize for SharedReference { +impl Serialize for TypedSharedReference { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { - if let SharedReference(Some(ty), arc) = self { - let value_type = registry::get_value_type(*ty); - if let Some(serializable) = value_type.any_as_serializable(arc) { - let mut t = serializer.serialize_tuple(2)?; - t.serialize_element(registry::get_value_type_global_name(*ty))?; - t.serialize_element(serializable)?; - t.end() - } else { - Err(serde::ser::Error::custom(format!( - "{:?} is not serializable", - arc - ))) - } + let TypedSharedReference(ty, SharedReference(arc)) = self; + let value_type = registry::get_value_type(*ty); + if let Some(serializable) = value_type.any_as_serializable(arc) { + let mut t = serializer.serialize_tuple(2)?; + t.serialize_element(registry::get_value_type_global_name(*ty))?; + t.serialize_element(serializable)?; + t.end() } else { - Err(serde::ser::Error::custom( - "untyped values are not serializable", - )) + Err(serde::ser::Error::custom(format!( + "{:?} is not serializable", + arc + ))) } } } impl Display for SharedReference { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(ty) = self.0 { - write!(f, "value of type {}", registry::get_value_type(ty).name) - } else { - write!(f, "untyped value") - } + write!(f, "untyped value") + } +} + +impl Display for TypedSharedReference { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "value of type {}", registry::get_value_type(self.0).name) } } -impl<'de> Deserialize<'de> for SharedReference { +impl<'de> Deserialize<'de> for TypedSharedReference { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -102,7 +121,7 @@ impl<'de> Deserialize<'de> for SharedReference { struct Visitor; impl<'de> serde::de::Visitor<'de> for Visitor { - type Value = SharedReference; + type Value = TypedSharedReference; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("a serializable shared reference") @@ -117,7 +136,7 @@ impl<'de> Deserialize<'de> for SharedReference { if let Some(seed) = registry::get_value_type(ty).get_any_deserialize_seed() { if let Some(value) = seq.next_element_seed(seed)? { - Ok(SharedReference::new(Some(ty), value.into())) + Ok(TypedSharedReference(ty, SharedReference::new(value.into()))) } else { Err(serde::de::Error::invalid_length( 1, diff --git a/crates/turbo-tasks/src/task/task_input.rs b/crates/turbo-tasks/src/task/task_input.rs index ef7cd47b5fe3c..b9f9ebb9d8b9c 100644 --- a/crates/turbo-tasks/src/task/task_input.rs +++ b/crates/turbo-tasks/src/task/task_input.rs @@ -5,8 +5,7 @@ use async_trait::async_trait; use serde::{Deserialize, Serialize}; use crate::{ - magic_any::MagicAny, vc::ResolvedVc, RcStr, TaskId, TransientInstance, TransientValue, Value, - ValueTypeId, Vc, + MagicAny, RcStr, ResolvedVc, TaskId, TransientInstance, TransientValue, Value, ValueTypeId, Vc, }; /// Trait to implement in order for a type to be accepted as a diff --git a/crates/turbo-tasks/src/trait_ref.rs b/crates/turbo-tasks/src/trait_ref.rs index d5eb54ecd8376..43efa4af50296 100644 --- a/crates/turbo-tasks/src/trait_ref.rs +++ b/crates/turbo-tasks/src/trait_ref.rs @@ -5,8 +5,9 @@ use serde::{Deserialize, Serialize}; use crate::{ manager::find_cell_by_type, + task::shared_reference::TypedSharedReference, vc::{cast::VcCast, ReadVcFuture, VcValueTraitCast}, - RawVc, SharedReference, Vc, VcValueTrait, + RawVc, Vc, VcValueTrait, }; /// Similar to a [`ReadRef`][crate::ReadRef], but contains a value trait @@ -19,7 +20,7 @@ pub struct TraitRef where T: ?Sized, { - shared_reference: SharedReference, + shared_reference: TypedSharedReference, _t: PhantomData, } @@ -63,7 +64,7 @@ impl Serialize for TraitRef { impl<'de, T> Deserialize<'de> for TraitRef { fn deserialize>(deserializer: D) -> Result { Ok(Self { - shared_reference: SharedReference::deserialize(deserializer)?, + shared_reference: TypedSharedReference::deserialize(deserializer)?, _t: PhantomData, }) } @@ -83,7 +84,7 @@ impl TraitRef where T: ?Sized, { - pub(crate) fn new(shared_reference: SharedReference) -> Self { + pub(crate) fn new(shared_reference: TypedSharedReference) -> Self { Self { shared_reference, _t: PhantomData, @@ -99,10 +100,9 @@ where /// trait `T`. pub fn cell(trait_ref: TraitRef) -> Vc { // See Safety clause above. - let SharedReference(ty, _) = trait_ref.shared_reference; - let ty = ty.unwrap(); + let TypedSharedReference(ty, shared_ref) = trait_ref.shared_reference; let local_cell = find_cell_by_type(ty); - local_cell.update_shared_reference(trait_ref.shared_reference); + local_cell.update_shared_reference(shared_ref); let raw_vc: RawVc = local_cell.into(); raw_vc.into() } diff --git a/crates/turbo-tasks/src/value.rs b/crates/turbo-tasks/src/value.rs index b3b36db17840f..05ff7098a2b23 100644 --- a/crates/turbo-tasks/src/value.rs +++ b/crates/turbo-tasks/src/value.rs @@ -70,7 +70,8 @@ impl Deref for TransientValue { /// Equality and hash is implemented as pointer comparison. /// /// Doesn't require serialization, and won't be stored in the persistent cache -/// in the future. +/// in the future, so we don't include the `ValueTypeId` in the +/// `SharedReference`. pub struct TransientInstance { inner: SharedReference, phantom: PhantomData, @@ -121,7 +122,7 @@ impl From> for SharedReference { impl From> for TransientInstance { fn from(arc: triomphe::Arc) -> Self { Self { - inner: SharedReference::new(None, arc), + inner: SharedReference::new(arc), phantom: PhantomData, } } @@ -131,7 +132,7 @@ impl TryFrom for TransientInstance type Error = (); fn try_from(inner: SharedReference) -> Result { - if inner.1.downcast_ref::().is_some() { + if inner.0.downcast_ref::().is_some() { Ok(Self { inner, phantom: PhantomData, @@ -145,7 +146,7 @@ impl TryFrom for TransientInstance impl TransientInstance { pub fn new(value: T) -> Self { Self { - inner: SharedReference::new(None, triomphe::Arc::new(value)), + inner: SharedReference::new(triomphe::Arc::new(value)), phantom: PhantomData, } } @@ -155,6 +156,6 @@ impl Deref for TransientInstance { type Target = T; fn deref(&self) -> &Self::Target { - self.inner.1.downcast_ref().unwrap() + self.inner.0.downcast_ref().unwrap() } } diff --git a/crates/turbo-tasks/src/vc/cast.rs b/crates/turbo-tasks/src/vc/cast.rs index b8f0edf2490a2..38325d377c74e 100644 --- a/crates/turbo-tasks/src/vc/cast.rs +++ b/crates/turbo-tasks/src/vc/cast.rs @@ -2,7 +2,7 @@ use std::{marker::PhantomData, mem::ManuallyDrop}; use anyhow::Result; -use crate::{backend::CellContent, ReadRef, TraitRef, VcRead, VcValueTrait, VcValueType}; +use crate::{backend::TypedCellContent, ReadRef, TraitRef, VcRead, VcValueTrait, VcValueType}; /// Trait defined to share behavior between values and traits within /// [`ReadRawVcFuture`][crate::ReadRawVcFuture]. See [`VcValueTypeCast`] and @@ -12,7 +12,7 @@ use crate::{backend::CellContent, ReadRef, TraitRef, VcRead, VcValueTrait, VcVal pub trait VcCast: private::Sealed { type Output; - fn cast(content: CellContent) -> Result; + fn cast(content: TypedCellContent) -> Result; } /// Casts an arbitrary cell content into a [`ReadRef`]. @@ -26,7 +26,7 @@ where { type Output = ReadRef; - fn cast(content: CellContent) -> Result { + fn cast(content: TypedCellContent) -> Result { Ok( // Safety: the `VcValueType` implementor must guarantee that both `T` and // `Repr` are #[repr(transparent)]. @@ -57,7 +57,7 @@ where { type Output = TraitRef; - fn cast(content: CellContent) -> Result { + fn cast(content: TypedCellContent) -> Result { // Safety: Constructor ensures the cell content points to a value that // implements T content.cast_trait::()