1use std::any::{self, Any, TypeId};
6use std::fmt;
7use std::rc::Rc;
8
9use crate::animation::Loop;
10use crate::artboard::Artboard;
11use crate::draw_target::DrawTargetPlacement;
12use crate::importers::ImportStack;
13use crate::shapes::paint::{BlendMode, Color32, StrokeCap, StrokeJoin};
14use crate::shapes::FillRule;
15use crate::StatusCode;
16
17mod binary_reader;
18mod object;
19mod property;
20
21pub use binary_reader::BinaryReader;
22pub use object::{Object, ObjectRef};
23pub use property::{Property, TryFromU64};
24
25macro_rules! types {
26 ( $( ( $id:expr , $type:ty ) ),* $( , )? ) => {
27 pub fn get_type_id(id: u16) -> Option<TypeId> {
28 match id {
29 $(
30 $id => Some(TypeId::of::<$type>()),
31 )*
32 _ => None,
33 }
34 }
35
36 impl dyn Core {
37 pub fn from_type_id(id: TypeId) -> Option<(Rc<dyn Core>, Object)> {
38 match id {
39 $(
40 id if id == TypeId::of::<$type>() => {
41 let rc: Rc<dyn Core> = Rc::new(<$type>::default());
42 let object = Object::<$type>::new(&rc);
43 Some((rc, object.into()))
44 }
45 )*
46 _ => None,
47 }
48 }
49 }
50 };
51}
52
53macro_rules! parent_types {
54 ( ( $field_head:ident , $type_head:ty ) $( , ( $field_tail:ident , $type_tail:ty ) )* $( , )? ) => {
55 fn ref_of(&self, id: ::std::any::TypeId) -> Option<&dyn Core> {
56 if id == ::std::any::TypeId::of::<$type_head>() {
57 Some(&self.$field_head)
58 }
59 $(
60 else if id == ::std::any::TypeId::of::<$type_tail>() {
61 Some(&self.$field_tail)
62 }
63 )*
64 else {
65 self.$field_head
66 .ref_of(id)
67 $(
68 .or_else(|| self.$field_tail.ref_of(id))
69 )*
70 }
71 }
72 };
73}
74
75macro_rules! properties {
76 ( $parent:ident ) => {
77 fn property_of(&self, key: u16) -> Option<&dyn ::std::any::Any> {
78 self.$parent.property_of(key)
79 }
80
81 fn animate(&self, object: &ObjectRef<'_>, key: u64, animator: &dyn ::std::any::Any) {
82 self.$parent.animate(object, key, animator);
83 }
84 };
85
86 ( $( ( $key:expr , $field:ident , $setter:ident ) ),* , $parent:ident $( , )? ) => {
87 fn property_of(&self, key: u16) -> Option<&dyn ::std::any::Any> {
88 match key {
89 $(
90 $key => Some(&self.$field),
91 )*
92 _ => self.$parent.property_of(key),
93 }
94 }
95
96 fn animate(&self, object: &ObjectRef<'_>, key: u64, animator: &dyn ::std::any::Any) {
97 $(
98 if key == $key {
99 if let Some(animator) = animator.downcast_ref::<crate::animation::Animator<_>>() {
100 return animator.animate(&object.cast(), ObjectRef::<Self>::$setter);
101 }
102 }
103 )*
104
105 self.$parent.animate(&object, key, animator);
106 }
107 };
108
109 ( $( ( $key:expr , $field:ident , $setter:ident ) ),* $( , )? ) => {
110 fn property_of(&self, key: u16) -> Option<&dyn ::std::any::Any> {
111 match key {
112 $(
113 $key => Some(&self.$field),
114 )*
115 _ => None,
116 }
117 }
118
119 fn animate(&self, object: &ObjectRef<'_>, key: u64, animator: &dyn ::std::any::Any) {
120 $(
121 if key == $key {
122 if let Some(animator) = animator.downcast_ref::<crate::animation::Animator<_>>() {
123 return animator.animate(&object.cast(), ObjectRef::<Self>::$setter);
124 }
125 }
126 )*
127 }
128 };
129}
130
131macro_rules! on_added {
132 ( @impl import ) => {
133 fn import(&self, _object: crate::core::Object, _import_stack: &crate::importers::ImportStack) -> crate::status_code::StatusCode {
134 crate::status_code::StatusCode::Ok
135 }
136 };
137
138 ( @impl $method:ident ) => {
139 fn $method(&self, _context: &dyn crate::core::CoreContext) -> crate::status_code::StatusCode {
140 crate::status_code::StatusCode::Ok
141 }
142 };
143
144 ( @impl import , $type:ty ) => {
145 fn import(&self, object: crate::core::Object, import_stack: &crate::importers::ImportStack) -> crate::status_code::StatusCode {
146 self.cast::<$type>().import(object, import_stack)
147 }
148 };
149
150 ( @impl $method:ident , $type:ty ) => {
151 fn $method(&self, context: &dyn crate::core::CoreContext) -> crate::status_code::StatusCode {
152 self.cast::<$type>().$method(context)
153 }
154 };
155
156 () => {
157 on_added!(@impl on_added_dirty);
158 on_added!(@impl on_added_clean);
159 on_added!(@impl import);
160 };
161
162 ( [ $( $method:ident ),+ ] ) => {
163 $(
164 on_added!(@impl $method);
165 )+
166 };
167
168 ( [ $( $method:ident ),+ ] , $type:ty ) => {
169 $(
170 on_added!(@impl $method, $type);
171 )+
172 };
173
174 ( $type:ty ) => {
175 on_added!(@impl on_added_dirty, $type);
176 on_added!(@impl on_added_clean, $type);
177 on_added!(@impl import, $type);
178 };
179}
180
181macro_rules! match_cast {
182 ( $val:expr , { $( $to:ident ( $name:ident ) => $block:expr ),* $( , _ => $default:expr )? $( , )? } ) => {{
183 let f = || {
184 $(
185 if let Some($name) = $val.try_cast::<$to>() {
186 return $block;
187 }
188 )*
189 $($default)?
190 };
191
192 f()
193 }};
194}
195
196pub trait AsAny: Any + fmt::Debug {
197 fn as_any(&self) -> &dyn Any;
198 fn any_type_name(&self) -> &'static str;
199}
200
201impl<T: Any + fmt::Debug> AsAny for T {
202 #[inline(always)]
203 fn as_any(&self) -> &dyn Any {
204 self
205 }
206
207 #[inline(always)]
208 fn any_type_name(&self) -> &'static str {
209 core::any::type_name::<T>()
210 }
211}
212
213trait Cast: Core {
214 #[inline]
215 fn is<T>(&self) -> bool
216 where
217 T: Core,
218 {
219 self.as_any().is::<T>() || self.ref_of(TypeId::of::<T>()).is_some()
220 }
221
222 #[inline]
223 fn try_cast<T>(&self) -> Option<&T>
224 where
225 T: Core,
226 {
227 self.as_any()
228 .downcast_ref()
229 .or_else(|| self.ref_of(TypeId::of::<T>()).and_then(|any| any.as_any().downcast_ref()))
230 }
231
232 #[inline]
233 fn cast<T>(&self) -> &T
234 where
235 T: Core,
236 {
237 self.try_cast().unwrap_or_else(|| panic!("failed cast to {}", any::type_name::<T>()))
238 }
239}
240
241impl Cast for dyn Core {}
242
243#[allow(unused_variables)]
244pub trait Core: AsAny {
245 #[inline]
246 fn ref_of(&self, id: TypeId) -> Option<&dyn Core> {
247 None
248 }
249
250 #[inline]
251 fn property_of(&self, key: u16) -> Option<&dyn Any> {
252 None
253 }
254
255 #[inline]
256 fn animate(&self, object: &ObjectRef<'_>, key: u64, animator: &dyn Any) {}
257
258 #[inline]
259 fn type_name(&self) -> &'static str {
260 self.any_type_name().rsplit("::").next().unwrap()
261 }
262}
263
264impl dyn Core {
265 #[inline]
266 pub fn get_property<T: Clone + Default + 'static>(&self, key: u16) -> Option<&Property<T>> {
267 self.property_of(key).and_then(<dyn Any>::downcast_ref::<Property<T>>)
268 }
269
270 pub(crate) fn write(&self, property_key: u16, reader: &mut BinaryReader<'_>) -> bool {
271 if let Some(property) = self.property_of(property_key) {
272 macro_rules! write_types {
273 ( $property:expr , $reader:expr , [ $( $type:ident ),* $( , )? ] ) => {
274 match $property.type_id() {
275 $(
276 id if id == TypeId::of::<Property<$type>>() => {
277 let property = property.downcast_ref::<Property<$type>>().unwrap();
278 return $reader.write(property);
279 }
280 )*
281 _ => (),
282 }
283 };
284 }
285
286 write_types!(
287 property,
288 reader,
289 [
290 bool,
291 u32,
292 u64,
293 f32,
294 String,
295 Color32,
296 BlendMode,
297 DrawTargetPlacement,
298 FillRule,
299 Loop,
300 StrokeCap,
301 StrokeJoin,
302 ]
303 );
304 }
305
306 false
307 }
308}
309
310pub trait OnAdded {
311 fn on_added_dirty(&self, context: &dyn CoreContext) -> StatusCode;
312
313 fn on_added_clean(&self, context: &dyn CoreContext) -> StatusCode;
314
315 fn import(&self, object: Object, import_stack: &ImportStack) -> StatusCode;
316}
317
318pub trait CoreContext {
319 fn resolve(&self, id: usize) -> Option<Object>;
320 fn artboard(&self) -> Object<Artboard> {
321 self.resolve(0)
322 .and_then(|object| object.try_cast())
323 .expect("frist object should always be the Artboard")
324 }
325}
326
327types![
328 (1, crate::Artboard),
329 (2, crate::Node),
330 (3, crate::shapes::Shape),
331 (4, crate::shapes::Ellipse),
332 (5, crate::shapes::StraightVertex),
333 (6, crate::shapes::CubicDetachedVertex),
334 (7, crate::shapes::Rectangle),
335 (8, crate::shapes::Triangle),
336 (9, crate::shapes::PathComposer),
337 (10, crate::Component),
338 (11, crate::ContainerComponent),
339 (13, crate::Drawable),
340 (14, crate::shapes::PathVertex),
341 (15, crate::shapes::ParametricPath),
342 (16, crate::shapes::PointsPath),
343 (17, crate::shapes::paint::RadialGradient),
344 (18, crate::shapes::paint::SolidColor),
345 (19, crate::shapes::paint::GradientStop),
346 (20, crate::shapes::paint::Fill),
347 (21, crate::shapes::paint::ShapePaint),
348 (22, crate::shapes::paint::LinearGradient),
349 (23, crate::Backboard),
350 (24, crate::shapes::paint::Stroke),
351 (25, crate::animation::KeyedObject),
352 (26, crate::animation::KeyedProperty),
353 (27, crate::animation::Animation),
354 (28, crate::animation::CubicInterpolator),
355 (29, crate::animation::KeyFrame),
356 (30, crate::animation::KeyFrameDouble),
357 (31, crate::animation::LinearAnimation),
358 (34, crate::shapes::CubicAsymmetricVertex),
359 (35, crate::shapes::CubicMirroredVertex),
360 (37, crate::animation::KeyFrameColor),
361 (38, crate::TransformComponent),
362 (39, crate::bones::SkeletalComponent),
363 (40, crate::bones::Bone),
364 (41, crate::bones::RootBone),
365 (42, crate::shapes::ClippingShape),
366 (43, crate::bones::Skin),
367 (44, crate::bones::Tendon),
368 (45, crate::bones::Weight),
369 (46, crate::bones::CubicWeight),
370 (47, crate::shapes::paint::TrimPath),
371 (48, crate::DrawTarget),
372 (49, crate::DrawRules),
373 (50, crate::animation::KeyFrameId),
374 (51, crate::shapes::Polygon),
375 (52, crate::shapes::Star),
376 (53, crate::animation::StateMachine),
377 (54, crate::animation::StateMachineComponent),
378 (55, crate::animation::StateMachineInput),
379 (56, crate::animation::StateMachineDouble),
380 (57, crate::animation::StateMachineLayer),
381 (58, crate::animation::StateMachineTrigger),
382 (59, crate::animation::StateMachineBool),
383 (60, crate::animation::LayerState),
384 (61, crate::animation::AnimationState),
385 (62, crate::animation::AnyState),
386 (63, crate::animation::EntryState),
387 (64, crate::animation::ExitState),
388 (65, crate::animation::StateTransition),
389 (66, crate::animation::StateMachineLayerComponent),
390 (67, crate::animation::TransitionCondition),
391 (68, crate::animation::TransitionTriggerCondition),
392 (69, crate::animation::TransitionValueCondition),
393 (70, crate::animation::TransitionDoubleCondition),
394 (71, crate::animation::TransitionBoolCondition),
395];