Skip to main content

rspack_core/dependency/
dependency_trait.rs

1use std::{
2  alloc::{Layout, LayoutError, alloc, handle_alloc_error},
3  any::Any,
4  fmt::{self, Debug},
5  ops::{Deref, DerefMut},
6  ptr,
7  sync::{Arc, OnceLock, atomic::AtomicUsize},
8};
9
10use rspack_cacheable::{
11  cacheable_dyn,
12  rkyv::{
13    Archive, ArchiveUnsized, Deserialize, DeserializeUnsized, Place, Serialize, SerializeUnsized,
14    de::{FromMetadata, Metadata, Pooling, PoolingExt, SharedPointer},
15    ptr_meta::{Pointee, from_raw_parts_mut},
16    rancor::{Fallible, ResultExt, Source},
17    rc::{ArchivedRc, Flavor, RcResolver},
18    ser::{Sharing, Writer},
19    traits::LayoutRaw,
20  },
21};
22use rspack_collections::{IdentifierMap, IdentifierSet};
23use rspack_error::Diagnostic;
24use rspack_location::DependencyLocation;
25use rspack_util::ext::AsAny;
26use triomphe::{Arc as TriompheArc, UniqueArc};
27use unsize::{CoerceUnsize, Coercion};
28
29use super::{
30  DependencyCategory, DependencyId, DependencyRange, DependencyType, ExportsSpec,
31  dependency_template::AsDependencyCodeGeneration, module_dependency::*,
32};
33use crate::{
34  AsContextDependency, ConnectionState, Context, ExportsInfoArtifact, ForwardId, ImportAttributes,
35  ImportPhase, JavascriptParserUrl, LazyUntil, Module, ModuleGraph, ModuleGraphCacheArtifact,
36  ModuleLayer, ReferencedExport, RuntimeSpec, SideEffectsStateArtifact,
37  create_exports_object_referenced,
38};
39
40#[derive(Debug, Clone, Copy)]
41pub enum AffectType {
42  True,
43  False,
44  Transitive,
45}
46
47/// Module-scoped state shared while collecting diagnostics from its dependencies.
48#[derive(Debug, Default)]
49pub struct DependencyDiagnosticsContext {
50  module_source: OnceLock<Option<Arc<str>>>,
51}
52
53impl DependencyDiagnosticsContext {
54  fn get_or_init_module_source(&self, init: impl FnOnce() -> Option<Arc<str>>) -> Option<Arc<str>> {
55    self.module_source.get_or_init(init).clone()
56  }
57
58  /// Lazily materialize the module source once and share it across its diagnostics.
59  pub fn module_source(&self, module: &dyn Module) -> Option<Arc<str>> {
60    self.get_or_init_module_source(|| {
61      module
62        .source()
63        .map(|source| source.source().into_string_lossy().into())
64    })
65  }
66}
67
68#[cacheable_dyn]
69pub trait Dependency:
70  AsDependencyCodeGeneration + AsContextDependency + AsModuleDependency + AsAny + Send + Sync + Debug
71{
72  fn id(&self) -> &DependencyId;
73
74  fn category(&self) -> &DependencyCategory {
75    &DependencyCategory::Unknown
76  }
77
78  fn dependency_type(&self) -> &DependencyType {
79    &DependencyType::Unknown
80  }
81
82  /// Whether this dependency should be excluded when a global entry include is applied to an
83  /// async entrypoint.
84  fn skip_async_entrypoints(&self) -> bool {
85    false
86  }
87
88  fn url_mode(&self) -> Option<JavascriptParserUrl> {
89    None
90  }
91
92  // get issuer context
93  fn get_context(&self) -> Option<&Context> {
94    None
95  }
96
97  // get issuer layer
98  fn get_layer(&self) -> Option<&ModuleLayer> {
99    None
100  }
101
102  fn get_phase(&self) -> ImportPhase {
103    ImportPhase::Evaluation
104  }
105
106  fn get_attributes(&self) -> Option<&ImportAttributes> {
107    None
108  }
109
110  fn get_exports(
111    &self,
112    _mg: &ModuleGraph,
113    _module_graph_cache: &ModuleGraphCacheArtifact,
114    _exports_info_artifact: &ExportsInfoArtifact,
115  ) -> Option<ExportsSpec> {
116    None
117  }
118
119  fn get_module_evaluation_side_effects_state(
120    &self,
121    _module_graph: &ModuleGraph,
122    _module_graph_cache: &ModuleGraphCacheArtifact,
123    _side_effects_state_artifact: &SideEffectsStateArtifact,
124    _module_chain: &mut IdentifierSet,
125    _connection_state_cache: &mut IdentifierMap<ConnectionState>,
126  ) -> ConnectionState {
127    ConnectionState::Active(true)
128  }
129
130  fn loc(&self) -> Option<DependencyLocation> {
131    None
132  }
133
134  fn range(&self) -> Option<DependencyRange> {
135    None
136  }
137
138  fn source_order(&self) -> Option<i32> {
139    None
140  }
141
142  fn resource_identifier(&self) -> Option<&str> {
143    None
144  }
145
146  fn get_diagnostics(
147    &self,
148    _module_graph: &ModuleGraph,
149    _module_graph_cache: &ModuleGraphCacheArtifact,
150    _exports_info_artifact: &ExportsInfoArtifact,
151  ) -> Option<Vec<Diagnostic>> {
152    None
153  }
154
155  fn get_diagnostics_with_context(
156    &self,
157    module_graph: &ModuleGraph,
158    module_graph_cache: &ModuleGraphCacheArtifact,
159    exports_info_artifact: &ExportsInfoArtifact,
160    _context: &DependencyDiagnosticsContext,
161  ) -> Option<Vec<Diagnostic>> {
162    self.get_diagnostics(module_graph, module_graph_cache, exports_info_artifact)
163  }
164
165  fn get_referenced_exports(
166    &self,
167    _module_graph: &ModuleGraph,
168    _module_graph_cache: &ModuleGraphCacheArtifact,
169    _exports_info_artifact: &ExportsInfoArtifact,
170    _runtime: Option<&RuntimeSpec>,
171  ) -> Vec<ReferencedExport> {
172    create_exports_object_referenced()
173  }
174
175  fn could_affect_referencing_module(&self) -> AffectType;
176
177  fn forward_id(&self) -> ForwardId {
178    ForwardId::All
179  }
180
181  fn lazy(&self) -> Option<LazyUntil> {
182    None
183  }
184
185  fn set_lazy(&self) {}
186
187  fn unset_lazy(&self) -> bool {
188    false
189  }
190}
191
192impl dyn Dependency + '_ {
193  pub fn downcast_ref<D: Any>(&self) -> Option<&D> {
194    self.as_any().downcast_ref::<D>()
195  }
196
197  pub fn downcast_mut<D: Any>(&mut self) -> Option<&mut D> {
198    self.as_any_mut().downcast_mut::<D>()
199  }
200
201  pub fn is<D: Any>(&self) -> bool {
202    self.downcast_ref::<D>().is_some()
203  }
204}
205
206/// A dependency with unique ownership while it is being constructed.
207///
208/// Unlike `Box<dyn Dependency>`, this uses the same allocation layout as [`DependencyRef`], so
209/// publishing it into the module graph does not reallocate or move the dependency.
210pub struct UniqueDependency(UniqueArc<dyn Dependency>);
211
212impl UniqueDependency {
213  pub fn new<D: Dependency + 'static>(dependency: D) -> Self {
214    let coercion =
215      unsafe { Coercion::<D, dyn Dependency>::new(|ptr: *const D| ptr as *const dyn Dependency) };
216    Self(UniqueArc::new(dependency).unsize(coercion))
217  }
218
219  pub fn shareable(self) -> DependencyRef {
220    DependencyRef(self.0.shareable())
221  }
222}
223
224impl Debug for UniqueDependency {
225  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226    Debug::fmt(self.as_ref(), f)
227  }
228}
229
230impl Deref for UniqueDependency {
231  type Target = dyn Dependency;
232
233  fn deref(&self) -> &Self::Target {
234    &*self.0
235  }
236}
237
238impl DerefMut for UniqueDependency {
239  fn deref_mut(&mut self) -> &mut Self::Target {
240    &mut *self.0
241  }
242}
243
244impl AsRef<dyn Dependency> for UniqueDependency {
245  fn as_ref(&self) -> &(dyn Dependency + 'static) {
246    &*self.0
247  }
248}
249
250impl AsMut<dyn Dependency> for UniqueDependency {
251  fn as_mut(&mut self) -> &mut (dyn Dependency + 'static) {
252    &mut *self.0
253  }
254}
255
256impl Archive for UniqueDependency {
257  type Archived = ArchivedRc<<dyn Dependency as ArchiveUnsized>::Archived, DependencyRefFlavor>;
258  type Resolver = RcResolver;
259
260  fn resolve(&self, resolver: Self::Resolver, out: Place<Self::Archived>) {
261    ArchivedRc::resolve_from_ref(self.as_ref(), resolver, out);
262  }
263}
264
265impl<S> Serialize<S> for UniqueDependency
266where
267  dyn Dependency: SerializeUnsized<S>,
268  S: Writer + Sharing + Fallible + ?Sized,
269  S::Error: Source,
270{
271  fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
272    ArchivedRc::<
273      <dyn Dependency as ArchiveUnsized>::Archived,
274      DependencyRefFlavor,
275    >::serialize_from_ref(self.as_ref(), serializer)
276  }
277}
278
279impl<D> Deserialize<UniqueDependency, D>
280  for ArchivedRc<<dyn Dependency as ArchiveUnsized>::Archived, DependencyRefFlavor>
281where
282  <dyn Dependency as Pointee>::Metadata: Into<Metadata> + FromMetadata,
283  <dyn Dependency as ArchiveUnsized>::Archived: DeserializeUnsized<dyn Dependency, D>,
284  D: Fallible + ?Sized,
285  D::Error: Source,
286{
287  fn deserialize(&self, deserializer: &mut D) -> Result<UniqueDependency, D::Error> {
288    let metadata = self.get().deserialize_metadata();
289    let out = <DependencyRef as SharedPointer<dyn Dependency>>::alloc(metadata).into_error()?;
290    unsafe {
291      self.get().deserialize_unsized(deserializer, out)?;
292    }
293    let raw = unsafe { <DependencyRef as SharedPointer<dyn Dependency>>::from_value(out) };
294    let arc = unsafe { TriompheArc::from_raw(raw) };
295    let unique = UniqueArc::try_from(arc)
296      .unwrap_or_else(|_| unreachable!("a freshly deserialized dependency has one owner"));
297    Ok(UniqueDependency(unique))
298  }
299}
300
301/// Compatibility name for dependency construction sites. The backing allocation is a
302/// [`UniqueArc`], not a `Box`.
303pub type BoxDependency = UniqueDependency;
304
305/// A shared dependency published into the module graph.
306///
307/// This newtype also supplies rkyv with the dynamically sized allocation support that
308/// `triomphe::Arc` does not currently expose for trait objects.
309pub struct DependencyRef(TriompheArc<dyn Dependency>);
310
311impl DependencyRef {
312  pub fn new<D: Dependency + 'static>(dependency: D) -> Self {
313    UniqueDependency::new(dependency).shareable()
314  }
315}
316
317impl From<UniqueDependency> for DependencyRef {
318  fn from(dependency: UniqueDependency) -> Self {
319    dependency.shareable()
320  }
321}
322
323impl Clone for DependencyRef {
324  fn clone(&self) -> Self {
325    Self(self.0.clone())
326  }
327}
328
329impl Debug for DependencyRef {
330  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
331    Debug::fmt(self.as_ref(), f)
332  }
333}
334
335impl Deref for DependencyRef {
336  type Target = dyn Dependency;
337
338  fn deref(&self) -> &Self::Target {
339    &*self.0
340  }
341}
342
343impl AsRef<dyn Dependency> for DependencyRef {
344  fn as_ref(&self) -> &(dyn Dependency + 'static) {
345    &*self.0
346  }
347}
348
349pub struct DependencyRefFlavor;
350
351impl Flavor for DependencyRefFlavor {
352  const ALLOW_CYCLES: bool = false;
353}
354
355unsafe impl SharedPointer<dyn Dependency> for DependencyRef {
356  fn alloc(
357    metadata: <dyn Dependency as Pointee>::Metadata,
358  ) -> Result<*mut dyn Dependency, LayoutError> {
359    let value_layout = <dyn Dependency as LayoutRaw>::layout_raw(metadata)?;
360    let (layout, data_offset) = Layout::new::<AtomicUsize>().extend(value_layout)?;
361    let layout = layout.pad_to_align();
362    let allocation = unsafe { alloc(layout) };
363    if allocation.is_null() {
364      handle_alloc_error(layout);
365    }
366
367    unsafe {
368      ptr::write(allocation.cast::<AtomicUsize>(), AtomicUsize::new(1));
369      Ok(from_raw_parts_mut(
370        allocation.add(data_offset).cast(),
371        metadata,
372      ))
373    }
374  }
375
376  unsafe fn from_value(ptr: *mut dyn Dependency) -> *mut dyn Dependency {
377    ptr
378  }
379
380  unsafe fn drop(ptr: *mut dyn Dependency) {
381    drop(unsafe { TriompheArc::from_raw(ptr) });
382  }
383}
384
385impl Archive for DependencyRef {
386  type Archived = ArchivedRc<<dyn Dependency as ArchiveUnsized>::Archived, DependencyRefFlavor>;
387  type Resolver = RcResolver;
388
389  fn resolve(&self, resolver: Self::Resolver, out: Place<Self::Archived>) {
390    ArchivedRc::resolve_from_ref(self.as_ref(), resolver, out);
391  }
392}
393
394impl<S> Serialize<S> for DependencyRef
395where
396  dyn Dependency: SerializeUnsized<S>,
397  S: Writer + Sharing + Fallible + ?Sized,
398  S::Error: Source,
399{
400  fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
401    ArchivedRc::<
402      <dyn Dependency as ArchiveUnsized>::Archived,
403      DependencyRefFlavor,
404    >::serialize_from_ref(self.as_ref(), serializer)
405  }
406}
407
408impl<D> Deserialize<DependencyRef, D>
409  for ArchivedRc<<dyn Dependency as ArchiveUnsized>::Archived, DependencyRefFlavor>
410where
411  <dyn Dependency as Pointee>::Metadata: Into<Metadata> + FromMetadata,
412  <dyn Dependency as ArchiveUnsized>::Archived: DeserializeUnsized<dyn Dependency, D>,
413  D: Pooling + Fallible + ?Sized,
414  D::Error: Source,
415{
416  fn deserialize(&self, deserializer: &mut D) -> Result<DependencyRef, D::Error> {
417    let raw = deserializer.deserialize_shared::<_, DependencyRef>(self.get())?;
418    let arc = unsafe { TriompheArc::from_raw(raw) };
419    let _ = TriompheArc::into_raw(arc.clone());
420    Ok(DependencyRef(arc))
421  }
422}