Skip to content

Commit

Permalink
Add a minimum viable ResolvedValue marker trait
Browse files Browse the repository at this point in the history
This trait will provide a best-effort indication that a type is safe to return from a local task function.

More notes: https://www.notion.so/vercel/Resolved-Vcs-Vc-Lifetimes-Local-Vcs-and-Vc-Refcounts-49d666d3f9594017b5b312b87ddc5bff
  • Loading branch information
bgw committed Jul 3, 2024
1 parent ce295c6 commit 1903a1a
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 27 deletions.
6 changes: 3 additions & 3 deletions crates/turbo-tasks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ pub use turbo_tasks_macros::{function, value, value_impl, value_trait, TaskInput
pub use value::{TransientInstance, TransientValue, Value};
pub use value_type::{TraitMethod, TraitType, ValueType};
pub use vc::{
Dynamic, ResolvedVc, TypedForInput, Upcast, ValueDefault, Vc, VcCast, VcCellNewMode,
VcCellSharedMode, VcDefaultRead, VcRead, VcTransparentRead, VcValueTrait, VcValueTraitCast,
VcValueType, VcValueTypeCast,
Dynamic, ResolvedValue, ResolvedVc, TypedForInput, Upcast, ValueDefault, Vc, VcCast,
VcCellNewMode, VcCellSharedMode, VcDefaultRead, VcRead, VcTransparentRead, VcValueTrait,
VcValueTraitCast, VcValueType, VcValueTypeCast,
};

pub use crate::rcstr::RcStr;
Expand Down
47 changes: 25 additions & 22 deletions crates/turbo-tasks/src/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,26 +78,29 @@ impl<'a> TraceRawVcs for &'a str {
fn trace_raw_vcs(&self, _trace_context: &mut TraceRawVcsContext) {}
}

impl<A: TraceRawVcs> TraceRawVcs for (A,) {
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
TraceRawVcs::trace_raw_vcs(&self.0, trace_context);
}
}

impl<A: TraceRawVcs, B: TraceRawVcs> TraceRawVcs for (A, B) {
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
TraceRawVcs::trace_raw_vcs(&self.0, trace_context);
TraceRawVcs::trace_raw_vcs(&self.1, trace_context);
}
// based on stdlib's internal `tuple_impls!` macro
macro_rules! impl_trace_tuple {
($T:ident) => {
impl_trace_tuple!(@impl $T);
};
($T:ident $( $U:ident )+) => {
impl_trace_tuple!($( $U )+);
impl_trace_tuple!(@impl $T $( $U )+);
};
(@impl $( $T:ident )+) => {
impl<$($T: TraceRawVcs),+> TraceRawVcs for ($($T,)+) {
#[allow(non_snake_case)]
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
let ($($T,)+) = self;
$(
TraceRawVcs::trace_raw_vcs($T, trace_context);
)+
}
}
};
}

impl<A: TraceRawVcs, B: TraceRawVcs, C: TraceRawVcs> TraceRawVcs for (A, B, C) {
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
TraceRawVcs::trace_raw_vcs(&self.0, trace_context);
TraceRawVcs::trace_raw_vcs(&self.1, trace_context);
TraceRawVcs::trace_raw_vcs(&self.2, trace_context);
}
}
impl_trace_tuple!(E D C B A Z Y X W V U T);

impl<T: TraceRawVcs> TraceRawVcs for Option<T> {
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
Expand All @@ -123,7 +126,7 @@ impl<T: TraceRawVcs, S> TraceRawVcs for HashSet<T, S> {
}
}

