diff --git a/crates/turbo-tasks-macros/src/func.rs b/crates/turbo-tasks-macros/src/func.rs
index a02eb175ae06b..3e1a414cfa065 100644
--- a/crates/turbo-tasks-macros/src/func.rs
+++ b/crates/turbo-tasks-macros/src/func.rs
@@ -14,6 +14,7 @@ pub struct TurboFn {
// block: Block,
ident: Ident,
output: Type,
+ this: Option,
inputs: Vec,
}
@@ -56,6 +57,7 @@ impl TurboFn {
}
let mut raw_inputs = original_signature.inputs.iter();
+ let mut this = None;
let mut inputs = Vec::with_capacity(raw_inputs.len());
if let Some(possibly_receiver) = raw_inputs.next() {
@@ -142,7 +144,7 @@ impl TurboFn {
_ => {}
}
- inputs.push(Input {
+ this = Some(Input {
ident: Ident::new("self", self_token.span()),
ty: parse_quote! { turbo_tasks::Vc },
});
@@ -160,7 +162,7 @@ impl TurboFn {
return None;
}
- let ident = if let Pat::Ident(ident) = &*typed.pat {
+ if let Pat::Ident(ident) = &*typed.pat {
if ident.ident == "self" {
if let DefinitionContext::NakedFn { .. } = definition_context {
// The function is not associated. The compiler will emit an error
@@ -174,6 +176,13 @@ impl TurboFn {
// if the user provided an invalid receiver type
// when
// calling `into_concrete`.
+
+ let ident = ident.ident.clone();
+
+ this = Some(Input {
+ ident,
+ ty: parse_quote! { turbo_tasks::Vc },
+ });
} else {
match definition_context {
DefinitionContext::NakedFn { .. }
@@ -192,18 +201,22 @@ impl TurboFn {
return None;
}
}
- }
+ let ident = ident.ident.clone();
- ident.ident.clone()
+ inputs.push(Input {
+ ident,
+ ty: (*typed.ty).clone(),
+ });
+ }
} else {
// We can't support destructuring patterns (or other kinds of patterns).
- Ident::new("arg1", typed.pat.span())
- };
+ let ident = Ident::new("arg1", typed.pat.span());
- inputs.push(Input {
- ident,
- ty: (*typed.ty).clone(),
- });
+ inputs.push(Input {
+ ident,
+ ty: (*typed.ty).clone(),
+ });
+ }
}
}
}
@@ -234,6 +247,7 @@ impl TurboFn {
Some(TurboFn {
ident: original_signature.ident.clone(),
output,
+ this,
inputs,
})
}
@@ -242,8 +256,10 @@ impl TurboFn {
/// converted to a standard turbo_tasks function signature.
pub fn signature(&self) -> Signature {
let exposed_inputs: Punctuated<_, Token![,]> = self
- .inputs
- .iter()
+ .this
+ .as_ref()
+ .into_iter()
+ .chain(self.inputs.iter())
.map(|input| {
FnArg::Typed(PatType {
attrs: Default::default(),
@@ -288,21 +304,38 @@ impl TurboFn {
.collect()
}
+ fn converted_this(&self) -> Option {
+ self.this.as_ref().map(|Input { ty: _, ident }| {
+ parse_quote! {
+ turbo_tasks::Vc::into_raw(#ident)
+ }
+ })
+ }
+
/// The block of the exposed function for a dynamic dispatch call to the
/// given trait.
pub fn dynamic_block(&self, trait_type_id_ident: &Ident) -> Block {
let ident = &self.ident;
let output = &self.output;
- let converted_inputs = self.converted_inputs();
- parse_quote! {
- {
- <#output as turbo_tasks::task::TaskOutput>::try_from_raw_vc(
- turbo_tasks::trait_call(
- *#trait_type_id_ident,
- std::borrow::Cow::Borrowed(stringify!(#ident)),
- vec![#converted_inputs],
+ if let Some(converted_this) = self.converted_this() {
+ let converted_inputs = self.converted_inputs();
+ parse_quote! {
+ {
+ <#output as turbo_tasks::task::TaskOutput>::try_from_raw_vc(
+ turbo_tasks::trait_call(
+ *#trait_type_id_ident,
+ std::borrow::Cow::Borrowed(stringify!(#ident)),
+ #converted_this,
+ vec![#converted_inputs],
+ )
)
- )
+ }
+ }
+ } else {
+ parse_quote! {
+ {
+ unimplemented!("trait methods without self are not yet supported")
+ }
}
}
}
@@ -312,17 +345,35 @@ impl TurboFn {
pub fn static_block(&self, native_function_id_ident: &Ident) -> Block {
let output = &self.output;
let converted_inputs = self.converted_inputs();
- parse_quote! {
- {
- <#output as turbo_tasks::task::TaskOutput>::try_from_raw_vc(
- turbo_tasks::dynamic_call(
- *#native_function_id_ident,
- vec![#converted_inputs],
+ if let Some(converted_this) = self.converted_this() {
+ parse_quote! {
+ {
+ <#output as turbo_tasks::task::TaskOutput>::try_from_raw_vc(
+ turbo_tasks::dynamic_this_call(
+ *#native_function_id_ident,
+ #converted_this,
+ vec![#converted_inputs],
+ )
)
- )
+ }
+ }
+ } else {
+ parse_quote! {
+ {
+ <#output as turbo_tasks::task::TaskOutput>::try_from_raw_vc(
+ turbo_tasks::dynamic_call(
+ *#native_function_id_ident,
+ vec![#converted_inputs],
+ )
+ )
+ }
}
}
}
+
+ pub(crate) fn is_method(&self) -> bool {
+ self.this.is_some()
+ }
}
fn return_type_to_type(return_type: &ReturnType) -> Type {
@@ -454,13 +505,15 @@ impl DefinitionContext {
pub struct NativeFn {
function_path_string: String,
function_path: ExprPath,
+ is_method: bool,
}
impl NativeFn {
- pub fn new(function_path_string: &str, function_path: &ExprPath) -> NativeFn {
+ pub fn new(function_path_string: &str, function_path: &ExprPath, is_method: bool) -> NativeFn {
NativeFn {
function_path_string: function_path_string.to_owned(),
function_path: function_path.clone(),
+ is_method,
}
}
@@ -472,13 +525,23 @@ impl NativeFn {
let Self {
function_path_string,
function_path,
+ is_method,
} = self;
- parse_quote! {
- turbo_tasks::macro_helpers::Lazy::new(|| {
- #[allow(deprecated)]
- turbo_tasks::NativeFunction::new(#function_path_string.to_owned(), #function_path)
- })
+ if *is_method {
+ parse_quote! {
+ turbo_tasks::macro_helpers::Lazy::new(|| {
+ #[allow(deprecated)]
+ turbo_tasks::NativeFunction::new_method(#function_path_string.to_owned(), #function_path)
+ })
+ }
+ } else {
+ parse_quote! {
+ turbo_tasks::macro_helpers::Lazy::new(|| {
+ #[allow(deprecated)]
+ turbo_tasks::NativeFunction::new_function(#function_path_string.to_owned(), #function_path)
+ })
+ }
}
}
diff --git a/crates/turbo-tasks-macros/src/function_macro.rs b/crates/turbo-tasks-macros/src/function_macro.rs
index 4d805de9ad711..4c047d0e067a5 100644
--- a/crates/turbo-tasks-macros/src/function_macro.rs
+++ b/crates/turbo-tasks-macros/src/function_macro.rs
@@ -30,7 +30,11 @@ pub fn function(_args: TokenStream, input: TokenStream) -> TokenStream {
let mut inline_signature = sig.clone();
inline_signature.ident = inline_function_ident;
- let native_fn = NativeFn::new(&ident.to_string(), &inline_function_path);
+ let native_fn = NativeFn::new(
+ &ident.to_string(),
+ &inline_function_path,
+ turbo_fn.is_method(),
+ );
let native_function_ident = get_native_function_ident(ident);
let native_function_ty = native_fn.ty();
let native_function_def = native_fn.definition();
diff --git a/crates/turbo-tasks-macros/src/lib.rs b/crates/turbo-tasks-macros/src/lib.rs
index b7a0e3bcca25c..092eeb151b552 100644
--- a/crates/turbo-tasks-macros/src/lib.rs
+++ b/crates/turbo-tasks-macros/src/lib.rs
@@ -166,6 +166,13 @@ pub fn function(args: TokenStream, input: TokenStream) -> TokenStream {
function_macro::function(args, input)
}
+#[allow_internal_unstable(min_specialization, into_future, trivial_bounds)]
+#[proc_macro_error]
+#[proc_macro_attribute]
+pub fn test_tt(_args: TokenStream, input: TokenStream) -> TokenStream {
+ derive::derive_value_debug(input)
+}
+
#[allow_internal_unstable(min_specialization, into_future, trivial_bounds)]
#[proc_macro_error]
#[proc_macro_attribute]
diff --git a/crates/turbo-tasks-macros/src/value_impl_macro.rs b/crates/turbo-tasks-macros/src/value_impl_macro.rs
index fc8773b79226a..235268169d125 100644
--- a/crates/turbo-tasks-macros/src/value_impl_macro.rs
+++ b/crates/turbo-tasks-macros/src/value_impl_macro.rs
@@ -120,6 +120,7 @@ pub fn value_impl(args: TokenStream, input: TokenStream) -> TokenStream {
let native_fn = NativeFn::new(
&format!("{ty}::{ident}", ty = ty.to_token_stream()),
&inline_function_path,
+ turbo_fn.is_method(),
);
let native_function_ident = get_inherent_impl_function_ident(ty_ident, ident);
@@ -225,6 +226,7 @@ pub fn value_impl(args: TokenStream, input: TokenStream) -> TokenStream {
trait_path = trait_path.to_token_stream()
),
&inline_function_path,
+ turbo_fn.is_method(),
);
let native_function_ident =
diff --git a/crates/turbo-tasks-macros/src/value_trait_macro.rs b/crates/turbo-tasks-macros/src/value_trait_macro.rs
index 23ee201369b1f..931c26e69944d 100644
--- a/crates/turbo-tasks-macros/src/value_trait_macro.rs
+++ b/crates/turbo-tasks-macros/src/value_trait_macro.rs
@@ -108,8 +108,11 @@ pub fn value_trait(args: TokenStream, input: TokenStream) -> TokenStream {
let mut inline_signature = sig.clone();
inline_signature.ident = inline_function_ident;
- let native_function =
- NativeFn::new(&format!("{trait_ident}::{ident}"), &inline_function_path);
+ let native_function = NativeFn::new(
+ &format!("{trait_ident}::{ident}"),
+ &inline_function_path,
+ turbo_fn.is_method(),
+ );
let native_function_ident = get_trait_default_impl_function_ident(trait_ident, ident);
let native_function_ty = native_function.ty();
diff --git a/crates/turbo-tasks-memory/src/memory_backend.rs b/crates/turbo-tasks-memory/src/memory_backend.rs
index ac002ca4510e3..099b74d566e98 100644
--- a/crates/turbo-tasks-memory/src/memory_backend.rs
+++ b/crates/turbo-tasks-memory/src/memory_backend.rs
@@ -539,10 +539,12 @@ impl Backend for MemoryBackend {
self.task_statistics().map(|stats| match &*task_type {
PersistentTaskType::ResolveNative {
fn_type: function_id,
+ this: _,
args: _,
}
| PersistentTaskType::Native {
fn_type: function_id,
+ this: _,
args: _,
} => {
stats.increment_cache_hit(*function_id);
@@ -550,9 +552,10 @@ impl Backend for MemoryBackend {
PersistentTaskType::ResolveTrait {
trait_type,
method_name: name,
- args: inputs,
+ this,
+ args: _,
} => {
- // HACK: Resolve the first argument (`self`) in order to attribute the cache hit
+ // HACK: Resolve the this argument (`self`) in order to attribute the cache hit
// to the concrete trait implementation, rather than the dynamic trait method.
// This ensures cache hits and misses are both attributed to the same thing.
//
@@ -567,10 +570,7 @@ impl Backend for MemoryBackend {
// ResolveTrait tasks.
let trait_type = *trait_type;
let name = name.clone();
- let this = inputs
- .first()
- .cloned()
- .expect("No arguments for trait call");
+ let this = *this;
let stats = Arc::clone(stats);
turbo_tasks.run_once(Box::pin(async move {
let function_id =
@@ -586,6 +586,7 @@ impl Backend for MemoryBackend {
self.task_statistics().map(|stats| match &*task_type {
PersistentTaskType::Native {
fn_type: function_id,
+ this: _,
args: _,
} => {
stats.increment_cache_miss(*function_id);
diff --git a/crates/turbo-tasks-memory/src/task.rs b/crates/turbo-tasks-memory/src/task.rs
index b56c4dae65f76..c7f5863390a01 100644
--- a/crates/turbo-tasks-memory/src/task.rs
+++ b/crates/turbo-tasks-memory/src/task.rs
@@ -557,12 +557,14 @@ impl Task {
TaskTypeForDescription::Persistent(ty) => match &***ty {
PersistentTaskType::Native {
fn_type: native_fn,
+ this: _,
args: _,
} => {
format!("[{}] {}", id, registry::get_function(*native_fn).name)
}
PersistentTaskType::ResolveNative {
fn_type: native_fn,
+ this: _,
args: _,
} => {
format!(
@@ -574,6 +576,7 @@ impl Task {
PersistentTaskType::ResolveTrait {
trait_type,
method_name: fn_name,
+ this: _,
args: _,
} => {
format!(
@@ -722,18 +725,20 @@ impl Task {
TaskType::Persistent { ty, .. } => match &***ty {
PersistentTaskType::Native {
fn_type: native_fn,
+ this,
args: inputs,
} => {
let func = registry::get_function(*native_fn);
let span = func.span();
let entered = span.enter();
- let bound_fn = func.bind(inputs);
+ let bound_fn = func.bind(*this, inputs);
let future = bound_fn();
drop(entered);
(future, span)
}
PersistentTaskType::ResolveNative {
fn_type: ref native_fn_id,
+ this,
args: inputs,
} => {
let native_fn_id = *native_fn_id;
@@ -744,6 +749,7 @@ impl Task {
let turbo_tasks = turbo_tasks.pin();
let future = Box::pin(PersistentTaskType::run_resolve_native(
native_fn_id,
+ *this,
inputs,
turbo_tasks,
));
@@ -753,6 +759,7 @@ impl Task {
PersistentTaskType::ResolveTrait {
trait_type: trait_type_id,
method_name: name,
+ this,
args: inputs,
} => {
let trait_type_id = *trait_type_id;
@@ -765,6 +772,7 @@ impl Task {
let future = Box::pin(PersistentTaskType::run_resolve_trait(
trait_type_id,
name,
+ *this,
inputs,
turbo_tasks,
));
diff --git a/crates/turbo-tasks-memory/tests/call_types.rs b/crates/turbo-tasks-memory/tests/call_types.rs
new file mode 100644
index 0000000000000..c5e2d7f3168ea
--- /dev/null
+++ b/crates/turbo-tasks-memory/tests/call_types.rs
@@ -0,0 +1,184 @@
+#![feature(arbitrary_self_types)]
+
+use anyhow::Result;
+use turbo_tasks::Vc;
+use turbo_tasks_testing::{register, run};
+
+register!();
+
+#[tokio::test]
+async fn functions() {
+ run! {
+ assert_eq!(*fn_plain().await?, 42);
+ assert_eq!(*fn_arg(43).await?, 43);
+ assert_eq!(*fn_vc_arg(Vc::cell(44)).await?, 44);
+ assert_eq!(*async_fn_plain().await?, 42);
+ assert_eq!(*async_fn_arg(43).await?, 43);
+ assert_eq!(*async_fn_vc_arg(Vc::cell(44)).await?, 44);
+ }
+}
+
+#[turbo_tasks::function]
+fn fn_plain() -> Vc {
+ Vc::cell(42)
+}
+
+#[turbo_tasks::function]
+fn fn_arg(n: u32) -> Vc {
+ Vc::cell(n)
+}
+
+#[turbo_tasks::function]
+fn fn_vc_arg(n: Vc) -> Vc {
+ n
+}
+
+#[turbo_tasks::function]
+async fn async_fn_plain() -> Result> {
+ Ok(Vc::cell(42))
+}
+
+#[turbo_tasks::function]
+async fn async_fn_arg(n: u32) -> Result> {
+ Ok(Vc::cell(n))
+}
+
+#[turbo_tasks::function]
+async fn async_fn_vc_arg(n: Vc) -> Result> {
+ Ok(Vc::cell(*n.await?))
+}
+
+#[tokio::test]
+async fn methods() {
+ run! {
+ assert_eq!(*Value::static_method().await?, 42);
+ assert_eq!(*Value::async_static_method().await?, 42);
+
+ let value = Value(43).cell();
+ assert_eq!(*value.method().await?, 43);
+ assert_eq!(*value.async_method().await?, 43);
+ assert_eq!(*value.vc_method().await?, 42);
+ assert_eq!(*value.async_vc_method().await?, 43);
+ }
+}
+
+#[turbo_tasks::value]
+struct Value(u32);
+
+#[turbo_tasks::value_impl]
+impl Value {
+ #[turbo_tasks::function]
+ fn static_method() -> Vc {
+ Vc::cell(42)
+ }
+
+ #[turbo_tasks::function]
+ async fn async_static_method() -> Result> {
+ Ok(Vc::cell(42))
+ }
+
+ #[turbo_tasks::function]
+ fn method(&self) -> Vc {
+ Vc::cell(self.0)
+ }
+
+ #[turbo_tasks::function]
+ async fn async_method(&self) -> Result> {
+ Ok(Vc::cell(self.0))
+ }
+
+ #[turbo_tasks::function]
+ fn vc_method(self: Vc) -> Vc {
+ Vc::cell(42)
+ }
+
+ #[turbo_tasks::function]
+ async fn async_vc_method(self: Vc) -> Result> {
+ Ok(Vc::cell(self.await?.0))
+ }
+}
+
+#[tokio::test]
+async fn trait_methods() {
+ run! {
+ assert_eq!(*Value::static_trait_method().await?, 42);
+ assert_eq!(*Value::async_static_trait_method().await?, 42);
+
+ let value = Value(43).cell();
+ assert_eq!(*value.trait_method().await?, 43);
+ assert_eq!(*value.async_trait_method().await?, 43);
+ assert_eq!(*value.default_trait_method().await?, 42);
+ assert_eq!(*value.default_async_trait_method().await?, 42);
+
+ let trait_value: Vc> = Vc::upcast(value);
+ assert_eq!(*trait_value.trait_method().await?, 43);
+ assert_eq!(*trait_value.async_trait_method().await?, 43);
+ assert_eq!(*trait_value.default_trait_method().await?, 42);
+ assert_eq!(*trait_value.default_async_trait_method().await?, 42);
+
+ let value = wrap_value(value);
+ assert_eq!(*value.trait_method().await?, 43);
+ assert_eq!(*value.async_trait_method().await?, 43);
+ assert_eq!(*value.default_trait_method().await?, 42);
+ assert_eq!(*value.default_async_trait_method().await?, 42);
+
+ let trait_value = wrap_trait_value(trait_value);
+ assert_eq!(*trait_value.trait_method().await?, 43);
+ assert_eq!(*trait_value.async_trait_method().await?, 43);
+ assert_eq!(*trait_value.default_trait_method().await?, 42);
+ assert_eq!(*trait_value.default_async_trait_method().await?, 42);
+ }
+}
+
+#[turbo_tasks::function]
+fn wrap_value(v: Vc) -> Vc {
+ v
+}
+
+#[turbo_tasks::function]
+fn wrap_trait_value(v: Vc>) -> Vc> {
+ v
+}
+
+#[turbo_tasks::value_trait]
+trait ValueTrait {
+ fn static_trait_method() -> Vc;
+ async fn async_static_trait_method() -> Result>;
+ fn default_static_trait_method() -> Vc {
+ Vc::cell(42)
+ }
+ async fn default_async_static_trait_method() -> Result> {
+ Ok(Vc::cell(42))
+ }
+ fn trait_method(&self) -> Vc;
+ fn async_trait_method(&self) -> Result>;
+ fn default_trait_method(self: Vc) -> Vc {
+ Vc::cell(42)
+ }
+ async fn default_async_trait_method(self: Vc) -> Result> {
+ Ok(Vc::cell(42))
+ }
+}
+
+#[turbo_tasks::value_impl]
+impl ValueTrait for Value {
+ #[turbo_tasks::function]
+ fn static_trait_method() -> Vc {
+ Vc::cell(42)
+ }
+
+ #[turbo_tasks::function]
+ async fn async_static_trait_method() -> Result> {
+ Ok(Vc::cell(42))
+ }
+
+ #[turbo_tasks::function]
+ fn trait_method(&self) -> Vc {
+ Vc::cell(self.0)
+ }
+
+ #[turbo_tasks::function]
+ async fn async_trait_method(&self) -> Result> {
+ Ok(Vc::cell(self.0))
+ }
+}
diff --git a/crates/turbo-tasks-testing/src/lib.rs b/crates/turbo-tasks-testing/src/lib.rs
index da406efdfb645..7224e7db52fc9 100644
--- a/crates/turbo-tasks-testing/src/lib.rs
+++ b/crates/turbo-tasks-testing/src/lib.rs
@@ -36,14 +36,15 @@ pub struct VcStorage {
tasks: Mutex>,
}
-impl TurboTasksCallApi for VcStorage {
+impl VcStorage {
fn dynamic_call(
&self,
func: turbo_tasks::FunctionId,
+ this_arg: Option,
inputs: Vec,
) -> RawVc {
let this = self.this.upgrade().unwrap();
- let func = registry::get_function(func).bind(&inputs);
+ let func = registry::get_function(func).bind(this_arg, &inputs);
let handle = tokio::runtime::Handle::current();
let future = func();
let i = {
@@ -77,6 +78,25 @@ impl TurboTasksCallApi for VcStorage {
}));
RawVc::TaskOutput(id)
}
+}
+
+impl TurboTasksCallApi for VcStorage {
+ fn dynamic_call(
+ &self,
+ func: turbo_tasks::FunctionId,
+ inputs: Vec,
+ ) -> RawVc {
+ self.dynamic_call(func, None, inputs)
+ }
+
+ fn dynamic_this_call(
+ &self,
+ func: turbo_tasks::FunctionId,
+ this_arg: RawVc,
+ inputs: Vec,
+ ) -> RawVc {
+ self.dynamic_call(func, Some(this_arg), inputs)
+ }
fn native_call(
&self,
@@ -86,10 +106,20 @@ impl TurboTasksCallApi for VcStorage {
unreachable!()
}
+ fn this_call(
+ &self,
+ _func: turbo_tasks::FunctionId,
+ _this: RawVc,
+ _inputs: Vec,
+ ) -> RawVc {
+ unreachable!()
+ }
+
fn trait_call(
&self,
_trait_type: turbo_tasks::TraitTypeId,
_trait_fn_name: Cow<'static, str>,
+ _this: RawVc,
_inputs: Vec,
) -> RawVc {
unreachable!()
diff --git a/crates/turbo-tasks/src/backend.rs b/crates/turbo-tasks/src/backend.rs
index 38a81bf50042c..ba0604a44c115 100644
--- a/crates/turbo-tasks/src/backend.rs
+++ b/crates/turbo-tasks/src/backend.rs
@@ -17,9 +17,13 @@ use tracing::Span;
pub use crate::id::BackendJobId;
use crate::{
- event::EventListener, manager::TurboTasksBackendApi, raw_vc::CellId, registry,
+ event::EventListener,
+ manager::TurboTasksBackendApi,
+ raw_vc::CellId,
+ registry,
+ trait_helpers::{get_trait_method, has_trait, traits},
ConcreteTaskInput, FunctionId, RawVc, ReadRef, SharedReference, TaskId, TaskIdProvider,
- TaskIdSet, TraitRef, TraitTypeId, VcValueTrait, VcValueType,
+ TaskIdSet, TraitRef, TraitTypeId, ValueTypeId, VcValueTrait, VcValueType,
};
pub enum TaskType {
@@ -66,6 +70,7 @@ pub enum PersistentTaskType {
/// A normal task execution a native (rust) function
Native {
fn_type: FunctionId,
+ this: Option,
args: Vec,
},
@@ -73,6 +78,7 @@ pub enum PersistentTaskType {
/// resolve arguments. The inner function call will do a cache lookup.
ResolveNative {
fn_type: FunctionId,
+ this: Option,
args: Vec,
},
@@ -83,6 +89,7 @@ pub enum PersistentTaskType {
ResolveTrait {
trait_type: TraitTypeId,
method_name: Cow<'static, str>,
+ this: RawVc,
args: Vec,
},
}
@@ -98,15 +105,18 @@ impl PersistentTaskType {
match self {
Self::Native {
fn_type: _,
+ this: _,
args: inputs,
} => inputs.shrink_to_fit(),
Self::ResolveNative {
fn_type: _,
+ this: _,
args: inputs,
} => inputs.shrink_to_fit(),
Self::ResolveTrait {
trait_type: _,
method_name: _,
+ this: _,
args: inputs,
} => inputs.shrink_to_fit(),
}
@@ -116,15 +126,18 @@ impl PersistentTaskType {
match self {
PersistentTaskType::Native {
fn_type: _,
+ this: _,
args: v,
}
| PersistentTaskType::ResolveNative {
fn_type: _,
+ this: _,
args: v,
}
| PersistentTaskType::ResolveTrait {
trait_type: _,
method_name: _,
+ this: _,
args: v,
} => v.len(),
}
@@ -134,15 +147,18 @@ impl PersistentTaskType {
match self {
PersistentTaskType::Native {
fn_type: _,
+ this: _,
args: v,
}
| PersistentTaskType::ResolveNative {
fn_type: _,
+ this: _,
args: v,
}
| PersistentTaskType::ResolveTrait {
trait_type: _,
method_name: _,
+ this: _,
args: v,
} => v.is_empty(),
}
@@ -152,25 +168,31 @@ impl PersistentTaskType {
match self {
PersistentTaskType::Native {
fn_type: f,
+ this,
args: v,
} => PersistentTaskType::Native {
fn_type: *f,
+ this: *this,
args: v[..len].to_vec(),
},
PersistentTaskType::ResolveNative {
fn_type: f,
+ this,
args: v,
} => PersistentTaskType::ResolveNative {
fn_type: *f,
+ this: *this,
args: v[..len].to_vec(),
},
PersistentTaskType::ResolveTrait {
trait_type: f,
method_name: n,
+ this,
args: v,
} => PersistentTaskType::ResolveTrait {
trait_type: *f,
method_name: n.clone(),
+ this: *this,
args: v[..len].to_vec(),
},
}
@@ -185,15 +207,18 @@ impl PersistentTaskType {
match self {
PersistentTaskType::Native {
fn_type: native_fn,
+ this: _,
args: _,
}
| PersistentTaskType::ResolveNative {
fn_type: native_fn,
+ this: _,
args: _,
} => Cow::Borrowed(®istry::get_function(*native_fn).name),
PersistentTaskType::ResolveTrait {
trait_type: trait_id,
method_name: fn_name,
+ this: _,
args: _,
} => format!("{}::{}", registry::get_trait(*trait_id).name, fn_name).into(),
}
@@ -424,83 +449,82 @@ pub trait Backend: Sync + Send {
impl PersistentTaskType {
pub async fn run_resolve_native(
fn_id: FunctionId,
+ mut this: Option,
mut inputs: Vec,
turbo_tasks: Arc>,
) -> Result {
- for i in 0..inputs.len() {
- let input = unsafe { take(inputs.get_unchecked_mut(i)) };
- let input = input.resolve().await?;
- unsafe {
- *inputs.get_unchecked_mut(i) = input;
- }
+ if let Some(this) = this.as_mut() {
+ *this = this.resolve().await?;
+ }
+ for input in inputs.iter_mut() {
+ *input = take(input).resolve().await?;
}
- Ok(turbo_tasks.native_call(fn_id, inputs))
+ Ok(if let Some(this) = this {
+ turbo_tasks.this_call(fn_id, this, inputs)
+ } else {
+ turbo_tasks.native_call(fn_id, inputs)
+ })
}
pub async fn resolve_trait_method(
trait_type: TraitTypeId,
name: Cow<'static, str>,
- this: ConcreteTaskInput,
+ this: RawVc,
) -> Result {
- Self::resolve_trait_method_from_value(
- trait_type,
- this.resolve().await?.resolve_to_value().await?,
- name,
- )
+ let CellContent(Some(SharedReference(Some(value_type), _))) = this.into_read().await?
+ else {
+ bail!("Cell is empty or untyped");
+ };
+ Self::resolve_trait_method_from_value(trait_type, value_type, name)
}
pub async fn run_resolve_trait(
trait_type: TraitTypeId,
name: Cow<'static, str>,
- inputs: Vec,
+ this: RawVc,
+ mut inputs: Vec,
turbo_tasks: Arc>,
) -> Result {
- let mut resolved_inputs = Vec::with_capacity(inputs.len());
- let mut iter = inputs.into_iter();
-
- let this = iter
- .next()
- .expect("No arguments for trait call")
- .resolve()
- .await?;
- let this_value = this.clone().resolve_to_value().await?;
-
- let native_fn = Self::resolve_trait_method_from_value(trait_type, this_value, name)?;
- resolved_inputs.push(this);
- for input in iter {
- resolved_inputs.push(input)
+ 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 native_fn = Self::resolve_trait_method_from_value(trait_type, this_ty, name)?;
+ for input in inputs.iter_mut() {
+ *input = take(input).resolve().await?;
}
- Ok(turbo_tasks.dynamic_call(native_fn, resolved_inputs))
+ Ok(turbo_tasks.dynamic_this_call(native_fn, this, inputs))
}
/// Shared helper used by [`Self::resolve_trait_method`] and
/// [`Self::run_resolve_trait`].
fn resolve_trait_method_from_value(
trait_type: TraitTypeId,
- this_value: ConcreteTaskInput,
+ value_type: ValueTypeId,
name: Cow<'static, str>,
) -> Result {
- match this_value.get_trait_method(trait_type, name) {
+ match get_trait_method(trait_type, value_type, name) {
Ok(native_fn) => Ok(native_fn),
Err(name) => {
- if !this_value.has_trait(trait_type) {
- let traits = this_value
- .traits()
- .iter()
- .fold(String::new(), |mut out, t| {
- let _ = write!(out, " {}", t);
- out
- });
+ if !has_trait(value_type, trait_type) {
+ let traits = traits(value_type).iter().fold(String::new(), |mut out, t| {
+ let _ = write!(out, " {}", t);
+ out
+ });
Err(anyhow!(
"{} doesn't implement {} (only{})",
- this_value,
+ registry::get_value_type(value_type),
registry::get_trait(trait_type),
traits,
))
} else {
Err(anyhow!(
"{} implements trait {}, but method {} is missing",
- this_value,
+ registry::get_value_type(value_type),
registry::get_trait(trait_type),
name
))
@@ -516,23 +540,27 @@ impl PersistentTaskType {
match self {
PersistentTaskType::Native {
fn_type: fn_id,
+ this,
args: inputs,
} => {
let native_fn = registry::get_function(fn_id);
- let bound = native_fn.bind(&inputs);
+ let bound = native_fn.bind(this, &inputs);
(bound)()
}
PersistentTaskType::ResolveNative {
fn_type: fn_id,
+ this,
args: inputs,
- } => Box::pin(Self::run_resolve_native(fn_id, inputs, turbo_tasks)),
+ } => Box::pin(Self::run_resolve_native(fn_id, this, inputs, turbo_tasks)),
PersistentTaskType::ResolveTrait {
trait_type,
method_name: name,
+ this,
args: inputs,
} => Box::pin(Self::run_resolve_trait(
trait_type,
name,
+ this,
inputs,
turbo_tasks,
)),
@@ -561,6 +589,7 @@ pub(crate) mod tests {
assert_eq!(
PersistentTaskType::Native {
fn_type: *MOCK_FUNC_TASK_FUNCTION_ID,
+ this: None,
args: Vec::new()
}
.get_name(),
@@ -570,6 +599,7 @@ pub(crate) mod tests {
PersistentTaskType::ResolveTrait {
trait_type: *MOCKTRAIT_TRAIT_TYPE_ID,
method_name: "mock_method_task".into(),
+ this: RawVc::TaskOutput(unsafe { TaskId::new_unchecked(1) }),
args: Vec::new()
}
.get_name(),
diff --git a/crates/turbo-tasks/src/lib.rs b/crates/turbo-tasks/src/lib.rs
index 84c107c055aff..b5aa822a019c4 100644
--- a/crates/turbo-tasks/src/lib.rs
+++ b/crates/turbo-tasks/src/lib.rs
@@ -67,6 +67,7 @@ pub mod small_duration;
mod state;
pub mod task;
pub mod trace;
+mod trait_helpers;
mod trait_ref;
mod triomphe_utils;
pub mod util;
@@ -88,10 +89,10 @@ pub use invalidation::{
pub use join_iter_ext::{JoinIterExt, TryFlatJoinIterExt, TryJoinIterExt};
pub use keyed_cell::{global_keyed_cell, keyed_cell};
pub use manager::{
- dynamic_call, emit, get_invalidator, mark_finished, mark_stateful, prevent_gc, run_once,
- run_once_with_reason, spawn_blocking, spawn_thread, trait_call, turbo_tasks, CurrentCellRef,
- Invalidator, TaskIdProvider, TurboTasks, TurboTasksApi, TurboTasksBackendApi,
- TurboTasksCallApi, Unused, UpdateInfo,
+ dynamic_call, dynamic_this_call, emit, get_invalidator, mark_finished, mark_stateful,
+ prevent_gc, run_once, run_once_with_reason, spawn_blocking, spawn_thread, trait_call,
+ turbo_tasks, CurrentCellRef, Invalidator, TaskIdProvider, TurboTasks, TurboTasksApi,
+ TurboTasksBackendApi, TurboTasksCallApi, Unused, UpdateInfo,
};
pub use native_function::NativeFunction;
pub use raw_vc::{CellId, RawVc, ReadRawVcFuture, ResolveTypeError};
diff --git a/crates/turbo-tasks/src/manager.rs b/crates/turbo-tasks/src/manager.rs
index 28bb8c316126d..d810c1366f061 100644
--- a/crates/turbo-tasks/src/manager.rs
+++ b/crates/turbo-tasks/src/manager.rs
@@ -30,8 +30,8 @@ use crate::{
id::{BackendJobId, FunctionId, TraitTypeId},
id_factory::IdFactory,
raw_vc::{CellId, RawVc},
- registry,
trace::TraceRawVcs,
+ trait_helpers::get_trait_method,
util::StaticOrArc,
vc::ReadVcFuture,
Completion, ConcreteTaskInput, InvalidationReason, InvalidationReasonSet, SharedReference,
@@ -40,11 +40,19 @@ use crate::{
pub trait TurboTasksCallApi: Sync + Send {
fn dynamic_call(&self, func: FunctionId, inputs: Vec) -> RawVc;
+ fn dynamic_this_call(
+ &self,
+ func: FunctionId,
+ this: RawVc,
+ inputs: Vec,
+ ) -> RawVc;
fn native_call(&self, func: FunctionId, inputs: Vec) -> RawVc;
+ fn this_call(&self, func: FunctionId, this: RawVc, inputs: Vec) -> RawVc;
fn trait_call(
&self,
trait_type: TraitTypeId,
trait_fn_name: Cow<'static, str>,
+ this: RawVc,
inputs: Vec,
) -> RawVc;
@@ -371,6 +379,26 @@ impl TurboTasks {
RawVc::TaskOutput(self.backend.get_or_create_persistent_task(
PersistentTaskType::Native {
fn_type: func,
+ this: None,
+ args: inputs,
+ },
+ current_task("turbo_function calls"),
+ self,
+ ))
+ }
+
+ /// Call a native function with arguments.
+ /// All inputs must be resolved.
+ pub(crate) fn this_call(
+ &self,
+ func: FunctionId,
+ this: RawVc,
+ inputs: Vec,
+ ) -> RawVc {
+ RawVc::TaskOutput(self.backend.get_or_create_persistent_task(
+ PersistentTaskType::Native {
+ fn_type: func,
+ this: Some(this),
args: inputs,
},
current_task("turbo_function calls"),
@@ -387,6 +415,30 @@ impl TurboTasks {
RawVc::TaskOutput(self.backend.get_or_create_persistent_task(
PersistentTaskType::ResolveNative {
fn_type: func,
+ this: None,
+ args: inputs,
+ },
+ current_task("turbo_function calls"),
+ self,
+ ))
+ }
+ }
+
+ /// Calls a native function with arguments. Resolves arguments when needed
+ /// with a wrapper task.
+ pub fn dynamic_this_call(
+ &self,
+ func: FunctionId,
+ this: RawVc,
+ inputs: Vec,
+ ) -> RawVc {
+ if this.is_resolved() && inputs.iter().all(|i| i.is_resolved()) {
+ self.this_call(func, this, inputs)
+ } else {
+ RawVc::TaskOutput(self.backend.get_or_create_persistent_task(
+ PersistentTaskType::ResolveNative {
+ fn_type: func,
+ this: Some(this),
args: inputs,
},
current_task("turbo_function calls"),
@@ -401,19 +453,21 @@ impl TurboTasks {
&self,
trait_type: TraitTypeId,
mut trait_fn_name: Cow<'static, str>,
+ this: RawVc,
inputs: Vec,
) -> RawVc {
// avoid creating a wrapper task if self is already resolved
// for resolved cells we already know the value type so we can lookup the
// function
- let first_input = inputs.first().expect("trait call without self argument");
- if let &ConcreteTaskInput::TaskCell(_, CellId { type_id, .. }) = first_input {
- let value_type = registry::get_value_type(type_id);
- let key = (trait_type, trait_fn_name);
- if let Some(native_fn) = value_type.get_trait_method(&key) {
- return self.dynamic_call(*native_fn, inputs);
+ if let RawVc::TaskCell(_, CellId { type_id, .. }) = this {
+ match get_trait_method(trait_type, type_id, trait_fn_name) {
+ Ok(native_fn) => {
+ return self.dynamic_this_call(native_fn, this, inputs);
+ }
+ Err(name) => {
+ trait_fn_name = name;
+ }
}
- trait_fn_name = key.1;
}
// create a wrapper task to resolve all inputs
@@ -421,6 +475,7 @@ impl TurboTasks {
PersistentTaskType::ResolveTrait {
trait_type,
method_name: trait_fn_name,
+ this,
args: inputs,
},
current_task("turbo_function calls"),
@@ -804,16 +859,28 @@ impl TurboTasksCallApi for TurboTasks {
fn dynamic_call(&self, func: FunctionId, inputs: Vec) -> RawVc {
self.dynamic_call(func, inputs)
}
+ fn dynamic_this_call(
+ &self,
+ func: FunctionId,
+ this: RawVc,
+ inputs: Vec,
+ ) -> RawVc {
+ self.dynamic_this_call(func, this, inputs)
+ }
fn native_call(&self, func: FunctionId, inputs: Vec) -> RawVc {
self.native_call(func, inputs)
}
+ fn this_call(&self, func: FunctionId, this: RawVc, inputs: Vec) -> RawVc {
+ self.this_call(func, this, inputs)
+ }
fn trait_call(
&self,
trait_type: TraitTypeId,
trait_fn_name: Cow<'static, str>,
+ this: RawVc,
inputs: Vec,
) -> RawVc {
- self.trait_call(trait_type, trait_fn_name, inputs)
+ self.trait_call(trait_type, trait_fn_name, this, inputs)
}
#[track_caller]
@@ -1292,13 +1359,20 @@ pub fn dynamic_call(func: FunctionId, inputs: Vec) -> RawVc {
with_turbo_tasks(|tt| tt.dynamic_call(func, inputs))
}
+/// Calls [`TurboTasks::dynamic_this_call`] for the current turbo tasks
+/// instance.
+pub fn dynamic_this_call(func: FunctionId, this: RawVc, inputs: Vec) -> RawVc {
+ with_turbo_tasks(|tt| tt.dynamic_this_call(func, this, inputs))
+}
+
/// Calls [`TurboTasks::trait_call`] for the current turbo tasks instance.
pub fn trait_call(
trait_type: TraitTypeId,
trait_fn_name: Cow<'static, str>,
+ this: RawVc,
inputs: Vec,
) -> RawVc {
- with_turbo_tasks(|tt| tt.trait_call(trait_type, trait_fn_name, inputs))
+ with_turbo_tasks(|tt| tt.trait_call(trait_type, trait_fn_name, this, inputs))
}
pub fn turbo_tasks() -> Arc {
diff --git a/crates/turbo-tasks/src/native_function.rs b/crates/turbo-tasks/src/native_function.rs
index 1a17956222596..c43910288fc99 100644
--- a/crates/turbo-tasks/src/native_function.rs
+++ b/crates/turbo-tasks/src/native_function.rs
@@ -3,10 +3,14 @@ use std::{fmt::Debug, hash::Hash};
use tracing::Span;
use crate::{
+ self as turbo_tasks,
registry::register_function,
- task::{function::NativeTaskFn, IntoTaskFn, TaskFn},
+ task::{
+ function::{IntoTaskFnWithThis, NativeTaskFn},
+ IntoTaskFn, TaskFn,
+ },
util::SharedError,
- ConcreteTaskInput, {self as turbo_tasks},
+ ConcreteTaskInput, RawVc,
};
/// A native (rust) turbo-tasks function. It's used internally by
@@ -30,7 +34,7 @@ impl Debug for NativeFunction {
}
impl NativeFunction {
- pub fn new(name: String, implementation: I) -> Self
+ pub fn new_function(name: String, implementation: I) -> Self
where
I: IntoTaskFn,
{
@@ -40,9 +44,19 @@ impl NativeFunction {
}
}
+ pub fn new_method(name: String, implementation: I) -> Self
+ where
+ I: IntoTaskFnWithThis,
+ {
+ Self {
+ name,
+ implementation: Box::new(implementation.into_task_fn_with_this()),
+ }
+ }
+
/// Creates a functor for execution from a fixed set of inputs.
- pub fn bind(&'static self, inputs: &[ConcreteTaskInput]) -> NativeTaskFn {
- match (self.implementation).functor(inputs) {
+ pub fn bind(&'static self, this: Option, inputs: &[ConcreteTaskInput]) -> NativeTaskFn {
+ match (self.implementation).functor(this, inputs) {
Ok(functor) => functor,
Err(err) => {
let err = SharedError::new(err);
diff --git a/crates/turbo-tasks/src/raw_vc.rs b/crates/turbo-tasks/src/raw_vc.rs
index e36b2894626ea..50c4a8ed16c3f 100644
--- a/crates/turbo-tasks/src/raw_vc.rs
+++ b/crates/turbo-tasks/src/raw_vc.rs
@@ -59,6 +59,13 @@ pub enum RawVc {
}
impl RawVc {
+ pub(crate) fn is_resolved(&self) -> bool {
+ match self {
+ RawVc::TaskOutput(_) => false,
+ RawVc::TaskCell(_, _) => true,
+ }
+ }
+
pub(crate) fn into_read(self) -> ReadRawVcFuture {
// returns a custom future to have something concrete and sized
// this avoids boxing in IntoFuture
diff --git a/crates/turbo-tasks/src/task/concrete_task_input.rs b/crates/turbo-tasks/src/task/concrete_task_input.rs
index 8f0a94693c918..e0982858c744a 100644
--- a/crates/turbo-tasks/src/task/concrete_task_input.rs
+++ b/crates/turbo-tasks/src/task/concrete_task_input.rs
@@ -1,6 +1,5 @@
use std::{
any::Any,
- borrow::Cow,
fmt::{Debug, Display},
future::Future,
hash::Hash,
@@ -14,12 +13,11 @@ use unsize::CoerceUnsize;
use crate::{
backend::CellContent,
- id::{FunctionId, TraitTypeId},
magic_any::MagicAny,
manager::{read_task_cell, read_task_output},
registry,
triomphe_utils::{coerce_to_any_send_sync, downcast_triomphe_arc},
- turbo_tasks, CellId, RawVc, RcStr, TaskId, TraitType, ValueTypeId,
+ turbo_tasks, CellId, RawVc, RcStr, TaskId, ValueTypeId,
};
/// A type-erased wrapper for [`triomphe::Arc`].
@@ -405,74 +403,6 @@ impl ConcreteTaskInput {
}
}
- pub fn get_trait_method(
- &self,
- trait_type: TraitTypeId,
- name: Cow<'static, str>,
- ) -> Result> {
- match self {
- ConcreteTaskInput::TaskOutput(_) | ConcreteTaskInput::TaskCell(_, _) => {
- panic!("get_trait_method must be called on a resolved TaskInput")
- }
- ConcreteTaskInput::SharedValue(SharedValue(ty, _))
- | ConcreteTaskInput::SharedReference(SharedReference(ty, _)) => {
- if let Some(ty) = *ty {
- let key = (trait_type, name);
- if let Some(func) = registry::get_value_type(ty).get_trait_method(&key) {
- Ok(*func)
- } else if let Some(func) = registry::get_trait(trait_type)
- .default_trait_methods
- .get(&key.1)
- {
- Ok(*func)
- } else {
- Err(key.1)
- }
- } else {
- Err(name)
- }
- }
- _ => Err(name),
- }
- }
-
- pub fn has_trait(&self, trait_type: TraitTypeId) -> bool {
- match self {
- ConcreteTaskInput::TaskOutput(_) | ConcreteTaskInput::TaskCell(_, _) => {
- panic!("has_trait() must be called on a resolved TaskInput")
- }
- ConcreteTaskInput::SharedValue(SharedValue(ty, _))
- | ConcreteTaskInput::SharedReference(SharedReference(ty, _)) => {
- if let Some(ty) = *ty {
- registry::get_value_type(ty).has_trait(&trait_type)
- } else {
- false
- }
- }
- _ => false,
- }
- }
-
- pub fn traits(&self) -> Vec<&'static TraitType> {
- match self {
- ConcreteTaskInput::TaskOutput(_) | ConcreteTaskInput::TaskCell(_, _) => {
- panic!("traits() must be called on a resolved TaskInput")
- }
- ConcreteTaskInput::SharedValue(SharedValue(ty, _))
- | ConcreteTaskInput::SharedReference(SharedReference(ty, _)) => {
- if let Some(ty) = *ty {
- registry::get_value_type(ty)
- .traits_iter()
- .map(registry::get_trait)
- .collect()
- } else {
- Vec::new()
- }
- }
- _ => Vec::new(),
- }
- }
-
pub fn is_resolved(&self) -> bool {
match self {
ConcreteTaskInput::TaskOutput(_) => false,
diff --git a/crates/turbo-tasks/src/task/function.rs b/crates/turbo-tasks/src/task/function.rs
index c1bfcaac41e39..aa436bf6cef39 100644
--- a/crates/turbo-tasks/src/task/function.rs
+++ b/crates/turbo-tasks/src/task/function.rs
@@ -32,7 +32,7 @@ pub type NativeTaskFuture = Pin> + Send>>;
pub type NativeTaskFn = Box NativeTaskFuture + Send + Sync>;
pub trait TaskFn: Send + Sync + 'static {
- fn functor(&self, inputs: &[ConcreteTaskInput]) -> Result;
+ fn functor(&self, this: Option, inputs: &[ConcreteTaskInput]) -> Result;
}
pub trait IntoTaskFn {
@@ -58,6 +58,29 @@ where
}
}
+pub trait IntoTaskFnWithThis {
+ type TaskFn: TaskFn;
+
+ fn into_task_fn_with_this(self) -> Self::TaskFn;
+}
+
+impl IntoTaskFnWithThis for F
+where
+ F: TaskFnInputFunctionWithThis,
+ Mode: TaskFnMode,
+ Inputs: TaskInputs,
+{
+ type TaskFn = FunctionTaskFnWithThis;
+
+ fn into_task_fn_with_this(self) -> Self::TaskFn {
+ FunctionTaskFnWithThis {
+ task_fn: self,
+ mode: PhantomData,
+ inputs: PhantomData,
+ }
+ }
+}
+
pub struct FunctionTaskFn {
task_fn: F,
mode: PhantomData,
@@ -70,13 +93,36 @@ where
Mode: TaskFnMode,
Inputs: TaskInputs,
{
- fn functor(&self, inputs: &[ConcreteTaskInput]) -> Result {
- TaskFnInputFunction::functor(&self.task_fn, inputs)
+ fn functor(&self, this: Option, inputs: &[ConcreteTaskInput]) -> Result {
+ TaskFnInputFunction::functor(&self.task_fn, this, inputs)
+ }
+}
+
+pub struct FunctionTaskFnWithThis {
+ task_fn: F,
+ mode: PhantomData,
+ inputs: PhantomData,
+}
+
+impl TaskFn for FunctionTaskFnWithThis
+where
+ F: TaskFnInputFunctionWithThis,
+ Mode: TaskFnMode,
+ Inputs: TaskInputs,
+{
+ fn functor(&self, this: Option, inputs: &[ConcreteTaskInput]) -> Result {
+ TaskFnInputFunctionWithThis::functor(&self.task_fn, this, inputs)
}
}
trait TaskFnInputFunction: Send + Sync + Clone + 'static {
- fn functor(&self, inputs: &[ConcreteTaskInput]) -> Result;
+ fn functor(&self, this: Option, inputs: &[ConcreteTaskInput]) -> Result;
+}
+
+trait TaskFnInputFunctionWithThis:
+ Send + Sync + Clone + 'static
+{
+ fn functor(&self, this: Option, inputs: &[ConcreteTaskInput]) -> Result;
}
pub trait TaskInputs: Send + Sync + 'static {}
@@ -91,12 +137,12 @@ pub trait TaskFnMode: Send + Sync + 'static {}
pub struct FunctionMode;
impl TaskFnMode for FunctionMode {}
-pub struct MethodMode;
-impl TaskFnMode for MethodMode {}
-
pub struct AsyncFunctionMode;
impl TaskFnMode for AsyncFunctionMode {}
+pub struct MethodMode;
+impl TaskFnMode for MethodMode {}
+
pub struct AsyncMethodMode;
impl TaskFnMode for AsyncMethodMode {}
@@ -128,14 +174,6 @@ macro_rules! task_fn_impl {
get_args_iter(inputs.iter())
}
- pub fn get_method_args(
- inputs: &[ConcreteTaskInput],
- ) -> Result<(&ConcreteTaskInput, ($(&as_concrete_task_input!($arg),)*))> {
- let mut iter = inputs.iter();
- let recv = iter.next().context("task is missing receiver")?;
- Ok((recv, get_args_iter(iter)?))
- }
-
fn get_args_iter(
mut iter: std::slice::Iter<'_, ConcreteTaskInput>,
) -> Result<($(&as_concrete_task_input!($arg),)*)> {
@@ -154,7 +192,7 @@ macro_rules! task_fn_impl {
Output: TaskOutput + 'static,
{
#[allow(non_snake_case)]
- fn functor(&self, inputs: &[ConcreteTaskInput]) -> Result {
+ fn functor(&self, _this: Option, inputs: &[ConcreteTaskInput]) -> Result {
let ($($arg,)*) = $helper_module::get_args(inputs)?;
let task_fn = self.clone();
@@ -183,7 +221,7 @@ macro_rules! task_fn_impl {
Output: TaskOutput + 'static,
{
#[allow(non_snake_case)]
- fn functor(&self, inputs: &[ConcreteTaskInput]) -> Result {
+ fn functor(&self, _this: Option, inputs: &[ConcreteTaskInput]) -> Result {
let ($($arg,)*) = $helper_module::get_args(inputs)?;
let task_fn = self.clone();
@@ -204,7 +242,7 @@ macro_rules! task_fn_impl {
}
}
- impl TaskFnInputFunction, $($arg,)*)> for F
+ impl TaskFnInputFunctionWithThis, $($arg,)*)> for F
where
Recv: VcValueType,
$($arg: TaskInput + 'static,)*
@@ -212,18 +250,17 @@ macro_rules! task_fn_impl {
Output: TaskOutput + 'static,
{
#[allow(non_snake_case)]
- fn functor(&self, inputs: &[ConcreteTaskInput]) -> Result {
- let (recv, ($($arg,)*)) = $helper_module::get_method_args(inputs)?;
-
+ fn functor(&self, this: Option, inputs: &[ConcreteTaskInput]) -> Result {
let task_fn = self.clone();
- let recv = Vc::::try_from_concrete(recv)?;
+ let recv = Vc::::from(this.expect("Method need to have a `self` argument"));
+
+ let ($($arg,)*) = $helper_module::get_args(inputs)?;
$(
let $arg = $arg::try_from_concrete($arg)?;
)*
Ok(Box::new(move || {
let task_fn = task_fn.clone();
- let recv = recv.clone();
$(
let $arg = $arg.clone();
)*
@@ -237,6 +274,36 @@ macro_rules! task_fn_impl {
}
}
+ impl TaskFnInputFunctionWithThis, $($arg,)*)> for F
+ where
+ Recv: Send + 'static,
+ $($arg: TaskInput + 'static,)*
+ F: Fn(Vc, $($arg,)*) -> Output + Send + Sync + Clone + 'static,
+ Output: TaskOutput + 'static,
+ {
+ #[allow(non_snake_case)]
+ fn functor(&self, this: Option, inputs: &[ConcreteTaskInput]) -> Result {
+ let task_fn = self.clone();
+ let recv = Vc::::from(this.expect("Method need to have a `self` argument"));
+
+ let ($($arg,)*) = $helper_module::get_args(inputs)?;
+ $(
+ let $arg = $arg::try_from_concrete($arg)?;
+ )*
+
+ Ok(Box::new(move || {
+ let task_fn = task_fn.clone();
+ $(
+ let $arg = $arg.clone();
+ )*
+
+ Box::pin(async move {
+ Output::try_into_raw_vc((task_fn)(recv, $($arg),*))
+ })
+ }))
+ }
+ }
+
pub trait $async_fn_trait: Fn(A0, $($arg,)*) -> Self::OutputFuture {
type OutputFuture: Future