1use 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}