1use std::collections::HashMap;
12
13use crate::type_config::{AliasingEffectConfig, AliasingSignatureConfig, ValueKind, ValueReason};
14use crate::Effect;
15use crate::Type;
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: HashMap<String, Type>,
123 pub function_type: Option<FunctionSignature>,
124}
125
126pub struct ShapeRegistry {
135 base: Option<&'static HashMap<String, ObjectShape>>,
136 entries: HashMap<String, ObjectShape>,
137}
138
139impl ShapeRegistry {
140 pub fn new() -> Self {
142 Self {
143 base: None,
144 entries: HashMap::new(),
145 }
146 }
147
148 pub fn with_base(base: &'static HashMap<String, ObjectShape>) -> Self {
150 Self {
151 base: Some(base),
152 entries: HashMap::new(),
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) -> HashMap<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(
244 registry: &mut ShapeRegistry,
245 sig: HookSignatureBuilder,
246 id: Option<&str>,
247) -> Type {
248 let shape_id = id.map(|s| s.to_string()).unwrap_or_else(next_anon_id);
249 let return_type = sig.return_type.clone();
250 add_shape(
251 registry,
252 &shape_id,
253 Vec::new(),
254 Some(FunctionSignature {
255 positional_params: sig.positional_params,
256 rest_param: sig.rest_param,
257 return_type: sig.return_type,
258 return_value_kind: sig.return_value_kind,
259 return_value_reason: sig.return_value_reason,
260 callee_effect: sig.callee_effect,
261 hook_kind: Some(sig.hook_kind),
262 no_alias: sig.no_alias,
263 mutable_only_if_operands_are_mutable: false,
264 impure: false,
265 known_incompatible: sig.known_incompatible,
266 canonical_name: None,
267 aliasing: sig.aliasing,
268 }),
269 );
270 Type::Function {
271 shape_id: Some(shape_id),
272 return_type: Box::new(return_type),
273 is_constructor: false,
274 }
275}
276
277pub fn add_object(
280 registry: &mut ShapeRegistry,
281 id: Option<&str>,
282 properties: Vec<(String, Type)>,
283) -> Type {
284 let shape_id = id.map(|s| s.to_string()).unwrap_or_else(next_anon_id);
285 add_shape(registry, &shape_id, properties, None);
286 Type::Object {
287 shape_id: Some(shape_id),
288 }
289}
290
291fn add_shape(
292 registry: &mut ShapeRegistry,
293 id: &str,
294 properties: Vec<(String, Type)>,
295 function_type: Option<FunctionSignature>,
296) {
297 let shape = ObjectShape {
298 properties: properties.into_iter().collect(),
299 function_type,
300 };
301 registry.insert(id.to_string(), shape);
305}
306
307pub struct FunctionSignatureBuilder {
313 pub positional_params: Vec<Effect>,
314 pub rest_param: Option<Effect>,
315 pub return_type: Type,
316 pub return_value_kind: ValueKind,
317 pub return_value_reason: Option<ValueReason>,
318 pub callee_effect: Effect,
319 pub no_alias: bool,
320 pub mutable_only_if_operands_are_mutable: bool,
321 pub impure: bool,
322 pub known_incompatible: Option<String>,
323 pub canonical_name: Option<String>,
324 pub aliasing: Option<AliasingSignatureConfig>,
325}
326
327impl Default for FunctionSignatureBuilder {
328 fn default() -> Self {
329 Self {
330 positional_params: Vec::new(),
331 rest_param: None,
332 return_type: Type::Poly,
333 return_value_kind: ValueKind::Mutable,
334 return_value_reason: None,
335 callee_effect: Effect::Read,
336 no_alias: false,
337 mutable_only_if_operands_are_mutable: false,
338 impure: false,
339 known_incompatible: None,
340 canonical_name: None,
341 aliasing: None,
342 }
343 }
344}
345
346pub struct HookSignatureBuilder {
348 pub positional_params: Vec<Effect>,
349 pub rest_param: Option<Effect>,
350 pub return_type: Type,
351 pub return_value_kind: ValueKind,
352 pub return_value_reason: Option<ValueReason>,
353 pub callee_effect: Effect,
354 pub hook_kind: HookKind,
355 pub no_alias: bool,
356 pub known_incompatible: Option<String>,
357 pub aliasing: Option<AliasingSignatureConfig>,
358}
359
360impl Default for HookSignatureBuilder {
361 fn default() -> Self {
362 Self {
363 positional_params: Vec::new(),
364 rest_param: None,
365 return_type: Type::Poly,
366 return_value_kind: ValueKind::Frozen,
367 return_value_reason: None,
368 callee_effect: Effect::Read,
369 hook_kind: HookKind::Custom,
370 no_alias: false,
371 known_incompatible: None,
372 aliasing: None,
373 }
374 }
375}
376
377pub fn default_nonmutating_hook(registry: &mut ShapeRegistry) -> Type {
384 add_hook(
385 registry,
386 HookSignatureBuilder {
387 rest_param: Some(Effect::Freeze),
388 return_type: Type::Poly,
389 return_value_kind: ValueKind::Frozen,
390 hook_kind: HookKind::Custom,
391 aliasing: Some(AliasingSignatureConfig {
392 receiver: "@receiver".to_string(),
393 params: Vec::new(),
394 rest: Some("@rest".to_string()),
395 returns: "@returns".to_string(),
396 temporaries: Vec::new(),
397 effects: vec![
398 AliasingEffectConfig::Freeze {
400 value: "@rest".to_string(),
401 reason: ValueReason::HookCaptured,
402 },
403 AliasingEffectConfig::Create {
405 into: "@returns".to_string(),
406 value: ValueKind::Frozen,
407 reason: ValueReason::HookReturn,
408 },
409 AliasingEffectConfig::Alias {
411 from: "@rest".to_string(),
412 into: "@returns".to_string(),
413 },
414 ],
415 }),
416 ..Default::default()
417 },
418 Some("DefaultNonmutatingHook"),
419 )
420}
421
422pub fn default_mutating_hook(registry: &mut ShapeRegistry) -> Type {
425 add_hook(
426 registry,
427 HookSignatureBuilder {
428 rest_param: Some(Effect::ConditionallyMutate),
429 return_type: Type::Poly,
430 return_value_kind: ValueKind::Mutable,
431 hook_kind: HookKind::Custom,
432 ..Default::default()
433 },
434 Some("DefaultMutatingHook"),
435 )
436}