Skip to main content

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(|ptr| {
619                Arc::clone(unsafe {
620                    <ExtensionData as Data>::ref_from(ptr)
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