fre_rs/context.rs
1//!
2//! Core implementation of the extension abstraction.
3//!
4
5
6use super::*;
7
8
9pub(crate) type ContextHandle = NonNull<c_void>;
10
11
12/// The current ANE context, on which most APIs in this crate depend.
13///
14/// The lifetime is strictly tied to the current context method call stack.
15///
16/// # Invariant
17///
18/// During any context-related call, the current context is guaranteed to be
19/// valid, and its associated `ExtensionContext` object must not call `dispose`.
20///
21/// Violating this invariant may cause subsequent API calls to fail and lead to
22/// rapidly increasing complexity in error handling. This crate treats such
23/// situations as invalid state and does not attempt to recover from them.
24///
25#[derive(Debug)]
26#[repr(transparent)]
27pub struct CurrentContext<'a> (ContextHandle, PhantomData<&'a()>);
28impl<'a> CurrentContext<'a> {
29
30 /// Returns the context type associated with the current context.
31 ///
32 /// This corresponds to the `contextType` argument passed to
33 /// `ExtensionContext.createExtensionContext`.
34 ///
35 /// Returns [`None`] if that argument was `null`.
36 ///
37 pub fn ty(&self) -> Option<UCStr> {self.ctx_reg().context_type()}
38
39 /// Returns an immutable reference to the Context Data associated with the current context.
40 ///
41 /// Context Data is user-defined data bound to the context, sharing the same
42 /// lifetime as the context itself.
43 ///
44 /// It can only be set via the first return value of [`ContextInitializer`].
45 ///
46 pub fn data(&self) -> Option<&dyn Any> {self.ctx_reg().context_data()}
47
48 /// Returns a mutable reference to the Context Data associated with the current context.
49 ///
50 /// Context Data is user-defined data bound to the context, sharing the same
51 /// lifetime as the context itself.
52 ///
53 /// It can only be set via the first return value of [`ContextInitializer`].
54 ///
55 pub fn data_mut(&mut self) -> Option<&mut dyn Any> {self.ctx_reg_mut().context_data_mut()}
56
57 /// Calls a method associated with the current context.
58 ///
59 /// Methods can only be set via the second return value of [`ContextInitializer`].
60 ///
61 /// [`Err`]=> [`ContextError::MethodsNotRegistered`], [`ContextError::MethodNotFound`];
62 ///
63 pub fn call_method (&mut self, name: &str, args: Option<&[as3::Object<'a>]> ) -> Result<as3::Object<'a>, ContextError> {
64 self.ctx_reg_mut().methods.as_ref()
65 .ok_or(ContextError::MethodsNotRegistered)
66 .map(|ms| ms.get(name))?
67 .ok_or(ContextError::MethodNotFound)
68 .map(|(func, data)| {
69 let args = args.unwrap_or_default();
70 let argc = args.len() as u32;
71 let argv = args.as_ptr() as *const FREObject;
72 let r = unsafe {func(self.as_ptr(), data, argc, argv)};
73 unsafe {transmute(r)}
74 })
75 }
76
77 /// Returns the ActionScript-side Context Data associated with the current context.
78 ///
79 /// `ExtensionContext.actionScriptData`
80 ///
81 pub fn get_actionscript_data (&self) -> as3::Object<'a>
82 {self.as_cooperative_ctx().get_actionscript_data().expect("INVARIANT: `CurrentContext` is always valid.")}
83
84 /// Sets the ActionScript-side Context Data associated with the current context.
85 ///
86 /// `ExtensionContext.actionScriptData`
87 ///
88 pub fn set_actionscript_data (&self, object: as3::Object<'_>)
89 {self.as_cooperative_ctx().set_actionscript_data(object).expect("INVARIANT: `CurrentContext` is always valid.");}
90
91 /// Returns the associated context from an `ExtensionContext` object.
92 ///
93 /// # Safety
94 ///
95 /// `context` must be another context constructed by the current
96 /// extension via [`ContextInitializer`]. Otherwise, the invariants
97 /// of [`CooperativeContext`] are violated, and its internal APIs
98 /// for accessing native data will result in undefined behavior.
99 ///
100 /// # Panic
101 ///
102 /// Panics if `context` is not an `ExtensionContext` object,
103 /// or if it is associated with the current context.
104 ///
105 #[allow(unsafe_op_in_unsafe_fn)]
106 pub unsafe fn cooperative_context_from_object(&self, context: as3::Object<'a>) -> CooperativeContext<'a> {
107 transmute(self.foreign_context_from_object(context))
108 }
109
110 /// Returns the associated context from an `ExtensionContext` object.
111 ///
112 /// # Panic
113 ///
114 /// Panics if `context` is not an `ExtensionContext` object,
115 /// or if it is associated with the current context.
116 ///
117 pub fn foreign_context_from_object(&self, context: as3::Object<'a>) -> ForeignContext<'a> {
118 let mut ptr = std::ptr::null_mut();
119 let r = unsafe {FREGetFREContextFromExtensionContext(context.as_ptr(), &mut ptr)};
120 assert!(r.is_ok(), "{}", FfiError::try_from(r).expect("The result must be error."));
121 assert!(!ptr.is_null());
122 assert_ne!(ptr, self.as_ptr(), "INVARIANT: `CurrentContext` is unique.");
123 unsafe {transmute(ptr)}
124 }
125
126}
127impl<'a> CurrentContext<'a> {
128
129 /// A wrapper used by [`FREContextInitializer`], [`FREContextFinalizer`], and
130 /// [`FREFunction`] that provides a safe stack-level execution environment.
131 ///
132 /// **In typical usage of this crate, this function should not be called directly.**
133 ///
134 /// # Safety
135 ///
136 /// While all operations performed within this function are safe at the stack level,
137 /// calling this function itself is unsafe and requires that all input arguments
138 /// are valid. In particular, this function assumes it is invoked directly with
139 /// arguments provided by the Flash runtime.
140 ///
141 /// Violating these assumptions may lead to undefined behavior.
142 ///
143 #[allow(unsafe_op_in_unsafe_fn)]
144 pub unsafe fn with <F, R> (ctx: &'a FREContext, f: F) -> R
145 where
146 F: FnOnce (&CurrentContext<'a>) -> R,
147 R: 'a,
148 {
149 let ctx = Self::new(ctx);
150 let r = f(&ctx);
151 r
152 }
153
154 /// A wrapper around [`FREContextInitializer`] that provides a safe stack-level
155 /// execution environment for context initialization.
156 ///
157 /// **In typical usage of this crate, this function should not be called directly.**
158 ///
159 /// # Safety
160 ///
161 /// While all operations performed within this function are safe at the stack level,
162 /// calling this function itself is unsafe and requires the following conditions:
163 ///
164 /// - The native data associated with [`Context`] must not be accessed or managed
165 /// by external code.
166 /// - This function will construct a [`ContextRegistry`] and assign it as the native data.
167 /// The constructed [`ContextRegistry`] must be properly disposed in
168 /// [`FREContextFinalizer`] to ensure its lifecycle is correctly terminated.
169 /// - This function assumes it is invoked directly with arguments provided by the
170 /// Flash runtime, meaning all arguments must be valid and consistent.
171 ///
172 /// Violating these assumptions may lead to undefined behavior.
173 ///
174 #[allow(unsafe_op_in_unsafe_fn)]
175 pub unsafe fn with_context_initializer <F> (
176 ext_data: FREData,// &'extension mut
177 ctx_type: FREStr,// &'function
178 ctx: &'a FREContext,// &'function
179 num_funcs_to_set: *mut u32,// return
180 funcs_to_set: *mut *const FRENamedFunction,// return &'context mut
181 f: F
182 )
183 where F: FnOnce (&CurrentContext<'a>) -> (Option<Box<dyn Any>>, FunctionSet)
184 {
185 assert!(!num_funcs_to_set.is_null());
186 assert!(!funcs_to_set.is_null());
187 Self::with(ctx, |ctx|{
188 let ctx_type = if ctx_type.is_null() {None} else {
189 let ctx_type = CStr::from_ptr(ctx_type as *const c_char);
190 let ctx_type = UCStr::try_from(ctx_type).expect("Input string is not valid UTF-8.");
191 Some(ctx_type)
192 };
193 let ctx_reg = ContextRegistry::new(ext_data, ctx_type).into_raw();
194 let r = ForeignContext(ctx.0, PhantomData).set_native_data(Some(ctx_reg));// <'context> move
195 assert!(r.is_ok());
196 let (ctx_data, funcs) = f(ctx);
197 let methods = MethodSet::from(funcs);
198 let r = methods.as_ref();
199 debug_assert!(r.len() <= u32::MAX as usize);
200 *num_funcs_to_set = r.len() as u32;
201 *funcs_to_set = r.as_ptr();
202 let ctx_reg = RefCell::<ContextRegistry>::mut_from(ctx_reg).unwrap();
203 let mut ctx_reg_mut = ctx_reg.borrow_mut();
204 ctx_reg_mut.ctx_data = ctx_data;
205 ctx_reg_mut.methods = Some(methods);
206 })
207 }
208
209 /// A wrapper around [`FREFunction`] that provides a safe stack-level execution
210 /// environment for the given closure.
211 ///
212 /// **In typical usage of this crate, this function should not be called directly.**
213 ///
214 /// # Safety
215 ///
216 /// While all operations performed within this function are safe at the stack level,
217 /// calling this function itself is unsafe and requires the following conditions:
218 ///
219 /// - `func_data` must either be constructed via [`Data::into_raw`] before
220 /// [`ContextInitializer`] returns, or be a null pointer.
221 /// - This function assumes it is invoked directly with arguments provided by the
222 /// Flash runtime, meaning all arguments must be valid and consistent.
223 ///
224 /// Violating these assumptions may lead to undefined behavior.
225 ///
226 #[allow(unsafe_op_in_unsafe_fn)]
227 pub unsafe fn with_method <F, R> (
228 ctx: &'a FREContext,// &'function
229 func_data: FREData,// &'function mut
230 argc: u32,
231 argv: *const FREObject,// &'function
232 f: F
233 ) -> FREObject
234 where
235 F: FnOnce (&CurrentContext<'a>, Option<&mut dyn Any>, &[as3::Object<'a>]) -> R,
236 R: Into<as3::Object<'a>> + 'a
237 {
238 assert!(!argv.is_null() || argc==0);
239 Self::with(ctx, |ctx| {
240 let func_data = NonNullFREData::new(func_data)
241 .map(|raw| crate::data::mut_from(raw));
242 let args = std::slice::from_raw_parts(argv as *const as3::Object, argc as usize);
243 f(ctx, func_data, args).into().as_ptr()
244 })
245 }
246
247}
248impl<'a> CurrentContext<'a> {
249 fn new(ctx: &'a FREContext) -> Self {
250 Self(ContextHandle::new(*ctx).expect("INVARIANT: `CurrentContext` is always valid."), PhantomData)
251 }
252 fn as_cooperative_ctx(&self) -> CooperativeContext<'a> {unsafe {transmute(self.0)}}
253 fn ctx_reg(&self) -> &ContextRegistry {
254 let ptr = self.as_cooperative_ctx()
255 .with(|ctx_reg|ctx_reg as *const ContextRegistry)
256 .expect("INVARIANT: `CurrentContext` is unique.");
257 unsafe {&*(ptr)}
258 }
259 fn ctx_reg_mut(&mut self) -> &mut ContextRegistry {
260 let ptr = self.as_cooperative_ctx()
261 .with_mut(|ctx_reg|ctx_reg as *mut ContextRegistry)
262 .expect("INVARIANT: `CurrentContext` is unique.");
263 unsafe {&mut *(ptr)}
264 }
265}
266impl Sealed for CurrentContext<'_> {}
267impl Context for CurrentContext<'_> {
268 fn as_handle (&self) -> ContextHandle {self.0}
269 fn is_valid(&self) -> bool {
270 debug_assert!(self.as_cooperative_ctx().is_valid());
271 true
272 }
273}
274
275
276/// A handle to a context created by the current extension,
277/// which may become invalid under specific conditions.
278///
279/// Can only be obtained through [`CurrentContext::cooperative_context_from_object`].
280///
281/// Invalidity only occurs after the associated `ExtensionContext` object
282/// has been disposed. Therefore, callers should be prepared for operations
283/// on the context to fail at appropriate points.
284///
285/// This crate leverages [`FREGetFREContextFromExtensionContext`] to enable
286/// more advanced use cases, but doing so also increases overall complexity.
287///
288/// # Invariant
289///
290/// The context must have been constructed by the current extension via
291/// [`ContextInitializer`], and it must not be the [`CurrentContext`].
292/// Violating these invariants may results in undefined behavior.
293///
294#[derive(Debug, Clone, Copy, PartialEq, Eq)]
295#[repr(transparent)]
296pub struct CooperativeContext <'a> (ContextHandle, PhantomData<&'a()>);
297impl<'a> CooperativeContext<'a> {
298
299 /// Provides immutable access to the [`ContextRegistry`] within a closure.
300 ///
301 /// [`Err`]=> [`ContextError::InvalidContext`], [`ContextError::NullRegistry`], [`ContextError::InvalidRegistry`], [`ContextError::FfiCallFailed`], [`ContextError::BorrowRegistryConflict`];
302 ///
303 pub fn with <F, R> (self, f: F) -> Result<R, ContextError>
304 where F: FnOnce (&ContextRegistry) -> R {
305 if !self.is_valid() {return Err(ContextError::InvalidContext)}
306 let handle = self.as_foreign_ctx().get_native_data()?
307 .ok_or(ContextError::NullRegistry)?;
308 let cell = unsafe {RefCell::<ContextRegistry>::ref_from(handle)}
309 .map_err(|_| ContextError::InvalidRegistry)?;
310 let ctx_reg = cell.try_borrow()
311 .map_err(|_| ContextError::BorrowRegistryConflict)?;
312 let r = f(&ctx_reg);
313 Ok(r)
314 }
315
316 /// Provides mutable access to the [`ContextRegistry`] within a closure.
317 ///
318 /// [`Err`]=> [`Self::with`];
319 ///
320 pub fn with_mut <F, R> (self, f: F) -> Result<R, ContextError>
321 where F: FnOnce (&mut ContextRegistry) -> R {
322 if !self.is_valid() {return Err(ContextError::InvalidContext)}
323 let handle = self.as_foreign_ctx().get_native_data()?
324 .ok_or(ContextError::NullRegistry)?;
325 let cell = unsafe {RefCell::<ContextRegistry>::ref_from(handle)}
326 .map_err(|_| ContextError::InvalidRegistry)?;
327 let mut ctx_reg = cell.try_borrow_mut()
328 .map_err(|_| ContextError::BorrowRegistryConflict)?;
329 let r = f(&mut ctx_reg);
330 Ok(r)
331 }
332
333 /// Calls a registered function by name through an internal call within the current extension.
334 ///
335 /// Nested calls increase complexity. Callers must consider borrowing rules and context validity.
336 ///
337 /// [`Err`]=> [`Self::with`], [`ContextError::MethodNotFound`];
338 ///
339 pub fn call_method (self, name: &str, args: Option<&[as3::Object<'a>]> ) -> Result<as3::Object<'a>, ContextError> {
340 let (func, data) = self.with(|ctx_reg| {
341 ctx_reg.methods.as_ref()
342 .expect("INVARIANT: `CooperativeContext` is not current context and has been initialized with `MethodSet`.")
343 .get(name)
344 .ok_or(ContextError::MethodNotFound)
345 })??;
346 let args = args.unwrap_or_default();
347 let argc = args.len() as u32;
348 let argv = args.as_ptr() as *const FREObject;
349 let r = unsafe {func(self.as_ptr(), data, argc, argv)};
350 Ok(unsafe {transmute(r)})
351 }
352
353 /// Returns the ActionScript-side Context Data associated with the context.
354 ///
355 /// `ExtensionContext.actionScriptData`
356 ///
357 /// Only fails if the context is invalid.
358 ///
359 pub fn get_actionscript_data (self) -> Result<as3::Object<'a>, FfiError>
360 {self.as_foreign_ctx().get_actionscript_data()}
361
362
363 /// Sets the ActionScript-side Context Data associated with the context.
364 ///
365 /// `ExtensionContext.actionScriptData`
366 ///
367 /// Only fails if the context is invalid.
368 ///
369 pub fn set_actionscript_data (self, object: as3::Object<'_>) -> Result<(), FfiError>
370 {self.as_foreign_ctx().set_actionscript_data(object)}
371
372
373 fn as_foreign_ctx(self) -> ForeignContext<'a> {unsafe {transmute(self)}}
374}
375impl Sealed for CooperativeContext<'_> {}
376impl Context for CooperativeContext<'_> {
377 fn as_handle (&self) -> ContextHandle {self.0}
378 fn is_valid(&self) -> bool {self.get_actionscript_data().is_ok()}
379}
380
381
382/// A handle to a context that may become invalid under specific conditions.
383///
384/// Can only be obtained through [`CurrentContext::foreign_context_from_object`].
385///
386/// Assumes the context was NOT constructed by the current extension.
387/// Accessing its associated native data is therefore unsafe.
388///
389/// Invalidity only occurs after the associated `ExtensionContext` object
390/// has been disposed. Therefore, callers should be prepared for operations
391/// on the context to fail at appropriate points.
392///
393/// This crate leverages [`FREGetFREContextFromExtensionContext`] to enable
394/// more advanced use cases, but doing so also increases overall complexity.
395///
396#[derive(Debug, Clone, Copy, PartialEq, Eq)]
397#[repr(transparent)]
398pub struct ForeignContext <'a> (ContextHandle, PhantomData<&'a()>);
399impl<'a> ForeignContext<'a> {
400
401 /// Returns a pointer to the native data. Callers must understand its memory
402 /// layout and explicitly treat it as either a borrow or a move.
403 ///
404 /// Only fails if the context is invalid.
405 ///
406 pub fn get_native_data (self) -> Result<Option<NonNullFREData>, FfiError> {
407 let mut data = FREData::default();
408 let r = unsafe {FREGetContextNativeData(self.as_ptr(), &mut data)};
409 if let Ok(e) = FfiError::try_from(r) {Err(e)} else {Ok(NonNullFREData::new(data))}
410 }
411
412 /// Sets the native data pointer for the context.
413 ///
414 /// Only fails if the context is invalid.
415 ///
416 /// # Safety
417 ///
418 /// Callers must ensure that no valid native data is currently set,
419 /// or that any previously associated native data has become invalid
420 /// and its memory has been properly released.
421 ///
422 /// If `data` is a non-null pointer, it must have well-defined ownership:
423 /// it must be treated explicitly as either a borrow or a move.
424 ///
425 /// If treated as a move, callers must ensure that the memory is properly
426 /// released before [`FREContextFinalizer`] completes.
427 ///
428 #[allow(unsafe_op_in_unsafe_fn)]
429 pub unsafe fn set_native_data (self, data: Option<NonNullFREData>) -> Result<(), FfiError> {
430 let data: *mut c_void = data.map(|ptr|ptr.as_ptr())
431 .unwrap_or_default();
432 let r = FRESetContextNativeData(self.as_ptr(), data);
433 if let Ok(e) = FfiError::try_from(r) {Err(e)} else {Ok(())}
434 }
435
436 /// Returns the ActionScript-side Context Data associated with the context.
437 ///
438 /// `ExtensionContext.actionScriptData`
439 ///
440 /// Only fails if the context is invalid.
441 ///
442 pub fn get_actionscript_data (self) -> Result<as3::Object<'a>, FfiError> {
443 let mut object = FREObject::default();
444 let r = unsafe {FREGetContextActionScriptData(self.as_ptr(), &mut object)};
445 if let Ok(e) = FfiError::try_from(r) {Err(e)} else {Ok(unsafe {transmute(object)})}
446 }
447
448 /// Sets the ActionScript-side Context Data associated with the context.
449 ///
450 /// `ExtensionContext.actionScriptData`
451 ///
452 /// Only fails if the context is invalid.
453 ///
454 pub fn set_actionscript_data (self, object: as3::Object<'_>) -> Result<(), FfiError> {
455 let r = unsafe {FRESetContextActionScriptData(self.as_ptr(), object.as_ptr())};
456 if let Ok(e) = FfiError::try_from(r) {Err(e)} else {Ok(())}
457 }
458
459}
460impl Sealed for ForeignContext<'_> {}
461impl Context for ForeignContext<'_> {
462 fn as_handle (&self) -> ContextHandle {self.0}
463 fn is_valid(&self) -> bool {self.get_actionscript_data().is_ok()}
464}
465
466
467#[allow(private_bounds)]
468pub trait Context: Sealed {
469 fn as_handle (&self) -> ContextHandle;
470 fn as_ptr (&self) -> FREContext {self.as_handle().as_ptr()}
471
472 /// Returns whether the context is valid.
473 ///
474 /// The context remains valid until [`FREContextFinalizer`] has completed.
475 /// Invalidity only occurs when the associated `ExtensionContext` object
476 /// is destructed or its `dispose` method is explicitly called.
477 ///
478 fn is_valid(&self) -> bool;
479
480 /// Returns an [`EventDispatcher`] used to perform asynchronous callbacks
481 /// via the ActionScript event system.
482 ///
483 fn event_dispatcher(&self) -> EventDispatcher {EventDispatcher(self.as_handle())}
484
485 /// Sends a message to the debugger output.
486 ///
487 /// Delivery is not guaranteed; the `message` may not be presented.
488 ///
489 /// `message` can be an [`as3::Object`] or a slice of it.
490 ///
491 fn trace (&self, message: impl ToUcstrLossy) {
492 let r = unsafe {FRETrace(self.as_ptr(), message.to_ucstr_lossy().as_ptr())};
493 debug_assert!(r.is_ok());
494 }
495
496 /// Return [`Err`] if `stage` is non-null but not a `Stage` object
497 ///
498 /// This is a minimal safety wrapper around the underlying FFI. Its current
499 /// placement, shape, and usage are not ideal, and it is expected to be
500 /// refactored if the ANE C API allows more precise determination of an
501 /// object's concrete type.
502 fn get_render_mode (&self, stage: Option<as3::Object<'_>>) -> Result<crate::misc::RenderMode, FfiError> {
503 let stage = stage.unwrap_or_default();
504 let mut rm = u8::default();
505 let r = unsafe {FREGetRenderMode(self.as_ptr(), stage.as_ptr(), &mut rm)};
506 if let Ok(e) = FfiError::try_from(r) {
507 Err(e)
508 } else {
509 let rm: FRERenderMode = FRERenderMode(rm as i32);
510 Ok(crate::misc::RenderMode::from(rm))
511 }
512 }
513
514 /// `air.media.MediaBuffer` (AIR SDK 51)
515 ///
516 /// `AIR-5963: Add ANE capabilities to render a Sprite using a MediaBuffer - initial support via BitmapData`
517 ///
518 /// This is a minimal safety wrapper around the underlying FFI. Its current
519 /// placement, shape, and usage are not ideal, and it is expected to be
520 /// refactored if the ANE C API allows more precise determination of an
521 /// object's concrete type.
522 ///
523 fn set_render_source (&self, media_buffer: as3::Object<'_>, sprite: as3::Object<'_>) -> Result<(), FfiError> {
524 let r = unsafe {FRESetRenderSource(self.as_ptr(), media_buffer.as_ptr(), sprite.as_ptr())};
525 if let Ok(e) = FfiError::try_from(r) {Err(e)} else {Ok(())}
526 }
527
528
529 /// This is a minimal safety wrapper around the underlying FFI. Its current
530 /// placement, shape, and usage are not ideal, and it is expected to be
531 /// refactored if the ANE C API allows more precise determination of an
532 /// object's concrete type.
533 ///
534 fn with_media_buffer <F, R> (&self, media_buffer: as3::Object<'_>, f: F) -> Result<R, FfiError>
535 where F: FnOnce (MediaBufferDataAdapter) -> R {
536 let mut bytes = FREBytes::default();
537 let mut width = u32::default();
538 let mut height = u32::default();
539 let mut stride = u32::default();
540 let mut format = u32::default();
541 let result = unsafe {FREMediaBufferLock(self.as_ptr(), media_buffer.as_ptr(), &mut bytes, &mut width, &mut height, &mut stride, &mut format)};
542 if let Ok(e) = FfiError::try_from(result) {return Err(e);}
543 let adapter = unsafe {MediaBufferDataAdapter::new(bytes, width, height, stride, format)};
544 let r = f(adapter);
545 let result = unsafe {FREMediaBufferUnlock(self.as_ptr(), media_buffer.as_ptr(), u32::default())};
546 debug_assert!(result.is_ok());
547 Ok(r)
548 }
549
550}
551
552
553/// The extension-side concrete representation of a [`Context`].
554///
555/// This can be considered the actual context instance, while [`Context`]
556/// serves as an abstract handle or outer wrapper around it.
557///
558/// Can only be constructed through [`CurrentContext::with_context_initializer`].
559///
560#[derive(Debug)]
561pub struct ContextRegistry {
562 ctx_type: Option<UCStr>,
563 ctx_data: Option<Box<dyn Any>>,
564 ext_data: Option<ExtensionData>,// &'extension mut
565 methods: Option<MethodSet>,
566}
567impl ContextRegistry {
568
569 /// Returns the context type associated with the context.
570 ///
571 /// This corresponds to the `contextType` argument passed to
572 /// `ExtensionContext.createExtensionContext`.
573 ///
574 /// Returns [`None`] if that argument was `null`.
575 ///
576 pub fn context_type(&self) -> Option<UCStr> {(self.ctx_type).clone()}
577
578
579 /// Returns an immutable reference to the Context Data associated with the context.
580 ///
581 /// Context Data is user-defined data bound to the context, sharing the same
582 /// lifetime as the context itself.
583 ///
584 /// It can only be set via the first return value of [`ContextInitializer`].
585 ///
586 pub fn context_data(&self) -> Option<&dyn Any> {self.ctx_data.as_ref().map(|d|d.as_ref())}
587
588 /// Returns a mutable reference to the Context Data associated with the context.
589 ///
590 /// Context Data is user-defined data bound to the context, sharing the same
591 /// lifetime as the context itself.
592 ///
593 /// It can only be set via the first return value of [`ContextInitializer`].
594 ///
595 pub fn context_data_mut(&mut self) -> Option<&mut dyn Any> {self.ctx_data.as_mut().map(|d|d.as_mut())}
596
597 /// Provides access to the Extension Data.
598 ///
599 /// The Extension Data is set from the return value of [`Initializer`].
600 /// It can be accessed across threads and is synchronized via a [`Mutex`],
601 /// providing exclusive access on each call.
602 ///
603 /// Calling this method within nested [`Function`] invocations can lead
604 /// to deadlocks. It is recommended to avoid accessing it within a
605 /// [`Function`] call stack, and instead perform synchronization between
606 /// Context Data and Extension Data in [`ContextInitializer`] and [`ContextFinalizer`].
607 ///
608 pub fn with_extension_data <F, R> (&self, f: F) -> Option<R>
609 where F: FnOnce (&mut dyn Any) -> R {
610 let ext_data = self.ext_data.as_ref()?;
611 let mut ext_data = ext_data.lock().expect("Mutex poisoned.");
612 let r = f(ext_data.as_mut());
613 Some(r)
614 }
615
616 fn new (ext_data: FREData, ctx_type: Option<UCStr>) -> RefCell<Self> {
617 let ext_data = NonNullFREData::new(ext_data)
618 .map(|raw| {
619 Arc::clone(unsafe {
620 <ExtensionData as Data>::ref_from(raw)
621 }.unwrap())
622 });
623 RefCell::new(Self {
624 ctx_type,
625 ctx_data: None,
626 ext_data,
627 methods: None,
628 })
629 }
630}
631impl Data for RefCell<ContextRegistry> {}
632