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 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 Provided,
166 NotProvided,
168 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}