turbopack_dev_server/source/
conditional.rs1use anyhow::Result;
2use turbo_rcstr::{RcStr, rcstr};
3use turbo_tasks::{Completion, ResolvedVc, State, Vc};
4use turbopack_core::introspect::{Introspectable, IntrospectableChildren};
5
6use crate::source::{
7 ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataVary,
8 ContentSourceSideEffect, ContentSources, GetContentSourceContent,
9 route_tree::{MapGetContentSourceContent, RouteTree, RouteTrees},
10};
11
12#[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new")]
24pub struct ConditionalContentSource {
25 activator: ResolvedVc<Box<dyn ContentSource>>,
26 action: ResolvedVc<Box<dyn ContentSource>>,
27 activated: State<bool>,
28}
29
30#[turbo_tasks::value_impl]
31impl ConditionalContentSource {
32 #[turbo_tasks::function]
33 pub fn new(
34 activator: ResolvedVc<Box<dyn ContentSource>>,
35 action: ResolvedVc<Box<dyn ContentSource>>,
36 ) -> Vc<Self> {
37 ConditionalContentSource {
38 activator,
39 action,
40 activated: State::new(false),
41 }
42 .cell()
43 }
44}
45
46#[turbo_tasks::value_impl]
47impl ContentSource for ConditionalContentSource {
48 #[turbo_tasks::function]
49 async fn get_routes(self: ResolvedVc<Self>) -> Result<Vc<RouteTree>> {
50 let this = self.await?;
51 Ok(if !*this.activated.get() {
52 this.activator.get_routes().map_routes(Vc::upcast(
53 ConditionalContentSourceMapper { source: self }.cell(),
54 ))
55 } else {
56 Vc::<RouteTrees>::cell(vec![
57 this.activator.get_routes().to_resolved().await?,
58 this.action.get_routes().to_resolved().await?,
59 ])
60 .merge()
61 })
62 }
63
64 #[turbo_tasks::function]
65 fn get_children(&self) -> Vc<ContentSources> {
66 Vc::cell(vec![self.activator, self.action])
67 }
68}
69
70#[turbo_tasks::value]
71struct ConditionalContentSourceMapper {
72 source: ResolvedVc<ConditionalContentSource>,
73}
74
75#[turbo_tasks::value_impl]
76impl MapGetContentSourceContent for ConditionalContentSourceMapper {
77 #[turbo_tasks::function]
78 fn map_get_content(
79 &self,
80 get_content: ResolvedVc<Box<dyn GetContentSourceContent>>,
81 ) -> Vc<Box<dyn GetContentSourceContent>> {
82 Vc::upcast(
83 ActivateOnGetContentSource {
84 source: self.source,
85 get_content,
86 }
87 .cell(),
88 )
89 }
90}
91
92#[turbo_tasks::value_impl]
93impl Introspectable for ConditionalContentSource {
94 #[turbo_tasks::function]
95 fn ty(&self) -> Vc<RcStr> {
96 Vc::cell(rcstr!("conditional content source"))
97 }
98
99 #[turbo_tasks::function]
100 fn details(&self) -> Vc<RcStr> {
101 Vc::cell(if *self.activated.get() {
102 rcstr!("activated")
103 } else {
104 rcstr!("not activated")
105 })
106 }
107
108 #[turbo_tasks::function]
109 fn title(&self) -> Result<Vc<RcStr>> {
110 if let Some(activator) = ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.activator)
111 {
112 Ok(activator.title())
113 } else {
114 Ok(Vc::<RcStr>::default())
115 }
116 }
117
118 #[turbo_tasks::function]
119 fn children(&self) -> Result<Vc<IntrospectableChildren>> {
120 Ok(Vc::cell(
121 [
122 ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.activator)
123 .map(|i| (rcstr!("activator"), i)),
124 ResolvedVc::try_sidecast::<Box<dyn Introspectable>>(self.action)
125 .map(|i| (rcstr!("action"), i)),
126 ]
127 .into_iter()
128 .flatten()
129 .collect(),
130 ))
131 }
132}
133
134#[turbo_tasks::value(serialization = "none", eq = "manual", cell = "new")]
135struct ActivateOnGetContentSource {
136 source: ResolvedVc<ConditionalContentSource>,
137 get_content: ResolvedVc<Box<dyn GetContentSourceContent>>,
138}
139
140#[turbo_tasks::value_impl]
141impl GetContentSourceContent for ActivateOnGetContentSource {
142 #[turbo_tasks::function]
143 fn vary(&self) -> Vc<ContentSourceDataVary> {
144 self.get_content.vary()
145 }
146
147 #[turbo_tasks::function]
148 async fn get(
149 self: ResolvedVc<Self>,
150 path: RcStr,
151 data: ContentSourceData,
152 ) -> Result<Vc<ContentSourceContent>> {
153 turbo_tasks::emit(ResolvedVc::upcast::<Box<dyn ContentSourceSideEffect>>(self));
154 Ok(self.await?.get_content.get(path, data))
155 }
156}
157
158#[turbo_tasks::value_impl]
159impl ContentSourceSideEffect for ActivateOnGetContentSource {
160 #[turbo_tasks::function]
161 async fn apply(&self) -> Result<Vc<Completion>> {
162 self.source.await?.activated.set(true);
163 Ok(Completion::new())
164 }
165}