1use super::*;
2
3
4pub unsafe trait AsObject<'a>: Sized + Copy + Eq + Display + Into<FREObject> + Into<Object<'a>> {
23
24 const TYPE: Type;
29
30 fn as_object (self) -> Object<'a> {
31 debug_assert_eq!(size_of_val(&self), size_of::<FREObject>());
32 unsafe {transmute_unchecked(self)}
33 }
34 fn as_ptr (self) -> FREObject {
35 unsafe {transmute(self.as_object())}
36 }
37 fn is_null(self) -> bool {self.as_ptr().is_null()}
38
39 fn get_type(self) -> Type {
45 let mut ty = FREObjectType(i32::default());
46 let r = unsafe {FREGetObjectType(self.as_ptr(), &mut ty)};
47 assert!(r.is_ok());
48 ty.into()
49 }
50
51 fn get_property (self, name: UCStr) -> Result<Object<'a>, ExternalError<'a>> {
52 let mut object = std::ptr::null_mut();
53 let mut thrown = std::ptr::null_mut();
54 let r = unsafe {FREGetObjectProperty(self.as_ptr(), name.as_ptr(), &mut object, &mut thrown)};
55 if let Ok(e) = ExternalError::try_from(r, Some(unsafe {transmute(thrown)})) {
56 Err(e)
57 }else{
58 Ok(unsafe {transmute(object)})
59 }
60 }
61
62 fn set_property <O: AsObject<'a>> (self, name: UCStr, value: O) -> Result<(), ExternalError<'a>> {
63 let mut thrown = std::ptr::null_mut();
64 let r = unsafe {FRESetObjectProperty(self.as_ptr(), name.as_ptr(), value.as_ptr(), &mut thrown)};
65 if let Ok(e) = ExternalError::try_from(r, Some(unsafe {transmute(thrown)})) {
66 Err(e)
67 }else{
68 Ok(())
69 }
70 }
71
72 fn call_method (self, name: UCStr, args: Option<&[Object]>) -> Result<Object<'a>, ExternalError<'a>> {
73 let args = args.unwrap_or_default();
74 debug_assert!(args.len() <= u32::MAX as usize);
75 let mut obj = std::ptr::null_mut();
76 let mut thrown = std::ptr::null_mut();
77 let r = unsafe {FRECallObjectMethod(self.as_ptr(), name.as_ptr(), args.len() as u32, transmute(args.as_ptr()), &mut obj, &mut thrown)};
78 if let Ok(e) = ExternalError::try_from(r, Some(unsafe {transmute(thrown)})) {
79 Err(e)
80 }else{
81 Ok(unsafe {transmute(obj)})
82 }
83 }
84
85 #[allow(non_snake_case)]
87 fn toString (self) -> Result<as3::String<'a>, ExternalError<'a>> {
88 const TO_STRING: UCStr = unsafe {UCStr::from_literal_unchecked(c"toString")};
89 self.call_method(TO_STRING, None).map(|r|{unsafe {transmute(r)}})
90 }
91}
92
93
94pub unsafe trait TryAs<'a, T>: AsObject<'a> + TryInto<T>
101where T: AsObject<'a> {
102 fn try_as (self) -> Result<T, Type> {
103 let ty = self.get_type();
104 if ty == T::TYPE {
105 debug_assert_eq!(size_of_val(&self), size_of::<T>());
106 Ok(unsafe {transmute_unchecked(self)})
107 }else{Err(ty)}
108 }
109}
110unsafe impl<'a, O> TryAs<'a, Object<'a>> for O
111where O: AsObject<'a> {
112 fn try_as (self) -> Result<Object<'a>, Type> {Ok(self.as_object())}
113}
114
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
127#[repr(transparent)]
128pub struct Object <'a> (FREObject, PhantomData<&'a()>);
129impl<'a> Object<'a> {
130 pub fn new (_: &CurrentContext<'a>, class: UCStr, args: Option<&[Object<'a>]>) -> Result<Object<'a>, ExternalError<'a>> {
131 let args = args.unwrap_or_default();
132 debug_assert!(args.len() <= u32::MAX as usize);
133 let mut object = std::ptr::null_mut();
134 let mut thrown = std::ptr::null_mut();
135 let r = unsafe {FRENewObject(class.as_ptr(), args.len() as u32, transmute(args.as_ptr()), &mut object, &mut thrown)};
136 if let Ok(e) = ExternalError::try_from(r, Some(unsafe {transmute(thrown)})) {
137 Err(e)
138 }else{
139 assert!(!object.is_null());
140 Ok(unsafe {transmute(object)})
141 }
142 }
143
144 pub fn with_native_window <F, R> (self, f: F) -> Result<R, FfiError>
154 where F: FnOnce (FRENativeWindow) -> R + Sync
155 {
156 let mut handle = std::ptr::null_mut();
157 let result = unsafe {FREAcquireNativeWindowHandle(self.as_ptr(), &mut handle)};
158 if let Ok(e) = FfiError::try_from(result) {return Err(e)};
159 let r = f(handle);
160 let result = unsafe {FREReleaseNativeWindowHandle(self.as_ptr())};
161 assert!(result.is_ok());
162 Ok(r)
163 }
164
165 pub fn with_native_window_3d <F, R> (self, f: F) -> Result<R, ExternalError<'a>>
173 where F: FnOnce (FRENativeWindow, &[Option<Context3D<'a>>]) -> R + Sync
174 {
175 const NAME_STAGE: UCStr = unsafe {UCStr::from_literal_unchecked(c"stage")};
176 const NAME_STAGE_3DS: UCStr = unsafe {UCStr::from_literal_unchecked(c"stage3Ds")};
177 const NAME_CONTEXT_3D: UCStr = unsafe {UCStr::from_literal_unchecked(c"context3D")};
178 let stage3ds: Vector = self.get_property(NAME_STAGE)?
179 .get_property(NAME_STAGE_3DS)?
180 .try_as()
181 .map_err(|_|ExternalError::C(FfiError::TypeMismatch))?;
182 let ctx3ds: Box<[Option<Context3D>]> = stage3ds.iter()
183 .map(|stage3d|{
184 stage3d.get_property(NAME_CONTEXT_3D)
185 .ok()
186 })
187 .map(|i|{
188 if let Some(ctx3d) = i {
189 if ctx3d.is_null() {None} else {Some(unsafe {transmute(ctx3d)})}
190 } else {None}
191 })
192 .collect();
193 let mut handle = std::ptr::null_mut();
194 let result = unsafe {FREAcquireNativeWindowHandle(self.as_ptr(), &mut handle)};
195 if let Ok(e) = FfiError::try_from(result) {return Err(e.into())};
196 let r = f(handle, ctx3ds.as_ref());
197 let result = unsafe {FREReleaseNativeWindowHandle(self.as_ptr())};
198 debug_assert!(result.is_ok());
199 Ok(r)
200 }
201
202}
203impl TryFrom<Object<'_>> for i32 {
204 type Error = FfiError;
205 fn try_from(value: Object) -> Result<Self, Self::Error> {
206 let mut val = i32::default();
207 let r = unsafe {FREGetObjectAsInt32(value.0, &mut val)};
208 if let Ok(e) = r.try_into() {return Err(e);}
209 Ok(val)
210 }
211}
212impl TryFrom<Object<'_>> for u32 {
213 type Error = FfiError;
214 fn try_from(value: Object) -> Result<Self, Self::Error> {
215 let mut val = u32::default();
216 let r = unsafe {FREGetObjectAsUint32(value.0, &mut val)};
217 if let Ok(e) = r.try_into() {return Err(e);}
218 Ok(val)
219 }
220}
221impl TryFrom<Object<'_>> for f64 {
222 type Error = FfiError;
223 fn try_from(value: Object) -> Result<Self, Self::Error> {
224 let mut val = f64::default();
225 let r = unsafe {FREGetObjectAsDouble(value.0, &mut val)};
226 if let Ok(e) = r.try_into() {return Err(e);}
227 Ok(val)
228 }
229}
230impl TryFrom<Object<'_>> for bool {
231 type Error = FfiError;
232 fn try_from(value: Object) -> Result<Self, Self::Error> {
233 let mut val = u32::default();
234 let r = unsafe {FREGetObjectAsBool(value.0, &mut val)};
235 if let Ok(e) = r.try_into() {return Err(e);}
236 Ok(val != 0)
237 }
238}
239impl<'a> TryFrom<Object<'a>> for &'a str {
240 type Error = FfiError;
241 fn try_from(value: Object) -> Result<Self, Self::Error> {
242 let mut len = u32::default();
243 let mut ptr = std::ptr::null();
244 let r = unsafe {FREGetObjectAsUTF8(value.0, &mut len, &mut ptr)};
245 if let Ok(e) = r.try_into() {return Err(e);}
246 let bytes = unsafe {std::slice::from_raw_parts(ptr, len as usize)};
247 let s = unsafe {str::from_utf8_unchecked(bytes)};
248 Ok(s)
249 }
250}
251impl Display for Object<'_> {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 if self.is_null() {return write!(f, "null");}
254 match self.toString() {
255 Ok(s) => {Display::fmt(s.value(), f)},
256 Err(e) => {
257 match e {
258 ExternalError::C(e) => Display::fmt(&e, f),
259 ExternalError::ActionScript(e) => {
260 if let Ok(s) = e.thrown().toString().map(|s|{s.value()}) {
261 write!(f, "{e} {s}")
262 } else {Display::fmt(&e, f)}
263 },
264 }
265 },
266 }
267 }
268}
269impl Default for Object<'_> {
270 fn default() -> Self {as3::null}
271}
272unsafe impl<'a> AsObject<'a> for Object<'a> {const TYPE: Type = Type::Object;}
273impl From<()> for Object<'_> {fn from(_: ()) -> Self {as3::null}}
274impl<'a, O: AsObject<'a>> From<Option<O>> for Object<'a> {
275 fn from(value: Option<O>) -> Self {
276 if let Some(obj) = value {
277 obj.as_object()
278 } else {as3::null}
279 }
280}
281impl From<Object<'_>> for FREObject {fn from(value: Object) -> Self {value.as_ptr()}}