impl<T: TraceRawVcs, S> TraceRawVcs for AutoSet<T, S> {
impl<T: TraceRawVcs, S, const I: usize> TraceRawVcs for AutoSet<T, S, I> {
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
for item in self.iter() {
TraceRawVcs::trace_raw_vcs(item, trace_context);
Expand Down Expand Up @@ -156,7 +159,7 @@ impl<K: TraceRawVcs, V: TraceRawVcs, S> TraceRawVcs for HashMap<K, V, S> {
}
}

impl<K: TraceRawVcs, V: TraceRawVcs, S> TraceRawVcs for AutoMap<K, V, S> {
impl<K: TraceRawVcs, V: TraceRawVcs, S, const I: usize> TraceRawVcs for AutoMap<K, V, S, I> {
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
for (key, value) in self.iter() {
TraceRawVcs::trace_raw_vcs(key, trace_context);
Expand Down Expand Up @@ -210,13 +213,13 @@ impl<T: TraceRawVcs, E: TraceRawVcs> TraceRawVcs for Result<T, E> {
}
}

impl<T: TraceRawVcs> TraceRawVcs for Mutex<T> {
impl<T: TraceRawVcs + ?Sized> TraceRawVcs for Mutex<T> {
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
self.lock().unwrap().trace_raw_vcs(trace_context);
}
}

impl<T: TraceRawVcs> TraceRawVcs for RefCell<T> {
impl<T: TraceRawVcs + ?Sized> TraceRawVcs for RefCell<T> {
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
self.borrow().trace_raw_vcs(trace_context);
}
Expand Down
2 changes: 1 addition & 1 deletion crates/turbo-tasks/src/vc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use self::{
cell_mode::{VcCellNewMode, VcCellSharedMode},
default::ValueDefault,
read::{ReadVcFuture, VcDefaultRead, VcRead, VcTransparentRead},
resolved::ResolvedVc,
resolved::{ResolvedValue, ResolvedVc},
traits::{Dynamic, TypedForInput, Upcast, VcValueTrait, VcValueType},
};
use crate::{
Expand Down
91 changes: 90 additions & 1 deletion crates/turbo-tasks/src/vc/resolved.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
use std::{
cell::RefCell,
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
hash::{Hash, Hasher},
ops::Deref,
path::{Path, PathBuf},
sync::{
atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicU16, AtomicU32, AtomicU64,
AtomicU8, AtomicUsize,
},
Arc, Mutex,
},
time::Duration,
};

use crate::vc::Vc;
use auto_hash_map::{AutoMap, AutoSet};
use indexmap::{IndexMap, IndexSet};

use crate::{vc::Vc, RcStr};

#[derive(Copy, Clone)]
pub struct ResolvedVc<T>
Expand Down Expand Up @@ -32,3 +46,78 @@ where
self.node.hash(state);
}
}

/// Indicates that a type does not contain any instances of [`Vc`]. It may
/// contain [`ResolvedVc`].
///
/// # Safety
///
/// This trait is marked as unsafe. You should not derive it yourself, but
/// instead you should rely on [`#[turbo_tasks::value(resolved)]`][macro@
/// turbo_tasks::value] to do it for you.
pub unsafe trait ResolvedValue {}

unsafe impl<T: ?Sized + Send + ResolvedValue> ResolvedValue for ResolvedVc<T> {}

macro_rules! impl_resolved {
($ty:ty) => {
unsafe impl ResolvedValue for $ty {}
};

($ty:ty, $($tys:ty),+) => {
impl_resolved!($ty);
impl_resolved!($($tys),+);
}
}

impl_resolved!(i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, char, bool, usize);
impl_resolved!(
AtomicI8,
AtomicU8,
AtomicI16,
AtomicU16,
AtomicI32,
AtomicU32,
AtomicI64,
AtomicU64,
AtomicBool,
AtomicUsize
);
impl_resolved!((), String, Duration, anyhow::Error, RcStr);
impl_resolved!(Path, PathBuf);
impl_resolved!(serde_json::Value);

// based on stdlib's internal `tuple_impls!` macro
macro_rules! impl_resolved_tuple {
($T:ident) => {
impl_resolved_tuple!(@impl $T);
};
($T:ident $( $U:ident )+) => {
impl_resolved_tuple!($( $U )+);
impl_resolved_tuple!(@impl $T $( $U )+);
};
(@impl $( $T:ident )+) => {
unsafe impl<$($T: ResolvedValue),+> ResolvedValue for ($($T,)+) {}
};
}

impl_resolved_tuple!(E D C B A Z Y X W V U T);

unsafe impl<T: ResolvedValue> ResolvedValue for Option<T> {}
unsafe impl<T: ResolvedValue> ResolvedValue for Vec<T> {}
unsafe impl<T: ResolvedValue, S> ResolvedValue for HashSet<T, S> {}
unsafe impl<T: ResolvedValue, S, const I: usize> ResolvedValue for AutoSet<T, S, I> {}
unsafe impl<T: ResolvedValue> ResolvedValue for BTreeSet<T> {}
unsafe impl<T: ResolvedValue, S> ResolvedValue for IndexSet<T, S> {}
unsafe impl<K: ResolvedValue, V: ResolvedValue, S> ResolvedValue for HashMap<K, V, S> {}
unsafe impl<K: ResolvedValue, V: ResolvedValue, S, const I: usize> ResolvedValue
for AutoMap<K, V, S, I>
{
}
unsafe impl<K: ResolvedValue, V: ResolvedValue> ResolvedValue for BTreeMap<K, V> {}
unsafe impl<K: ResolvedValue, V: ResolvedValue, S> ResolvedValue for IndexMap<K, V, S> {}
unsafe impl<T: ResolvedValue + ?Sized> ResolvedValue for Box<T> {}
unsafe impl<T: ResolvedValue + ?Sized> ResolvedValue for Arc<T> {}
unsafe impl<T: ResolvedValue, E: ResolvedValue> ResolvedValue for Result<T, E> {}
unsafe impl<T: ResolvedValue + ?Sized> ResolvedValue for Mutex<T> {}
unsafe impl<T: ResolvedValue + ?Sized> ResolvedValue for RefCell<T> {}

0 comments on commit 1903a1a

Please sign in to comment.