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