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> (
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 F: FnOnce (&CurrentContext<'a>, Option<&mut dyn Any>, &[as3::Object<'a>]) -> as3::Object<'a>
235    {
236        assert!(!argv.is_null() || argc==0);
237        Self::with(ctx, |ctx| {
238            let func_data = NonNullFREData::new(func_data)
239                .map(|raw| crate::data::mut_from(raw));
240            let args = std::slice::from_raw_parts(argv as *const as3::Object, argc as usize);
241            f(ctx, func_data, args).as_ptr()
242        })
243    }
244
245}
246impl<'a> CurrentContext<'a> {
247    fn new(ctx: &'a FREContext) -> Self {
248        Self(ContextHandle::new(*ctx).expect("INVARIANT: `CurrentContext` is always valid."), PhantomData)
249    }
250    fn as_cooperative_ctx(&self) -> CooperativeContext<'a> {unsafe {transmute(self.0)}}
251    fn ctx_reg(&self) -> &ContextRegistry {
252        let ptr = self.as_cooperative_ctx()
253            .with(|ctx_reg|ctx_reg as *const ContextRegistry)
254            .expect("INVARIANT: `CurrentContext` is unique.");
255        unsafe {&*(ptr)}
256    }
257    fn ctx_reg_mut(&mut self) -> &mut ContextRegistry {
258        let ptr = self.as_cooperative_ctx()
259            .with_mut(|ctx_reg|ctx_reg as *mut ContextRegistry)
260            .expect("INVARIANT: `CurrentContext` is unique.");
261        unsafe {&mut *(ptr)}
262    }
263}
264impl Sealed for CurrentContext<'_> {}
265impl Context for CurrentContext<'_> {
266    fn as_handle (&self) -> ContextHandle {self.0}
267    fn is_valid(&self) -> bool {
268        debug_assert!(self.as_cooperative_ctx().is_valid());
269        true
270    }
271}
272
273
274/// A handle to a context that may become invalid under specific conditions.
275/// 
276/// Can only be obtained through [`CurrentContext::cooperative_context_from_object`].
277///
278/// Invalidity only occurs after the associated `ExtensionContext` object
279/// has been disposed. Therefore, callers should be prepared for operations
280/// on the context to fail at appropriate points.
281///
282/// This crate leverages [`FREGetFREContextFromExtensionContext`] to enable
283/// more advanced use cases, but doing so also increases overall complexity.
284/// 
285/// # Invariant
286/// 
287/// The context must have been constructed by the current extension via
288/// [`ContextInitializer`]. Violating this invariant results in undefined behavior.
289///
290#[derive(Debug, Clone, Copy, PartialEq, Eq)]
291#[repr(transparent)]
292pub struct CooperativeContext <'a> (ContextHandle, PhantomData<&'a()>);
293impl<'a> CooperativeContext<'a> {
294
295    /// Provides immutable access to the [`ContextRegistry`] within a closure.
296    /// 
297    /// [`Err`]=> [`ContextError::InvalidContext`], [`ContextError::NullRegistry`], [`ContextError::InvalidRegistry`], [`ContextError::FfiCallFailed`], [`ContextError::BorrowRegistryConflict`];
298    /// 
299    pub fn with <F, R> (self, f: F) -> Result<R, ContextError>
300    where F: FnOnce (&ContextRegistry) -> R {
301        if !self.is_valid() {return Err(ContextError::InvalidContext)}
302        let handle = self.as_foreign_ctx().get_native_data()?
303            .ok_or(ContextError::NullRegistry)?;
304        let cell = unsafe {RefCell::<ContextRegistry>::ref_from(handle)}
305            .map_err(|_| ContextError::InvalidRegistry)?;
306        let ctx_reg = cell.try_borrow()
307            .map_err(|_| ContextError::BorrowRegistryConflict)?;
308        let r = f(&ctx_reg);
309        Ok(r)
310    }
311
312    /// Provides mutable access to the [`ContextRegistry`] within a closure.
313    /// 
314    /// [`Err`]=> [`Self::with`];
315    /// 
316    pub fn with_mut <F, R> (self, f: F) -> Result<R, ContextError>
317    where F: FnOnce (&mut ContextRegistry) -> R {
318        if !self.is_valid() {return Err(ContextError::InvalidContext)}
319        let handle = self.as_foreign_ctx().get_native_data()?
320            .ok_or(ContextError::NullRegistry)?;
321        let cell = unsafe {RefCell::<ContextRegistry>::ref_from(handle)}
322            .map_err(|_| ContextError::InvalidRegistry)?;
323        let mut ctx_reg = cell.try_borrow_mut()
324            .map_err(|_| ContextError::BorrowRegistryConflict)?;
325        let r = f(&mut ctx_reg);
326        Ok(r)
327    }
328
329    /// Calls a registered function by name through an internal call within the current extension.
330    /// 
331    /// Nested calls increase complexity. Callers must consider borrowing rules and context validity.
332    /// 
333    /// [`Err`]=> [`Self::with`], [`ContextError::MethodNotFound`];
334    /// 
335    pub fn call_method (self, name: &str, args: Option<&[as3::Object<'a>]> ) -> Result<as3::Object<'a>, ContextError> {
336        let (func, data) = self.with(|ctx_reg| {
337            ctx_reg.methods.as_ref()
338            .expect("INVARIANT: `CooperativeContext` is not current context and has been initialized with `MethodSet`.")
339            .get(name)
340            .ok_or(ContextError::MethodNotFound)
341        })??;
342        let args = args.unwrap_or_default();
343        let argc = args.len() as u32;
344        let argv = args.as_ptr() as *const FREObject;
345        let r = unsafe {func(self.as_ptr(), data, argc, argv)};
346        Ok(unsafe {transmute(r)})
347    }
348    
349    /// Returns the ActionScript-side Context Data associated with the context.
350    /// 
351    /// `ExtensionContext.actionScriptData`
352    /// 
353    /// Only fails if the context is invalid.
354    /// 
355    pub fn get_actionscript_data (self) -> Result<as3::Object<'a>, FfiError>
356    {self.as_foreign_ctx().get_actionscript_data()}
357    
358    
359    /// Sets the ActionScript-side Context Data associated with the context.
360    /// 
361    /// `ExtensionContext.actionScriptData`
362    /// 
363    /// Only fails if the context is invalid.
364    /// 
365    pub fn set_actionscript_data (self, object: as3::Object<'_>) -> Result<(), FfiError>
366    {self.as_foreign_ctx().set_actionscript_data(object)}
367
368
369    fn as_foreign_ctx(self) -> ForeignContext<'a> {unsafe {transmute(self)}}
370}
371impl Sealed for CooperativeContext<'_> {}
372impl Context for CooperativeContext<'_> {
373    fn as_handle (&self) -> ContextHandle {self.0}
374    fn is_valid(&self) -> bool {self.get_actionscript_data().is_ok()}
375}
376
377
378/// A handle to a context that may become invalid under specific conditions.
379/// 
380/// Can only be obtained through [`CurrentContext::foreign_context_from_object`].
381/// 
382/// Assumes the context was not constructed by the current extension.
383/// Accessing its associated native data is therefore unsafe.
384///
385/// Invalidity only occurs after the associated `ExtensionContext` object
386/// has been disposed. Therefore, callers should be prepared for operations
387/// on the context to fail at appropriate points.
388///
389/// This crate leverages [`FREGetFREContextFromExtensionContext`] to enable
390/// more advanced use cases, but doing so also increases overall complexity.
391///
392#[derive(Debug, Clone, Copy, PartialEq, Eq)]
393#[repr(transparent)]
394pub struct ForeignContext <'a> (ContextHandle, PhantomData<&'a()>);
395impl<'a> ForeignContext<'a> {
396    
397    /// Returns a pointer to the native data. Callers must understand its memory
398    /// layout and explicitly treat it as either a borrow or a move.
399    /// 
400    /// Only fails if the context is invalid.
401    /// 
402    pub fn get_native_data (self) -> Result<Option<NonNullFREData>, FfiError> {
403        let mut data = FREData::default();
404        let r = unsafe {FREGetContextNativeData(self.as_ptr(), &mut data)};
405        if let Ok(e) = FfiError::try_from(r) {Err(e)} else {Ok(NonNullFREData::new(data))}
406    }
407
408    /// Sets the native data pointer for the context.
409    ///
410    /// Only fails if the context is invalid.
411    /// 
412    /// # Safety
413    ///
414    /// Callers must ensure that no valid native data is currently set,
415    /// or that any previously associated native data has become invalid
416    /// and its memory has been properly released.
417    ///
418    /// If `data` is a non-null pointer, it must have well-defined ownership:
419    /// it must be treated explicitly as either a borrow or a move.
420    ///
421    /// If treated as a move, callers must ensure that the memory is properly
422    /// released before [`FREContextFinalizer`] completes.
423    /// 
424    #[allow(unsafe_op_in_unsafe_fn)]
425    pub unsafe fn set_native_data (self, data: Option<NonNullFREData>) -> Result<(), FfiError> {
426        let data: *mut c_void = data.map(|ptr|ptr.as_ptr())
427            .unwrap_or_default();
428        let r = FRESetContextNativeData(self.as_ptr(), data);
429        if let Ok(e) = FfiError::try_from(r) {Err(e)} else {Ok(())}
430    }
431
432    /// Returns the ActionScript-side Context Data associated with the context.
433    /// 
434    /// `ExtensionContext.actionScriptData`
435    /// 
436    /// Only fails if the context is invalid.
437    /// 
438    pub fn get_actionscript_data (self) -> Result<as3::Object<'a>, FfiError> {
439        let mut object = FREObject::default();
440        let r = unsafe {FREGetContextActionScriptData(self.as_ptr(), &mut object)};
441        if let Ok(e) = FfiError::try_from(r) {Err(e)} else {Ok(unsafe {transmute(object)})}
442    }
443    
444    /// Sets the ActionScript-side Context Data associated with the context.
445    /// 
446    /// `ExtensionContext.actionScriptData`
447    /// 
448    /// Only fails if the context is invalid.
449    /// 
450    pub fn set_actionscript_data (self, object: as3::Object<'_>) -> Result<(), FfiError> {
451        let r = unsafe {FRESetContextActionScriptData(self.as_ptr(), object.as_ptr())};
452        if let Ok(e) = FfiError::try_from(r) {Err(e)} else {Ok(())}
453    }
454
455}
456impl Sealed for ForeignContext<'_> {}
457impl Context for ForeignContext<'_> {
458    fn as_handle (&self) -> ContextHandle {self.0}
459    fn is_valid(&self) -> bool {self.get_actionscript_data().is_ok()}
460}
461
462
463#[allow(private_bounds)]
464pub trait Context: Sealed {
465    fn as_handle (&self) -> ContextHandle;
466    fn as_ptr (&self) -> FREContext {self.as_handle().as_ptr()}
467    
468    /// Returns whether the context is valid.
469    ///
470    /// The context remains valid until [`FREContextFinalizer`] has completed.
471    /// Invalidity only occurs when the associated `ExtensionContext` object
472    /// is destructed or its `dispose` method is explicitly called.
473    /// 
474    fn is_valid(&self) -> bool;
475
476    /// Returns an [`EventDispatcher`] used to perform asynchronous callbacks
477    /// via the ActionScript event system.
478    /// 
479    fn event_dispatcher(&self) -> EventDispatcher {EventDispatcher(self.as_handle())}
480
481    /// Sends a message to the debugger output.
482    ///
483    /// Delivery is not guaranteed; the `message` may not be presented.
484    /// 
485    /// `message` can be an [`as3::Object`] or a slice of it.
486    /// 
487    fn trace (&self, message: impl ToUcstrLossy) {
488        let r = unsafe {FRETrace(self.as_ptr(), message.to_ucstr_lossy().as_ptr())};
489        debug_assert!(r.is_ok());
490    }
491
492    /// Return [`Err`] if `stage` is non-null but not a `Stage` object
493    /// 
494    /// This is a minimal safety wrapper around the underlying FFI. Its current
495    /// placement, shape, and usage are not ideal, and it is expected to be
496    /// refactored if the ANE C API allows more precise determination of an
497    /// object's concrete type.
498    fn get_render_mode (&self, stage: Option<as3::Object<'_>>) -> Result<crate::misc::RenderMode, FfiError> {
499        let stage = stage.unwrap_or_default();
500        let mut rm = u8::default();
501        let r = unsafe {FREGetRenderMode(self.as_ptr(), stage.as_ptr(), &mut rm)};
502        if let Ok(e) = FfiError::try_from(r) {
503            Err(e)
504        } else {
505            let rm: FRERenderMode = FRERenderMode(rm as i32);
506            Ok(crate::misc::RenderMode::from(rm))
507        }
508    }
509    
510    /// `air.media.MediaBuffer` (AIR SDK 51)
511    /// 
512    /// `AIR-5963: Add ANE capabilities to render a Sprite using a MediaBuffer - initial support via BitmapData`
513    /// 
514    /// This is a minimal safety wrapper around the underlying FFI. Its current
515    /// placement, shape, and usage are not ideal, and it is expected to be
516    /// refactored if the ANE C API allows more precise determination of an
517    /// object's concrete type.
518    /// 
519    fn set_render_source (&self, media_buffer: as3::Object<'_>, sprite: as3::Object<'_>) -> Result<(), FfiError> {
520        let r = unsafe {FRESetRenderSource(self.as_ptr(), media_buffer.as_ptr(), sprite.as_ptr())};
521        if let Ok(e) = FfiError::try_from(r) {Err(e)} else {Ok(())}
522    }
523
524    
525    /// This is a minimal safety wrapper around the underlying FFI. Its current
526    /// placement, shape, and usage are not ideal, and it is expected to be
527    /// refactored if the ANE C API allows more precise determination of an
528    /// object's concrete type.
529    /// 
530    fn with_media_buffer <F, R> (&self, media_buffer: as3::Object<'_>, f: F) -> Result<R, FfiError> 
531    where F: FnOnce (MediaBufferDataAdapter) -> R {
532        let mut bytes = FREBytes::default();
533        let mut width = u32::default();
534        let mut height = u32::default();
535        let mut stride = u32::default();
536        let mut format = u32::default();
537        let result = unsafe {FREMediaBufferLock(self.as_ptr(), media_buffer.as_ptr(), &mut bytes, &mut width, &mut height, &mut stride, &mut format)};
538        if let Ok(e) = FfiError::try_from(result) {return Err(e);}
539        let adapter = unsafe {MediaBufferDataAdapter::new(bytes, width, height, stride, format)};
540        let r = f(adapter);
541        let result = unsafe {FREMediaBufferUnlock(self.as_ptr(), media_buffer.as_ptr(), u32::default())};
542        debug_assert!(result.is_ok());
543        Ok(r)
544    }
545
546}
547
548
549/// The extension-side concrete representation of a [`Context`].
550///
551/// This can be considered the actual context instance, while [`Context`]
552/// serves as an abstract handle or outer wrapper around it.
553/// 
554/// Can only be constructed through [`CurrentContext::with_context_initializer`].
555/// 
556#[derive(Debug)]
557pub struct ContextRegistry {
558    ctx_type: Option<UCStr>,
559    ctx_data: Option<Box<dyn Any>>,
560    ext_data: Option<ExtensionData>,// &'extension mut
561    methods: Option<MethodSet>,
562}
563impl ContextRegistry {
564
565    /// Returns the context type associated with the context.
566    ///
567    /// This corresponds to the `contextType` argument passed to
568    /// `ExtensionContext.createExtensionContext`.
569    ///
570    /// Returns [`None`] if that argument was `null`.
571    /// 
572    pub fn context_type(&self) -> Option<UCStr> {(self.ctx_type).clone()}
573
574    
575    /// Returns an immutable reference to the Context Data associated with the context.
576    ///
577    /// Context Data is user-defined data bound to the context, sharing the same
578    /// lifetime as the context itself.
579    ///
580    /// It can only be set via the first return value of [`ContextInitializer`].
581    /// 
582    pub fn context_data(&self) -> Option<&dyn Any> {self.ctx_data.as_ref().map(|d|d.as_ref())}
583
584    /// Returns a mutable reference to the Context Data associated with the context.
585    ///
586    /// Context Data is user-defined data bound to the context, sharing the same
587    /// lifetime as the context itself.
588    ///
589    /// It can only be set via the first return value of [`ContextInitializer`].
590    /// 
591    pub fn context_data_mut(&mut self) -> Option<&mut dyn Any> {self.ctx_data.as_mut().map(|d|d.as_mut())}
592
593    /// Provides access to the Extension Data.
594    ///
595    /// The Extension Data is set from the return value of [`Initializer`].
596    /// It can be accessed across threads and is synchronized via a [`Mutex`],
597    /// providing exclusive access on each call.
598    ///
599    /// Calling this method within nested [`Function`] invocations can lead
600    /// to deadlocks. It is recommended to avoid accessing it within a
601    /// [`Function`] call stack, and instead perform synchronization between
602    /// Context Data and Extension Data in [`ContextInitializer`] and [`ContextFinalizer`].
603    /// 
604    pub fn with_extension_data <F, R> (&self, f: F) -> Option<R>
605    where F: FnOnce (&mut dyn Any) -> R {
606        let ext_data = self.ext_data.as_ref()?;
607        let mut ext_data = ext_data.lock().expect("Mutex poisoned.");
608        let r = f(ext_data.as_mut());
609        Some(r)
610    }
611    
612    fn new (ext_data: FREData, ctx_type: Option<UCStr>) -> RefCell<Self> {
613        let ext_data = NonNullFREData::new(ext_data)
614            .map(|ptr| {
615                Arc::clone(unsafe {
616                    <ExtensionData as Data>::ref_from(ptr)
617                }.unwrap())
618            });
619        RefCell::new(Self {
620            ctx_type,
621            ctx_data: None,
622            ext_data,
623            methods: None,
624        })
625    }
626}
627impl Data for RefCell<ContextRegistry> {}
628