turbo_tasks/vc/mod.rs
1pub(crate) mod cast;
2mod cell_mode;
3pub(crate) mod default;
4mod local;
5pub(crate) mod operation;
6mod read;
7pub(crate) mod resolved;
8mod traits;
9
10use std::{
11 any::Any,
12 fmt::Debug,
13 future::{Future, IntoFuture},
14 hash::{Hash, Hasher},
15 marker::PhantomData,
16 ops::Deref,
17};
18
19use anyhow::Result;
20use bincode::{Decode, Encode};
21use serde::{Deserialize, Serialize};
22use shrink_to_fit::ShrinkToFit;
23
24pub use self::{
25 cast::{VcCast, VcValueTraitCast, VcValueTypeCast},
26 cell_mode::{VcCellCompareMode, VcCellKeyedCompareMode, VcCellMode, VcCellNewMode},
27 default::ValueDefault,
28 local::NonLocalValue,
29 operation::{OperationValue, OperationVc},
30 read::{ReadOwnedVcFuture, ReadVcFuture, VcDefaultRead, VcRead, VcTransparentRead},
31 resolved::ResolvedVc,
32 traits::{Dynamic, Upcast, UpcastStrict, VcValueTrait, VcValueType},
33};
34use crate::{
35 CellId, RawVc, ResolveTypeError,
36 debug::{ValueDebug, ValueDebugFormat, ValueDebugFormatString},
37 keyed::{KeyedAccess, KeyedEq},
38 registry,
39 trace::{TraceRawVcs, TraceRawVcsContext},
40 vc::read::{ReadContainsKeyedVcFuture, ReadKeyedVcFuture},
41};
42
43type VcReadTarget<T> = <<T as VcValueType>::Read as VcRead<T>>::Target;
44
45/// A "Value Cell" (`Vc` for short) is a reference to a memoized computation result stored on the
46/// heap or in filesystem cache, depending on the Turbo Engine backend implementation.
47///
48/// In order to get a reference to the pointed value, you need to `.await` the [`Vc<T>`] to get a
49/// [`ReadRef<T>`][`ReadRef`]:
50///
51/// ```
52/// let some_vc: Vc<T>;
53/// let some_ref: ReadRef<T> = some_vc.await?;
54/// some_ref.some_method_on_t();
55/// ```
56///
57/// `Vc`s are similar to a [`Future`] or a Promise with a few key differences:
58///
59/// - The value pointed to by a `Vc` can be invalidated by changing dependencies or cache evicted,
60/// meaning that `await`ing a `Vc` multiple times can give different results. A [`ReadRef`] is
61/// snapshot of the underlying cell at a point in time.
62///
63/// - Reading (`await`ing) `Vc`s causes the current task to be tracked a dependent of the `Vc`'s
64/// task or task cell. When the read task or task cell changes, the current task may be
65/// re-executed.
66///
67/// - `Vc` types are always [`Copy`]. Most [`Future`]s are not. This works because `Vc`s are
68/// represented as a few ids or indices into data structures managed by the `turbo-tasks`
69/// framework. `Vc` types are not reference counted, but do support [tracing] for a hypothetical
70/// (unimplemented) garbage collector.
71///
72/// - Unlike futures (but like promises), the work that a `Vc` represents [begins execution even if
73/// the `Vc` is not `await`ed](#execution-model).
74///
75/// For a more in-depth explanation of the concepts behind value cells, [refer to the Turbopack
76/// book][book-cells].
77///
78///
79/// ## Subtypes
80///
81/// There are a couple of explicit "subtypes" of `Vc`. These can both be cheaply converted back into
82/// a `Vc`.
83///
84/// - **[`ResolvedVc`]:** *(aka [`RawVc::TaskCell`])* A reference to a cell constructed within a
85/// task, as part of a [`Vc::cell`] or `value_type.cell()` constructor. As the cell has been
86/// constructed at least once, the concrete type of the cell is known (allowing
87/// [downcasting][ResolvedVc::try_downcast]). This is stored as a combination of a task id, a type
88/// id, and a cell id.
89///
90/// - **[`OperationVc`]:** *(aka [`RawVc::TaskOutput`])* The synchronous return value of a
91/// [`turbo_tasks::function`]. Internally, this is stored using a task id. Exact type information
92/// of trait types (i.e. `Vc<Box<dyn Trait>>`) is not known because the function may not have
93/// finished execution yet. [`OperationVc`]s must first be [`connect`][OperationVc::connect]ed
94/// before being read.
95///
96/// [`ResolvedVc`] is almost always preferred over the more awkward [`OperationVc`] API, but
97/// [`OperationVc`] can be useful when dealing with [collectibles], when you need to [read the
98/// result of a function with strong consistency][OperationVc::read_strongly_consistent], or with
99/// [`State`].
100///
101/// These many representations are stored internally using a type-erased [`RawVc`]. Type erasure
102/// reduces the [monomorphization] (and therefore binary size and compilation time) required to
103/// support `Vc` and its subtypes.
104///
105/// | | Representation | Equality | Downcasting | Strong Consistency | Collectibles | [Non-Local] |
106/// |-----------------|------------------------------------|-----------------|----------------------------|------------------------|-------------------|--------------|
107/// | [`Vc`] | [One of many][RawVc] | ❌ [Broken][eq] | ⚠️ After resolution | ❌ Eventual | ❌ No | ❌ [No][loc] |
108/// | [`ResolvedVc`] | [Task Id + Type Id + Cell Id][rtc] | ✅ Yes\* | ✅ [Yes, cheaply][resolve] | ❌ Eventual | ❌ No | ✅ Yes |
109/// | [`OperationVc`] | [Task Id][rto] | ✅ Yes\* | ⚠️ After resolution | ✅ [Supported][strong] | ✅ [Yes][collect] | ✅ Yes |
110///
111/// *\* see the type's documentation for details*
112///
113/// [Non-Local]: NonLocalValue
114/// [rtc]: RawVc::TaskCell
115/// [rto]: RawVc::TaskOutput
116/// [loc]: #optimization-local-outputs
117/// [eq]: #equality--hashing
118/// [resolve]: ResolvedVc::try_downcast
119/// [strong]: OperationVc::read_strongly_consistent
120/// [collect]: crate::CollectiblesSource
121///
122///
123/// ## Execution Model
124///
125/// While task functions are expected to be side-effect free, their execution behavior is still
126/// important for performance reasons, or to code using [collectibles] to represent issues or
127/// side-effects.
128///
129/// Function calls are neither "eager", nor "lazy". Even if not awaited, they are guaranteed to
130/// execute (potentially emitting collectibles) before the root task finishes or before the
131/// completion of any strongly consistent read containing their call. However, the exact point when
132/// that execution begins is an implementation detail. Functions may execute more than once due to
133/// dirty task invalidation.
134///
135///
136/// ## Equality & Hashing
137///
138/// Because `Vc`s can be equivalent but have different representation, it's not recommended to
139/// compare `Vc`s by equality. Instead, you should convert a `Vc` to an explicit subtype first
140/// (likely [`ResolvedVc`]). Future versions of `Vc` may not implement [`Eq`], [`PartialEq`], or
141/// [`Hash`].
142///
143///
144/// ## Optimization: Local Outputs
145///
146/// In addition to the potentially-explicit "resolved" and "operation" representations of a `Vc`,
147/// there's another internal representation of a `Vc`, known as a "Local `Vc`", or
148/// [`RawVc::LocalOutput`].
149///
150/// This is a special case of the synchronous return value of a [`turbo_tasks::function`] when some
151/// of its arguments have not yet been resolved. These are stored in task-local state that is freed
152/// after their parent non-local task exits.
153///
154/// We prevent potentially-local `Vc`s from escaping the lifetime of a function using the
155/// [`NonLocalValue`] marker trait alongside some fallback runtime checks. We do this to avoid some
156/// ergonomic challenges that would come from using lifetime annotations with `Vc`.
157///
158///
159/// [tracing]: crate::trace::TraceRawVcs
160/// [`ReadRef`]: crate::ReadRef
161/// [`turbo_tasks::function`]: crate::function
162/// [monomorphization]: https://doc.rust-lang.org/book/ch10-01-syntax.html#performance-of-code-using-generics
163/// [`State`]: crate::State
164/// [book-cells]: https://turbopack-rust-docs.vercel.sh/turbo-engine/cells.html
165/// [collectibles]: crate::CollectiblesSource
166#[must_use]
167#[derive(Serialize, Deserialize, Encode, Decode)]
168#[serde(transparent, bound = "")]
169#[bincode(bounds = "T: ?Sized")]
170#[repr(transparent)]
171pub struct Vc<T>
172where
173 T: ?Sized,
174{
175 pub(crate) node: RawVc,
176 #[doc(hidden)]
177 pub(crate) _t: PhantomData<T>,
178}
179
180/// This only exists to satisfy the Rust type system. However, this struct can
181/// never actually be instantiated, as dereferencing a `Vc<T>` will result in a
182/// linker error. See the implementation of `Deref` for `Vc<T>`.
183pub struct VcDeref<T>
184where
185 T: ?Sized,
186{
187 _t: PhantomData<T>,
188}
189
190macro_rules! do_not_use_or_you_will_be_fired {
191 ($($name:ident)*) => {
192 impl<T> VcDeref<T>
193 where
194 T: ?Sized,
195 {
196 $(
197 #[doc(hidden)]
198 #[allow(unused)]
199 #[allow(clippy::wrong_self_convention)]
200 #[deprecated = "This is not the method you are looking for."]
201 pub fn $name(self) {}
202 )*
203 }
204 };
205}
206
207// Hide raw pointer methods on `Vc<T>`. This is an artifact of having
208// implement `Deref<Target = *const T>` on `Vc<T>` for `arbitrary_self_types` to
209// do its thing. This can be removed once the `Receiver` trait no longer depends
210// on `Deref`.
211do_not_use_or_you_will_be_fired!(
212 add
213 addr
214 align_offset
215 as_mut
216 as_mut_ptr
217 as_ptr
218 as_ref
219 as_uninit_mut
220 as_uninit_ref
221 as_uninit_slice
222 as_uninit_slice_mut
223 byte_add
224 byte_offset
225 byte_offset_from
226 byte_sub
227 cast
228 cast_const
229 cast_mut
230 copy_from
231 copy_from_nonoverlapping
232 copy_to
233 copy_to_nonoverlapping
234 drop_in_place
235 expose_addr
236 from_bits
237 get_unchecked
238 get_unchecked_mut
239 guaranteed_eq
240 guaranteed_ne
241 is_aligned
242 is_aligned_to
243 is_empty
244 is_null
245 len
246 map_addr
247 mask
248 offset
249 offset_from
250 read
251 read_unaligned
252 read_volatile
253 replace
254 split_at_mut
255 split_at_mut_unchecked
256 sub
257 sub_ptr
258 swap
259 to_bits
260 to_raw_parts
261 with_addr
262 with_metadata_of
263 wrapping_add
264 wrapping_byte_add
265 wrapping_byte_offset
266 wrapping_byte_sub
267 wrapping_offset
268 wrapping_sub
269 write
270 write_bytes
271 write_unaligned
272 write_volatile
273);
274
275// Call this macro for all the applicable methods above:
276
277#[doc(hidden)]
278impl<T> Deref for VcDeref<T>
279where
280 T: ?Sized,
281{
282 // `*const T` or `*mut T` would be enough here, but from an abundance of
283 // caution, we use `*const *mut *const T` to make sure there will never be an
284 // applicable method.
285 type Target = *const *mut *const T;
286
287 fn deref(&self) -> &Self::Target {
288 unsafe extern "C" {
289 #[link_name = "\n\nERROR: you tried to dereference a `Vc<T>`\n"]
290 fn trigger() -> !;
291 }
292
293 unsafe { trigger() };
294 }
295}
296
297// This is the magic that makes `Vc<T>` accept `self: Vc<Self>` methods through
298// `arbitrary_self_types`, while not allowing any other receiver type:
299// * `Vc<T>` dereferences to `*const *mut *const T`, which means that it is valid under the
300// `arbitrary_self_types` rules.
301// * `*const *mut *const T` is not a valid receiver for any attribute access on `T`, which means
302// that the only applicable items will be the methods declared on `self: Vc<Self>`.
303//
304// If we had used `type Target = T` instead, `vc_t.some_attr_defined_on_t` would
305// have been accepted by the compiler.
306#[doc(hidden)]
307impl<T> Deref for Vc<T>
308where
309 T: ?Sized,
310{
311 type Target = VcDeref<T>;
312
313 fn deref(&self) -> &Self::Target {
314 unsafe extern "C" {
315 #[link_name = "\n\nERROR: you tried to dereference a `Vc<T>`\n"]
316 fn trigger() -> !;
317 }
318
319 unsafe { trigger() };
320 }
321}
322
323impl<T> Copy for Vc<T> where T: ?Sized {}
324
325impl<T> Clone for Vc<T>
326where
327 T: ?Sized,
328{
329 fn clone(&self) -> Self {
330 *self
331 }
332}
333
334impl<T> Hash for Vc<T>
335where
336 T: ?Sized,
337{
338 fn hash<H: Hasher>(&self, state: &mut H) {
339 self.node.hash(state);
340 }
341}
342
343impl<T> PartialEq<Vc<T>> for Vc<T>
344where
345 T: ?Sized,
346{
347 fn eq(&self, other: &Self) -> bool {
348 self.node == other.node
349 }
350}
351
352impl<T> Eq for Vc<T> where T: ?Sized {}
353
354/// Generates an opaque debug representation of the [`Vc`] itself, but not the data inside of it.
355///
356/// This is implemented to allow types containing [`Vc`] to implement the synchronous [`Debug`]
357/// trait, but in most cases users should use the [`ValueDebug`] implementation to get a string
358/// representation of the contents of the cell.
359impl<T> Debug for Vc<T>
360where
361 T: ?Sized,
362{
363 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
364 f.debug_tuple("Vc").field(&self.node).finish()
365 }
366}
367
368impl<T> Vc<T>
369where
370 T: VcValueType,
371{
372 // called by the `.cell()` method generated by the `#[turbo_tasks::value]` macro
373 #[doc(hidden)]
374 pub fn cell_private(mut inner: <T::Read as VcRead<T>>::Target) -> Self {
375 // cell contents are immutable, so go ahead and shrink the cell's contents
376 ShrinkToFit::shrink_to_fit(<T::Read as VcRead<T>>::target_to_value_mut_ref(&mut inner));
377 <T::CellMode as VcCellMode<T>>::cell(inner)
378 }
379}
380
381impl<T, Inner> Vc<T>
382where
383 T: VcValueType<Read = VcTransparentRead<T, Inner>>,
384 Inner: Any + Send + Sync,
385{
386 pub fn cell(inner: Inner) -> Self {
387 Self::cell_private(inner)
388 }
389}
390
391impl<T> Vc<T>
392where
393 T: ?Sized,
394{
395 /// Returns a debug identifier for this `Vc`.
396 pub async fn debug_identifier(vc: Self) -> Result<String> {
397 let resolved = vc.resolve().await?;
398 let raw_vc: RawVc = resolved.node;
399 if let RawVc::TaskCell(task_id, CellId { type_id, index }) = raw_vc {
400 let value_ty = registry::get_value_type(type_id);
401 Ok(format!("{}#{}: {}", value_ty.name, index, task_id))
402 } else {
403 unreachable!()
404 }
405 }
406
407 /// Returns the `RawVc` corresponding to this `Vc`.
408 pub fn into_raw(vc: Self) -> RawVc {
409 vc.node
410 }
411
412 /// Upcasts the given `Vc<T>` to a `Vc<Box<dyn K>>`.
413 ///
414 /// This is also available as an `Into`/`From` conversion.
415 #[inline(always)]
416 pub fn upcast<K>(vc: Self) -> Vc<K>
417 where
418 T: UpcastStrict<K>,
419 K: VcValueTrait + ?Sized,
420 {
421 Self::upcast_non_strict(vc)
422 }
423
424 /// Upcasts the given `Vc<T>` to a `Vc<Box<dyn K>>`
425 ///
426 /// This has a loose type constraint which would allow upcasting to the same type, prefer using
427 /// [`Vc::upcast`] when possible. This is useful for extension traits and other more generic
428 /// usecases.
429 ///
430 /// # Example
431 /// ```rust
432 /// // In generic code where T might be the same as K
433 /// fn process_foo(vc: ResolvedVc<impl Upcast<Box<dyn MyTrait>>>) -> Vc<Foo> {
434 /// let my_trait: ResolvedVc<Box<dyn MyTrait>> = Vc::upcast_non_strict(vc);
435 /// my_trait.do_something()
436 /// }
437 /// ```
438 /// Using generics you could allow users to pass any compatible type, but if you specified
439 /// `UpcastStrict<...>` instead of `Upcast<...>` you would disallow calling this function if you
440 /// already had a `ResolvedVc<Box<dyn MyTrait>>. So this function has a looser type constraint
441 /// to make these functions easier to write and use.
442 #[inline(always)]
443 pub fn upcast_non_strict<K>(vc: Self) -> Vc<K>
444 where
445 T: Upcast<K>,
446 K: VcValueTrait + ?Sized,
447 {
448 Vc {
449 node: vc.node,
450 _t: PhantomData,
451 }
452 }
453 /// Runs the operation, but ignores the returned Vc. Use that when only interested in running
454 /// the task for side effects.
455 pub async fn as_side_effect(self) -> Result<()> {
456 self.node.resolve().await?;
457 Ok(())
458 }
459
460 /// Do not use this: Use [`Vc::to_resolved`] instead. If you must have a resolved [`Vc`] type
461 /// and not a [`ResolvedVc`] type, simply deref the result of [`Vc::to_resolved`].
462 pub async fn resolve(self) -> Result<Vc<T>> {
463 Ok(Self {
464 node: self.node.resolve().await?,
465 _t: PhantomData,
466 })
467 }
468
469 /// Resolve the reference until it points to a cell directly, and wrap the
470 /// result in a [`ResolvedVc`], which statically guarantees that the
471 /// [`Vc`] was resolved.
472 pub async fn to_resolved(self) -> Result<ResolvedVc<T>> {
473 Ok(ResolvedVc {
474 node: self.resolve().await?,
475 })
476 }
477
478 /// Returns `true` if the reference is resolved, meaning the underlying [`RawVc`] uses the
479 /// [`RawVc::TaskCell`] representation.
480 ///
481 /// If you need resolved [`Vc`] value, it's typically better to use the [`ResolvedVc`] type to
482 /// enforce your requirements statically instead of dynamically at runtime.
483 ///
484 /// See also [`ResolvedVc::to_resolved`] and [`RawVc::is_resolved`].
485 pub fn is_resolved(self) -> bool {
486 self.node.is_resolved()
487 }
488
489 /// Returns `true` if the `Vc` was by a local function call (e.g. one who's arguments were not
490 /// fully resolved) and has not yet been resolved.
491 ///
492 /// Aside from differences in caching, a function's behavior should not be changed by using
493 /// local or non-local cells, so this function is mostly useful inside tests and internally in
494 /// turbo-tasks.
495 pub fn is_local(self) -> bool {
496 self.node.is_local()
497 }
498
499 /// Do not use this: Use [`OperationVc::resolve_strongly_consistent`] instead.
500 #[cfg(feature = "non_operation_vc_strongly_consistent")]
501 pub async fn resolve_strongly_consistent(self) -> Result<Self> {
502 Ok(Self {
503 node: self.node.resolve_strongly_consistent().await?,
504 _t: PhantomData,
505 })
506 }
507}
508
509impl<T> Vc<T>
510where
511 T: VcValueTrait + ?Sized,
512{
513 /// Attempts to sidecast the given `Vc<Box<dyn T>>` to a `Vc<Box<dyn K>>`.
514 /// This operation also resolves the `Vc`.
515 ///
516 /// Returns `None` if the underlying value type does not implement `K`.
517 ///
518 /// **Note:** if the trait T is required to implement K, use
519 /// `Vc::upcast(vc).resolve()` instead. This provides stronger guarantees,
520 /// removing the need for a `Result` return type.
521 pub async fn try_resolve_sidecast<K>(vc: Self) -> Result<Option<Vc<K>>, ResolveTypeError>
522 where
523 K: VcValueTrait + ?Sized,
524 {
525 debug_assert!(
526 <K as VcValueTrait>::get_trait_type_id() != <T as VcValueTrait>::get_trait_type_id(),
527 "Attempted to cast a type {} to itself, which is pointless. Use the value directly \
528 instead.",
529 crate::registry::get_trait(<T as VcValueTrait>::get_trait_type_id()).global_name
530 );
531 let raw_vc: RawVc = vc.node;
532 let raw_vc = raw_vc
533 .resolve_trait(<K as VcValueTrait>::get_trait_type_id())
534 .await?;
535 Ok(raw_vc.map(|raw_vc| Vc {
536 node: raw_vc,
537 _t: PhantomData,
538 }))
539 }
540
541 /// Attempts to downcast the given `Vc<Box<dyn T>>` to a `Vc<K>`, where `K`
542 /// is of the form `Box<dyn L>`, and `L` is a value trait.
543 /// This operation also resolves the `Vc`.
544 ///
545 /// Returns `None` if the underlying value type is not a `K`.
546 pub async fn try_resolve_downcast<K>(vc: Self) -> Result<Option<Vc<K>>, ResolveTypeError>
547 where
548 K: UpcastStrict<T> + VcValueTrait + ?Sized,
549 {
550 Self::try_resolve_sidecast(vc).await
551 }
552
553 /// Attempts to downcast the given `Vc<Box<dyn T>>` to a `Vc<K>`, where `K`
554 /// is a value type.
555 /// This operation also resolves the `Vc`.
556 ///
557 /// Returns `None` if the underlying value type is not a `K`.
558 pub async fn try_resolve_downcast_type<K>(vc: Self) -> Result<Option<Vc<K>>, ResolveTypeError>
559 where
560 K: UpcastStrict<T> + VcValueType,
561 {
562 let raw_vc: RawVc = vc.node;
563 let raw_vc = raw_vc
564 .resolve_value(<K as VcValueType>::get_value_type_id())
565 .await?;
566 Ok(raw_vc.map(|raw_vc| Vc {
567 node: raw_vc,
568 _t: PhantomData,
569 }))
570 }
571}
572
573impl<T> From<RawVc> for Vc<T>
574where
575 T: ?Sized,
576{
577 fn from(node: RawVc) -> Self {
578 Self {
579 node,
580 _t: PhantomData,
581 }
582 }
583}
584
585impl<T> TraceRawVcs for Vc<T>
586where
587 T: ?Sized,
588{
589 fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
590 TraceRawVcs::trace_raw_vcs(&self.node, trace_context);
591 }
592}
593
594impl<T> ValueDebugFormat for Vc<T>
595where
596 T: UpcastStrict<Box<dyn ValueDebug>> + Send + Sync + ?Sized,
597{
598 fn value_debug_format(&self, depth: usize) -> ValueDebugFormatString<'_> {
599 ValueDebugFormatString::Async(Box::pin(async move {
600 Ok({
601 let vc_value_debug = Vc::upcast::<Box<dyn ValueDebug>>(*self);
602 vc_value_debug.dbg_depth(depth).await?.to_string()
603 })
604 }))
605 }
606}
607
608macro_rules! into_future {
609 ($ty:ty) => {
610 impl<T> IntoFuture for $ty
611 where
612 T: VcValueType,
613 {
614 type Output = <ReadVcFuture<T> as Future>::Output;
615 type IntoFuture = ReadVcFuture<T>;
616 fn into_future(self) -> Self::IntoFuture {
617 self.node.into_read(T::has_serialization()).into()
618 }
619 }
620 };
621}
622
623into_future!(Vc<T>);
624into_future!(&Vc<T>);
625into_future!(&mut Vc<T>);
626
627impl<T> Vc<T>
628where
629 T: VcValueType,
630{
631 /// Do not use this: Use [`OperationVc::read_strongly_consistent`] instead.
632 #[cfg(feature = "non_operation_vc_strongly_consistent")]
633 #[must_use]
634 pub fn strongly_consistent(self) -> ReadVcFuture<T> {
635 self.node
636 .into_read(T::has_serialization())
637 .strongly_consistent()
638 .into()
639 }
640
641 /// Returns a untracked read of the value. This will not invalidate the current function when
642 /// the read value changed.
643 #[must_use]
644 pub fn untracked(self) -> ReadVcFuture<T> {
645 self.node
646 .into_read(T::has_serialization())
647 .untracked()
648 .into()
649 }
650
651 /// Read the value with the hint that this is the final read of the value. This might drop the
652 /// cell content. Future reads might need to recompute the value.
653 #[must_use]
654 pub fn final_read_hint(self) -> ReadVcFuture<T> {
655 self.node
656 .into_read(T::has_serialization())
657 .final_read_hint()
658 .into()
659 }
660}
661
662impl<T> Vc<T>
663where
664 T: VcValueType,
665 VcReadTarget<T>: Clone,
666{
667 /// Read the value and returns a owned version of it. It might clone the value.
668 pub fn owned(self) -> ReadOwnedVcFuture<T> {
669 let future: ReadVcFuture<T> = self.node.into_read(T::has_serialization()).into();
670 future.owned()
671 }
672}
673
674impl<T> Vc<T>
675where
676 T: VcValueType,
677 VcReadTarget<T>: KeyedEq,
678{
679 /// Read the value and selects a keyed value from it. Only depends on the used key instead of
680 /// the full value.
681 pub fn get<'l, Q>(self, key: &'l Q) -> ReadKeyedVcFuture<'l, T, Q>
682 where
683 Q: Hash + ?Sized,
684 VcReadTarget<T>: KeyedAccess<Q>,
685 {
686 let future: ReadVcFuture<T> = self.node.into_read(T::has_serialization()).into();
687 future.get(key)
688 }
689
690 /// Read the value and checks if it contains the given key. Only depends on the used key instead
691 /// of the full value.
692 pub fn contains_key<'l, Q>(self, key: &'l Q) -> ReadContainsKeyedVcFuture<'l, T, Q>
693 where
694 Q: Hash + ?Sized,
695 VcReadTarget<T>: KeyedAccess<Q>,
696 {
697 let future: ReadVcFuture<T> = self.node.into_read(T::has_serialization()).into();
698 future.contains_key(key)
699 }
700}
701
702impl<T> Unpin for Vc<T> where T: ?Sized {}
703
704impl<T> Default for Vc<T>
705where
706 T: ValueDefault,
707{
708 fn default() -> Self {
709 T::value_default()
710 }
711}
712
713pub trait OptionVcExt<T>
714where
715 T: VcValueType,
716{
717 fn to_resolved(self) -> impl Future<Output = Result<Option<ResolvedVc<T>>>> + Send;
718}
719
720impl<T> OptionVcExt<T> for Option<Vc<T>>
721where
722 T: VcValueType,
723{
724 async fn to_resolved(self) -> Result<Option<ResolvedVc<T>>> {
725 if let Some(vc) = self {
726 Ok(Some(vc.to_resolved().await?))
727 } else {
728 Ok(None)
729 }
730 }
731}