1use rustc_hash::FxHashMap;
12
13use crate::Effect;
14use crate::Type;
15use crate::type_config::{AliasingEffectConfig, AliasingSignatureConfig, ValueKind, ValueReason};
16
17pub const BUILT_IN_PROPS_ID: &str = "BuiltInProps";
22pub const BUILT_IN_ARRAY_ID: &str = "BuiltInArray";
23pub const BUILT_IN_SET_ID: &str = "BuiltInSet";
24pub const BUILT_IN_MAP_ID: &str = "BuiltInMap";
25pub const BUILT_IN_WEAK_SET_ID: &str = "BuiltInWeakSet";
26pub const BUILT_IN_WEAK_MAP_ID: &str = "BuiltInWeakMap";
27pub const BUILT_IN_FUNCTION_ID: &str = "BuiltInFunction";
28pub const BUILT_IN_JSX_ID: &str = "BuiltInJsx";
29pub const BUILT_IN_OBJECT_ID: &str = "BuiltInObject";
30pub const BUILT_IN_USE_STATE_ID: &str = "BuiltInUseState";
31pub const BUILT_IN_SET_STATE_ID: &str = "BuiltInSetState";
32pub const BUILT_IN_USE_ACTION_STATE_ID: &str = "BuiltInUseActionState";
33pub const BUILT_IN_SET_ACTION_STATE_ID: &str = "BuiltInSetActionState";
34pub const BUILT_IN_USE_REF_ID: &str = "BuiltInUseRefId";
35pub const BUILT_IN_REF_VALUE_ID: &str = "BuiltInRefValue";
36pub const BUILT_IN_MIXED_READONLY_ID: &str = "BuiltInMixedReadonly";
37pub const BUILT_IN_USE_EFFECT_HOOK_ID: &str = "BuiltInUseEffectHook";
38pub const BUILT_IN_USE_LAYOUT_EFFECT_HOOK_ID: &str = "BuiltInUseLayoutEffectHook";
39pub const BUILT_IN_USE_INSERTION_EFFECT_HOOK_ID: &str = "BuiltInUseInsertionEffectHook";
40pub const BUILT_IN_USE_OPERATOR_ID: &str = "BuiltInUseOperator";
41pub const BUILT_IN_USE_REDUCER_ID: &str = "BuiltInUseReducer";
42pub const BUILT_IN_DISPATCH_ID: &str = "BuiltInDispatch";
43pub const BUILT_IN_USE_CONTEXT_HOOK_ID: &str = "BuiltInUseContextHook";
44pub const BUILT_IN_USE_TRANSITION_ID: &str = "BuiltInUseTransition";
45pub const BUILT_IN_USE_OPTIMISTIC_ID: &str = "BuiltInUseOptimistic";
46pub const BUILT_IN_SET_OPTIMISTIC_ID: &str = "BuiltInSetOptimistic";
47pub const BUILT_IN_START_TRANSITION_ID: &str = "BuiltInStartTransition";
48pub const BUILT_IN_USE_EFFECT_EVENT_ID: &str = "BuiltInUseEffectEvent";
49pub const BUILT_IN_EFFECT_EVENT_ID: &str = "BuiltInEffectEventFunction";
50pub const REANIMATED_SHARED_VALUE_ID: &str = "ReanimatedSharedValueId";
51
52#[derive(Debug, Clone, PartialEq, Eq)]
57pub enum HookKind {
58 UseContext,
59 UseState,
60 UseActionState,
61 UseReducer,
62 UseRef,
63 UseEffect,
64 UseLayoutEffect,
65 UseInsertionEffect,
66 UseMemo,
67 UseCallback,
68 UseTransition,
69 UseImperativeHandle,
70 UseEffectEvent,
71 UseOptimistic,
72 Custom,
73}
74
75impl std::fmt::Display for HookKind {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 match self {
78 HookKind::UseContext => write!(f, "useContext"),
79 HookKind::UseState => write!(f, "useState"),
80 HookKind::UseActionState => write!(f, "useActionState"),
81 HookKind::UseReducer => write!(f, "useReducer"),
82 HookKind::UseRef => write!(f, "useRef"),
83 HookKind::UseEffect => write!(f, "useEffect"),
84 HookKind::UseLayoutEffect => write!(f, "useLayoutEffect"),
85 HookKind::UseInsertionEffect => write!(f, "useInsertionEffect"),
86 HookKind::UseMemo => write!(f, "useMemo"),
87 HookKind::UseCallback => write!(f, "useCallback"),
88 HookKind::UseTransition => write!(f, "useTransition"),
89 HookKind::UseImperativeHandle => write!(f, "useImperativeHandle"),
90 HookKind::UseEffectEvent => write!(f, "useEffectEvent"),
91 HookKind::UseOptimistic => write!(f, "useOptimistic"),
92 HookKind::Custom => write!(f, "Custom"),
93 }
94 }
95}
96
97#[derive(Debug, Clone)]
100pub struct FunctionSignature {
101 pub positional_params: Vec<Effect>,
102 pub rest_param: Option<Effect>,
103 pub return_type: Type,
104 pub return_value_kind: ValueKind,
105 pub return_value_reason: Option<ValueReason>,
106 pub callee_effect: Effect,
107 pub hook_kind: Option<HookKind>,
108 pub no_alias: bool,
109 pub mutable_only_if_operands_are_mutable: bool,
110 pub impure: bool,
111 pub known_incompatible: Option<String>,
112 pub canonical_name: Option<String>,
113 pub aliasing: Option<AliasingSignatureConfig>,
116}
117
118#[derive(Debug, Clone)]
121pub struct ObjectShape {
122 pub properties: FxHashMap<String, Type>,
123 pub function_type: Option<FunctionSignature>,
124}
125
126pub struct ShapeRegistry {
135 base: Option<&'static FxHashMap<String, ObjectShape>>,
136 entries: FxHashMap<String, ObjectShape>,
137}
138
139impl ShapeRegistry {
140 pub fn new() -> Self {
142 Self {
143 base: None,
144 entries: FxHashMap::default(),
145 }
146 }
147
148 pub fn with_base(base: &'static FxHashMap<String, ObjectShape>) -> Self {
150 Self {
151 base: Some(base),
152 entries: FxHashMap::default(),
153 }
154 }
155
156 pub fn get(&self, key: &str) -> Option<&ObjectShape> {
157 self.entries
158 .get(key)
159 .or_else(|| self.base.and_then(|b| b.get(key)))
160 }
161
162 pub fn insert(&mut self, key: String, value: ObjectShape) {
163 self.entries.insert(key, value);
164 }
165
166 pub fn into_inner(self) -> FxHashMap<String, ObjectShape> {
169 debug_assert!(
170 self.base.is_none(),
171 "into_inner() called on overlay-mode ShapeRegistry"
172 );
173 self.entries
174 }
175}
176
177impl Clone for ShapeRegistry {
178 fn clone(&self) -> Self {
179 Self {
180 base: self.base,
181 entries: self.entries.clone(),
182 }
183 }
184}
185
186fn next_anon_id() -> String {
193 use std::sync::atomic::{AtomicU32, Ordering};
194 static COUNTER: AtomicU32 = AtomicU32::new(0);
195 let id = COUNTER.fetch_add(1, Ordering::Relaxed);
196 format!("<generated_{}>", id)
197}
198
199pub fn add_function(
206 registry: &mut ShapeRegistry,
207 properties: Vec<(String, Type)>,
208 sig: FunctionSignatureBuilder,
209 id: Option<&str>,
210 is_constructor: bool,
211) -> Type {
212 let shape_id = id.map(|s| s.to_string()).unwrap_or_else(next_anon_id);
213 let return_type = sig.return_type.clone();
214 add_shape(
215 registry,
216 &shape_id,
217 properties,
218 Some(FunctionSignature {
219 positional_params: sig.positional_params,
220 rest_param: sig.rest_param,
221 return_type: sig.return_type,
222 return_value_kind: sig.return_value_kind,
223 return_value_reason: sig.return_value_reason,
224 callee_effect: sig.callee_effect,
225 hook_kind: None,
226 no_alias: sig.no_alias,
227 mutable_only_if_operands_are_mutable: sig.mutable_only_if_operands_are_mutable,
228 impure: sig.impure,
229 known_incompatible: sig.known_incompatible,
230 canonical_name: sig.canonical_name,
231 aliasing: sig.aliasing,
232 }),
233 );
234 Type::Function {
235 shape_id: Some(shape_id),
236 return_type: Box::new(return_type),
237 is_constructor,
238 }
239}
240
241pub fn add_hook(registry: &mut ShapeRegistry, sig: HookSignatureBuilder, id: Option<&str>) -> Type {
244 let shape_id = id.map(|s| s.to_string()).unwrap_or_else(next_anon_id);
245 let return_type = sig.return_type.clone();
246 add_shape(
247 registry,
248 &shape_id,
249 Vec::new(),
250 Some(FunctionSignature {
251 positional_params: sig.positional_params,
252 rest_param: sig.rest_param,
253 return_type: sig.return_type,
254 return_value_kind: sig.return_value_kind,
255 return_value_reason: sig.return_value_reason,
256 callee_effect: sig.callee_effect,
257 hook_kind: Some(sig.hook_kind),
258 no_alias: sig.no_alias,
259 mutable_only_if_operands_are_mutable: false,
260 impure: false,
261 known_incompatible: sig.known_incompatible,
262 canonical_name: None,
263 aliasing: sig.aliasing,
264 }),
265 );
266 Type::Function {
267 shape_id: Some(shape_id),
268 return_type: Box::new(return_type),
269 is_constructor: false,
270 }
271}
272
273pub fn add_object(
276 registry: &mut ShapeRegistry,
277 id: Option<&str>,
278 properties: Vec<(String, Type)>,
279) -> Type {
280 let shape_id = id.map(|s| s.to_string()).unwrap_or_else(next_anon_id);
281 add_shape(registry, &shape_id, properties, None);
282 Type::Object {
283 shape_id: Some(shape_id),
284 }
285}
286
287fn add_shape(
288 registry: &mut ShapeRegistry,
289 id: &str,
290 properties: Vec<(String, Type)>,
291 function_type: Option<FunctionSignature>,
292) {
293 let shape = ObjectShape {
294 properties: properties.into_iter().collect(),
295 function_type,
296 };
297 registry.insert(id.to_string(), shape);
301}
302
303pub struct FunctionSignatureBuilder {
309 pub positional_params: Vec<Effect>,
310 pub rest_param: Option<Effect>,
311 pub return_type: Type,
312 pub return_value_kind: ValueKind,
313 pub return_value_reason: Option<ValueReason>,
314 pub callee_effect: Effect,
315 pub no_alias: bool,
316 pub mutable_only_if_operands_are_mutable: bool,
317 pub impure: bool,
318 pub known_incompatible: Option<String>,
319 pub canonical_name: Option<String>,
320 pub aliasing: Option<AliasingSignatureConfig>,
321}
322
323impl Default for FunctionSignatureBuilder {
324 fn default() -> Self {
325 Self {
326 positional_params: Vec::new(),
327 rest_param: None,
328 return_type: Type::Poly,
329 return_value_kind: ValueKind::Mutable,
330 return_value_reason: None,
331 callee_effect: Effect::Read,
332 no_alias: false,
333 mutable_only_if_operands_are_mutable: false,
334 impure: false,
335 known_incompatible: None,
336 canonical_name: None,
337 aliasing: None,
338 }
339 }
340}
341
342pub struct HookSignatureBuilder {
344 pub positional_params: Vec<Effect>,
345 pub rest_param: Option<Effect>,
346 pub return_type: Type,
347 pub return_value_kind: ValueKind,
348 pub return_value_reason: Option<ValueReason>,
349 pub callee_effect: Effect,
350 pub hook_kind: HookKind,
351 pub no_alias: bool,
352 pub known_incompatible: Option<String>,
353 pub aliasing: Option<AliasingSignatureConfig>,
354}
355
356impl Default for HookSignatureBuilder {
357 fn default() -> Self {
358 Self {
359 positional_params: Vec::new(),
360 rest_param: None,
361 return_type: Type::Poly,
362 return_value_kind: ValueKind::Frozen,
363 return_value_reason: None,
364 callee_effect: Effect::Read,
365 hook_kind: HookKind::Custom,
366 no_alias: false,
367 known_incompatible: None,
368 aliasing: None,
369 }
370 }
371}
372
373pub fn default_nonmutating_hook(registry: &mut ShapeRegistry) -> Type {
380 add_hook(
381 registry,
382 HookSignatureBuilder {
383 rest_param: Some(Effect::Freeze),
384 return_type: Type::Poly,
385 return_value_kind: ValueKind::Frozen,
386 hook_kind: HookKind::Custom,
387 aliasing: Some(AliasingSignatureConfig {
388 receiver: "@receiver".to_string(),
389 params: Vec::new(),
390 rest: Some("@rest".to_string()),
391 returns: "@returns".to_string(),
392 temporaries: Vec::new(),
393 effects: vec![
394 AliasingEffectConfig::Freeze {
396 value: "@rest".to_string(),
397 reason: ValueReason::HookCaptured,
398 },
399 AliasingEffectConfig::Create {
401 into: "@returns".to_string(),
402 value: ValueKind::Frozen,
403 reason: ValueReason::HookReturn,
404 },
405 AliasingEffectConfig::Alias {
407 from: "@rest".to_string(),
408 into: "@returns".to_string(),
409 },
410 ],
411 }),
412 ..Default::default()
413 },
414 Some("DefaultNonmutatingHook"),
415 )
416}
417
418pub fn default_mutating_hook(registry: &mut ShapeRegistry) -> Type {
421 add_hook(
422 registry,
423 HookSignatureBuilder {
424 rest_param: Some(Effect::ConditionallyMutate),
425 return_type: Type::Poly,
426 return_value_kind: ValueKind::Mutable,
427 hook_kind: HookKind::Custom,
428 ..Default::default()
429 },
430 Some("DefaultMutatingHook"),
431 )
432}