rive_rs/core/
object.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::any::{self, Any, TypeId};
6use std::marker::PhantomData;
7use std::ops::Deref;
8use std::rc::{Rc, Weak};
9use std::{fmt, hash};
10
11use crate::core::{Cast, Core, CoreContext, OnAdded};
12use crate::importers::ImportStack;
13use crate::status_code::StatusCode;
14
15fn any_type_name<T: Any>() -> &'static str {
16    any::type_name::<T>().rsplit("::").next().unwrap()
17}
18
19type OnAddedListener = fn(&Rc<dyn Core>, &dyn CoreContext) -> StatusCode;
20type Importer = fn(&Rc<dyn Core>, Object, &ImportStack) -> StatusCode;
21
22pub struct Object<T = ()> {
23    weak: Weak<dyn Core>,
24    on_added_dirty: Option<OnAddedListener>,
25    pub on_added_clean: Option<OnAddedListener>,
26    import: Option<Importer>,
27    _phantom: PhantomData<T>,
28}
29
30impl<T> Object<T> {
31    pub(crate) fn new(rc: &Rc<dyn Core>) -> Self {
32        Self {
33            weak: Rc::downgrade(rc),
34            on_added_dirty: None,
35            on_added_clean: None,
36            import: None,
37            _phantom: PhantomData,
38        }
39    }
40
41    fn upgrade_rc(&self) -> Rc<dyn Core> {
42        self.weak.upgrade().expect("File dropped while objects still in use")
43    }
44
45    pub fn as_ref(&self) -> ObjectRef<'_, T> {
46        ObjectRef {
47            core_ref: CoreRef::Rc(self.upgrade_rc()),
48            on_added_dirty: self.on_added_dirty,
49            on_added_clean: self.on_added_clean,
50            import: self.import,
51        }
52    }
53
54    pub fn ptr_eq<U>(&self, other: &Object<U>) -> bool {
55        self.weak.ptr_eq(&other.weak)
56    }
57}
58
59impl<T: Any> Object<T> {
60    pub fn try_cast<C: Core>(&self) -> Option<Object<C>> {
61        let rc = self.upgrade_rc();
62        rc.is::<C>().then(|| Object {
63            weak: Rc::downgrade(&rc),
64            on_added_dirty: None,
65            on_added_clean: None,
66            import: None,
67            _phantom: PhantomData,
68        })
69    }
70
71    pub fn cast<C: Core>(&self) -> Object<C> {
72        fn type_name<T: Any>() -> String {
73            if TypeId::of::<T>() == TypeId::of::<()>() {
74                return String::from("Object");
75            }
76
77            format!("Object<{}>", any_type_name::<T>())
78        }
79
80        self.try_cast().unwrap_or_else(|| {
81            panic!("failed cast from {} to {}", type_name::<T>(), type_name::<C>(),)
82        })
83    }
84}
85
86impl<'a, T: Core> From<Object<T>> for Object
87where
88    ObjectRef<'a, T>: OnAdded,
89{
90    fn from(object: Object<T>) -> Self {
91        fn on_added_dirty<'a, T: Core>(rc: &Rc<dyn Core>, context: &dyn CoreContext) -> StatusCode
92        where
93            ObjectRef<'a, T>: OnAdded + 'a,
94        {
95            let object_ref: ObjectRef<'_, T> = ObjectRef {
96                core_ref: CoreRef::Rc(Rc::clone(rc)),
97                on_added_dirty: None,
98                on_added_clean: None,
99                import: None,
100            };
101            object_ref.on_added_dirty(context)
102        }
103
104        fn on_added_clean<'a, T: Core>(rc: &Rc<dyn Core>, context: &dyn CoreContext) -> StatusCode
105        where
106            ObjectRef<'a, T>: OnAdded,
107        {
108            let object_ref: ObjectRef<'_, T> = ObjectRef {
109                core_ref: CoreRef::Rc(Rc::clone(rc)),
110                on_added_dirty: None,
111                on_added_clean: None,
112                import: None,
113            };
114            object_ref.on_added_clean(context)
115        }
116
117        fn import<'a, T: Core>(
118            rc: &Rc<dyn Core>,
119            object: Object,
120            import_stack: &ImportStack,
121        ) -> StatusCode
122        where
123            ObjectRef<'a, T>: OnAdded,
124        {
125            let object_ref: ObjectRef<'_, T> = ObjectRef {
126                core_ref: CoreRef::Rc(Rc::clone(rc)),
127                on_added_dirty: None,
128                on_added_clean: None,
129                import: None,
130            };
131            object_ref.import(object, import_stack)
132        }
133
134        Self {
135            weak: object.weak,
136            on_added_dirty: Some(on_added_dirty::<T>),
137            on_added_clean: Some(on_added_clean::<T>),
138            import: Some(import::<T>),
139            _phantom: PhantomData,
140        }
141    }
142}
143
144impl<T> Clone for Object<T> {
145    fn clone(&self) -> Self {
146        Self {
147            weak: self.weak.clone(),
148            on_added_dirty: self.on_added_dirty,
149            on_added_clean: self.on_added_clean,
150            import: self.import,
151            _phantom: PhantomData,
152        }
153    }
154}
155
156impl fmt::Debug for Object {
157    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158        f.debug_struct("Object").finish()
159    }
160}
161
162impl<T: Core + fmt::Debug> fmt::Debug for Object<T> {
163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164        f.debug_struct("Object").finish()
165    }
166}
167
168impl<T> hash::Hash for Object<T> {
169    fn hash<H: hash::Hasher>(&self, state: &mut H) {
170        self.weak.upgrade().map(|rc| &*rc as *const _).hash(state);
171    }
172}
173
174impl<T> Eq for Object<T> {}
175
176impl<T> PartialEq for Object<T> {
177    fn eq(&self, other: &Self) -> bool {
178        self.weak.ptr_eq(&other.weak)
179    }
180}
181
182#[derive(Debug)]
183enum CoreRef<'a, T = ()> {
184    Rc(Rc<dyn Core>),
185    Borrow(&'a T),
186}
187
188impl<'a> CoreRef<'a> {
189    pub fn try_cast<'b, C: Core>(&'b self) -> Option<CoreRef<'a, C>> {
190        match self {
191            Self::Rc(rc) => rc.is::<C>().then(|| CoreRef::Rc(Rc::clone(rc))),
192            _ => unreachable!(),
193        }
194    }
195}
196
197impl<'a, T: Core> CoreRef<'a, T> {
198    pub fn try_cast<'b, C: Core>(&'b self) -> Option<CoreRef<'a, C>> {
199        match self {
200            Self::Rc(rc) => rc.is::<C>().then(|| CoreRef::Rc(Rc::clone(rc))),
201            Self::Borrow(borrow) => <dyn Core>::try_cast::<C>(*borrow).map(CoreRef::Borrow),
202        }
203    }
204
205    pub fn type_name(&self) -> &'static str {
206        match self {
207            Self::Rc(rc) => rc.type_name(),
208            Self::Borrow(borrow) => borrow.type_name(),
209        }
210    }
211}
212
213impl Deref for CoreRef<'_> {
214    type Target = dyn Core;
215
216    fn deref(&self) -> &Self::Target {
217        if let Self::Rc(rc) = self {
218            return &**rc;
219        }
220
221        panic!("CoreRef<'_> must contain an Rc pointer");
222    }
223}
224
225impl<T: Core> Deref for CoreRef<'_, T> {
226    type Target = T;
227
228    fn deref(&self) -> &Self::Target {
229        match self {
230            Self::Rc(rc) => rc.cast(),
231            Self::Borrow(borrow) => borrow,
232        }
233    }
234}
235
236impl<T> Clone for CoreRef<'_, T> {
237    fn clone(&self) -> Self {
238        match self {
239            Self::Rc(rc) => Self::Rc(Rc::clone(rc)),
240            Self::Borrow(borrow) => Self::Borrow(borrow),
241        }
242    }
243}
244
245pub struct ObjectRef<'a, T = ()> {
246    core_ref: CoreRef<'a, T>,
247    on_added_dirty: Option<OnAddedListener>,
248    on_added_clean: Option<OnAddedListener>,
249    import: Option<Importer>,
250}
251
252impl<'a, T: Core> From<&'a T> for ObjectRef<'a, T> {
253    fn from(borrow: &'a T) -> Self {
254        Self {
255            core_ref: CoreRef::Borrow(borrow),
256            on_added_dirty: None,
257            on_added_clean: None,
258            import: None,
259        }
260    }
261}
262
263impl<T: Core> From<Rc<T>> for ObjectRef<'_, T> {
264    fn from(rc: Rc<T>) -> Self {
265        Self { core_ref: CoreRef::Rc(rc), on_added_dirty: None, on_added_clean: None, import: None }
266    }
267}
268
269impl<'a, T: Core> ObjectRef<'a, T> {
270    pub fn try_cast<'b, C: Core>(&'b self) -> Option<ObjectRef<'a, C>> {
271        self.core_ref.try_cast().map(|core_ref| ObjectRef {
272            core_ref,
273            on_added_dirty: self.on_added_dirty,
274            on_added_clean: self.on_added_clean,
275            import: self.import,
276        })
277    }
278
279    pub fn cast<'b, C: Core>(&'b self) -> ObjectRef<'a, C> {
280        fn type_name<T: Any>() -> String {
281            format!("ObjectRef<'_, {}>", any_type_name::<T>())
282        }
283
284        self.try_cast().unwrap_or_else(|| {
285            panic!("failed cast from {} to {}", type_name::<T>(), type_name::<C>(),)
286        })
287    }
288
289    pub fn type_name(&self) -> &'static str {
290        self.core_ref.type_name()
291    }
292}
293
294impl<'a> ObjectRef<'a> {
295    pub fn try_cast<'b, C: Core>(&'b self) -> Option<ObjectRef<'a, C>> {
296        self.core_ref.try_cast().map(|core_ref| ObjectRef {
297            core_ref,
298            on_added_dirty: self.on_added_dirty,
299            on_added_clean: self.on_added_clean,
300            import: self.import,
301        })
302    }
303
304    pub fn cast<'b, C: Core>(&'b self) -> ObjectRef<'a, C> {
305        self.try_cast().unwrap_or_else(|| {
306            panic!("failed cast from ObjectRef<'_> to {}", any_type_name::<C>(),)
307        })
308    }
309
310    pub fn on_added_dirty(&self, context: &dyn CoreContext) -> StatusCode {
311        if let CoreRef::Rc(rc) = &self.core_ref {
312            self.on_added_dirty.map(|f| f(rc, context)).unwrap_or(StatusCode::Ok)
313        } else {
314            panic!("on_added_dirty should not be called on ObjectRef from borrows");
315        }
316    }
317
318    pub fn on_added_clean(&self, context: &dyn CoreContext) -> StatusCode {
319        if let CoreRef::Rc(rc) = &self.core_ref {
320            self.on_added_clean.map(|f| f(rc, context)).unwrap_or(StatusCode::Ok)
321        } else {
322            panic!("on_added_clean should not be called on ObjectRef from borrows");
323        }
324    }
325
326    pub fn import(&self, object: Object, import_stack: &ImportStack) -> StatusCode {
327        if let CoreRef::Rc(rc) = &self.core_ref {
328            self.import.map(|f| f(rc, object, import_stack)).unwrap_or(StatusCode::Ok)
329        } else {
330            panic!("import should not be called on ObjectRef from borrows");
331        }
332    }
333}
334
335impl<T> ObjectRef<'_, T> {
336    pub fn as_object(&self) -> Object<T> {
337        if let CoreRef::Rc(rc) = &self.core_ref {
338            Object {
339                weak: Rc::downgrade(rc),
340                on_added_dirty: self.on_added_dirty,
341                on_added_clean: self.on_added_clean,
342                import: self.import,
343                _phantom: PhantomData,
344            }
345        } else {
346            panic!("as_object should not be called on ObjectRef from borrows")
347        }
348    }
349}
350
351impl Deref for ObjectRef<'_> {
352    type Target = dyn Core;
353
354    fn deref(&self) -> &Self::Target {
355        &*self.core_ref
356    }
357}
358
359impl<T: Core> Deref for ObjectRef<'_, T> {
360    type Target = T;
361
362    fn deref(&self) -> &Self::Target {
363        &*self.core_ref
364    }
365}
366
367impl<T> Clone for ObjectRef<'_, T> {
368    fn clone(&self) -> Self {
369        Self {
370            core_ref: self.core_ref.clone(),
371            on_added_dirty: self.on_added_dirty,
372            on_added_clean: self.on_added_clean,
373            import: self.import,
374        }
375    }
376}
377
378impl fmt::Debug for ObjectRef<'_> {
379    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380        fmt::Debug::fmt(&*self.core_ref, f)
381    }
382}
383
384impl<T: Core + fmt::Debug> fmt::Debug for ObjectRef<'_, T> {
385    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386        fmt::Debug::fmt(&*self.core_ref, f)
387    }
388}
389
390impl<T: Eq> Eq for ObjectRef<'_, T> {}
391
392impl<T: PartialEq> PartialEq for ObjectRef<'_, T> {
393    fn eq(&self, other: &Self) -> bool {
394        self.as_object() == other.as_object()
395    }
396}