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