Skip to main content

rspack_core/exports/
utils.rs

1use std::{borrow::Cow, hash::Hash, sync::atomic::AtomicU32};
2
3use either::Either;
4use rspack_cacheable::{
5  cacheable,
6  with::{AsPreset, AsVec},
7};
8use rspack_util::{atom::Atom, json_stringify, ryu_js};
9use rustc_hash::FxHashSet as HashSet;
10
11use crate::{DependencyId, property_access};
12
13pub static NEXT_EXPORTS_INFO_UKEY: AtomicU32 = AtomicU32::new(0);
14pub static NEXT_EXPORT_INFO_UKEY: AtomicU32 = AtomicU32::new(0);
15
16#[derive(Debug, Clone, Hash)]
17pub struct ExportInfoTargetValue {
18  pub dependency: Option<DependencyId>,
19  pub export: Option<Vec<Atom>>,
20  pub priority: u8,
21}
22
23pub enum ProvidedExports {
24  Unknown,
25  ProvidedAll,
26  ProvidedNames(Vec<Atom>),
27}
28
29pub enum UsedExports {
30  Unknown,
31  UsedNamespace(bool),
32  UsedNames(Vec<Atom>),
33}
34
35#[cacheable]
36#[derive(Debug, Clone)]
37pub enum EvaluatedInlinableValue {
38  Null,
39  Undefined,
40  Boolean(bool),
41  Number(f64),
42  String(#[cacheable(with=AsPreset)] Atom),
43}
44
45impl Hash for EvaluatedInlinableValue {
46  fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
47    std::mem::discriminant(self).hash(state);
48    match self {
49      EvaluatedInlinableValue::Boolean(v) => {
50        v.hash(state);
51      }
52      EvaluatedInlinableValue::Number(v) => {
53        v.to_bits().hash(state);
54      }
55      EvaluatedInlinableValue::String(atom) => {
56        atom.hash(state);
57      }
58      _ => {}
59    }
60  }
61}
62
63impl EvaluatedInlinableValue {
64  pub const SHORT_SIZE: usize = 6;
65
66  pub fn new_null() -> Self {
67    Self::Null
68  }
69
70  pub fn new_undefined() -> Self {
71    Self::Undefined
72  }
73
74  pub fn new_boolean(v: bool) -> Self {
75    Self::Boolean(v)
76  }
77
78  pub fn new_number(v: f64) -> Self {
79    Self::Number(v)
80  }
81
82  pub fn new_string(v: Atom) -> Self {
83    Self::String(v)
84  }
85
86  pub fn render(&self, comment: &str) -> String {
87    let s: Cow<str> = match self {
88      Self::Null => "null".into(),
89      Self::Undefined => "undefined".into(),
90      Self::Boolean(v) => if *v { "true" } else { "false" }.into(),
91      Self::Number(v) => {
92        let mut buf = ryu_js::Buffer::new();
93        buf.format(*v).to_string().into()
94      }
95      Self::String(v) => json_stringify(v.as_str()).into(),
96    };
97    format!("({comment}{s})")
98  }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
102pub enum CanInlineUse {
103  // Must have this initial state to get the correct dependency condition of inline value
104  // at flag_dependency_usage_plugin. If it's just bool and the initial state is true like
105  // mangleExports, then the dependency condition of inline value will be false and the
106  // flag_dependency_usage_plugin will not collect the usage of these dependency.
107  HasInfo,
108  Yes,
109  No,
110}
111
112#[derive(Debug, Clone, Hash)]
113pub enum UsedNameItem {
114  Str(Atom),
115  Inlined(EvaluatedInlinableValue),
116}
117
118#[derive(Debug, Clone)]
119pub struct InlinedUsedName {
120  value: EvaluatedInlinableValue,
121  suffix: Vec<Atom>,
122}
123
124impl InlinedUsedName {
125  pub fn new(value: EvaluatedInlinableValue) -> Self {
126    Self {
127      value,
128      suffix: Vec::new(),
129    }
130  }
131
132  pub fn render(&self, comment: &str) -> String {
133    let mut inlined = self.value.render(comment);
134    inlined.push_str(&property_access(&self.suffix, 0));
135    inlined
136  }
137
138  pub fn inlined_value(&self) -> &EvaluatedInlinableValue {
139    &self.value
140  }
141
142  pub fn suffix_ids(&self) -> &[Atom] {
143    &self.suffix
144  }
145}
146
147#[derive(Debug, Clone)]
148pub enum UsedName {
149  Normal(Vec<Atom>),
150  Inlined(InlinedUsedName),
151}
152
153impl UsedName {
154  pub fn append(&mut self, item: impl IntoIterator<Item = Atom>) {
155    match self {
156      UsedName::Normal(vec) => vec.extend(item),
157      UsedName::Inlined(inlined) => inlined.suffix.extend(item),
158    }
159  }
160}
161
162#[derive(Debug, Hash, Clone, Copy)]
163pub enum ExportProvided {
164  /// The export can be statically analyzed, and it is provided
165  Provided,
166  /// The export can be statically analyzed, and the it is not provided
167  NotProvided,
168  /// The export is unknown, we don't know if module really has this export, eg. cjs module
169  Unknown,
170}
171
172#[derive(Debug, Hash, PartialEq, Eq, Default, Clone)]
173pub struct UsageKey(pub Vec<Either<Box<UsageKey>, UsageState>>);
174
175impl UsageKey {
176  pub fn add(&mut self, value: Either<Box<UsageKey>, UsageState>) {
177    self.0.push(value);
178  }
179}
180
181pub type UsageFilterFnTy<T> = Box<dyn Fn(&T) -> bool>;
182
183#[derive(Debug, PartialEq, Copy, Clone, Default, Hash, PartialOrd, Ord, Eq)]
184pub enum UsageState {
185  Unused = 0,
186  OnlyPropertiesUsed = 1,
187  NoInfo = 2,
188  #[default]
189  Unknown = 3,
190  Used = 4,
191}
192
193#[cacheable]
194#[derive(Debug, Clone, PartialEq, Eq)]
195pub struct UsedByExports {
196  pub condition: UsedByExportsCondition,
197  #[cacheable(with=AsVec)]
198  pub deferred_pure_checks: Vec<UsedByExportsDeferredPureCheck>,
199}
200
201impl UsedByExports {
202  pub fn set(exports: HashSet<Atom>) -> Self {
203    Self {
204      condition: UsedByExportsCondition::Set(exports),
205      deferred_pure_checks: Vec::new(),
206    }
207  }
208
209  pub fn bool(used: bool) -> Self {
210    Self {
211      condition: UsedByExportsCondition::Bool(used),
212      deferred_pure_checks: Vec::new(),
213    }
214  }
215
216  pub fn with_deferred_pure_checks(
217    mut self,
218    deferred_pure_checks: Vec<UsedByExportsDeferredPureCheck>,
219  ) -> Self {
220    self.deferred_pure_checks = deferred_pure_checks;
221    self
222  }
223}
224
225#[cacheable]
226#[derive(Debug, Clone, PartialEq, Eq)]
227pub enum UsedByExportsCondition {
228  Set(#[cacheable(with=AsVec<AsPreset>)] HashSet<Atom>),
229  Bool(bool),
230}
231
232#[cacheable]
233#[derive(Debug, Clone, PartialEq, Eq, Hash)]
234pub struct UsedByExportsDeferredPureCheck {
235  pub dep_id: DependencyId,
236  #[cacheable(with=AsPreset)]
237  pub atom: Atom,
238}