1use std::{mem, time::Duration};
4
5use zng_app_context::context_local;
6use zng_clone_move::clmv;
7
8use zng_handle::{Handle, HandleOwner, WeakHandle};
9use zng_time::{DInstant, Deadline, INSTANT};
10use zng_unit::TimeUnits as _;
11
12pub use zng_var_proc_macros::Transitionable;
13
14use self::types::ArcCowVar;
15
16use super::*;
17
18pub mod easing;
19
20#[derive(Default)]
21pub(super) struct AnimationHandleData {
22 on_drop: Mutex<Vec<Box<dyn FnOnce() + Send>>>,
23}
24impl Drop for AnimationHandleData {
25 fn drop(&mut self) {
26 for f in self.on_drop.get_mut().drain(..) {
27 f()
28 }
29 }
30}
31#[derive(Clone, PartialEq, Eq, Hash, Debug)]
38#[repr(transparent)]
39#[must_use = "the animation stops if the handle is dropped"]
40pub struct AnimationHandle(Handle<AnimationHandleData>);
41impl Default for AnimationHandle {
42 fn default() -> Self {
44 Self::dummy()
45 }
46}
47impl AnimationHandle {
48 pub(super) fn new() -> (HandleOwner<AnimationHandleData>, Self) {
49 let (owner, handle) = Handle::new(AnimationHandleData::default());
50 (owner, AnimationHandle(handle))
51 }
52
53 pub fn dummy() -> Self {
57 AnimationHandle(Handle::dummy(AnimationHandleData::default()))
58 }
59
60 pub fn perm(self) {
64 self.0.perm();
65 }
66
67 pub fn is_permanent(&self) -> bool {
71 self.0.is_permanent()
72 }
73
74 pub fn stop(self) {
76 self.0.force_drop();
77 }
78
79 pub fn is_stopped(&self) -> bool {
83 self.0.is_dropped()
84 }
85
86 pub fn downgrade(&self) -> WeakAnimationHandle {
88 WeakAnimationHandle(self.0.downgrade())
89 }
90
91 pub fn hook_animation_stop(&self, handler: Box<dyn FnOnce() + Send>) -> Result<(), Box<dyn FnOnce() + Send>> {
97 if !self.is_stopped() {
98 self.0.data().on_drop.lock().push(handler);
99 Ok(())
100 } else {
101 Err(handler)
102 }
103 }
104}
105
106#[derive(Clone, PartialEq, Eq, Hash, Default, Debug)]
108pub struct WeakAnimationHandle(pub(super) WeakHandle<AnimationHandleData>);
109impl WeakAnimationHandle {
110 pub fn new() -> Self {
112 Self(WeakHandle::new())
113 }
114
115 pub fn upgrade(&self) -> Option<AnimationHandle> {
117 self.0.upgrade().map(AnimationHandle)
118 }
119}
120
121struct AnimationData {
122 start_time: DInstant,
123 restart_count: usize,
124 stop: bool,
125 sleep: Option<Deadline>,
126 animations_enabled: bool,
127 force_enabled: bool,
128 now: DInstant,
129 time_scale: Factor,
130}
131
132#[derive(Clone)]
138pub struct Animation(Arc<Mutex<AnimationData>>);
139impl Animation {
140 pub(super) fn new(animations_enabled: bool, now: DInstant, time_scale: Factor) -> Self {
141 Animation(Arc::new(Mutex::new(AnimationData {
142 start_time: now,
143 restart_count: 0,
144 stop: false,
145 now,
146 sleep: None,
147 animations_enabled,
148 force_enabled: false,
149 time_scale,
150 })))
151 }
152
153 pub fn start_time(&self) -> DInstant {
155 self.0.lock().start_time
156 }
157
158 pub fn now(&self) -> DInstant {
165 self.0.lock().now
166 }
167
168 pub fn time_scale(&self) -> Factor {
170 self.0.lock().time_scale
171 }
172
173 pub(crate) fn reset_state(&self, enabled: bool, now: DInstant, time_scale: Factor) {
174 let mut m = self.0.lock();
175 if !m.force_enabled {
176 m.animations_enabled = enabled;
177 }
178 m.now = now;
179 m.time_scale = time_scale;
180 m.sleep = None;
181 }
182
183 pub(crate) fn reset_sleep(&self) {
184 self.0.lock().sleep = None;
185 }
186
187 pub fn sleep(&self, duration: Duration) {
194 let mut me = self.0.lock();
195 me.sleep = Some(Deadline(me.now + duration));
196 }
197
198 pub(crate) fn sleep_deadline(&self) -> Option<Deadline> {
199 self.0.lock().sleep
200 }
201
202 pub fn animations_enabled(&self) -> bool {
206 self.0.lock().animations_enabled
207 }
208
209 pub fn force_enable(&self) {
215 let mut me = self.0.lock();
216 me.force_enabled = true;
217 me.animations_enabled = true;
218 }
219
220 pub fn elapsed_dur(&self) -> Duration {
225 let me = self.0.lock();
226 me.now - me.start_time
227 }
228
229 pub fn elapsed(&self, duration: Duration) -> EasingTime {
235 let me = self.0.lock();
236 if me.animations_enabled {
237 EasingTime::elapsed(duration, me.now - me.start_time, me.time_scale)
238 } else {
239 EasingTime::end()
240 }
241 }
242
243 pub fn elapsed_stop(&self, duration: Duration) -> EasingTime {
247 let t = self.elapsed(duration);
248 if t.is_end() {
249 self.stop()
250 }
251 t
252 }
253
254 pub fn elapsed_restart(&self, duration: Duration) -> EasingTime {
258 let t = self.elapsed(duration);
259 if t.is_end() {
260 self.restart()
261 }
262 t
263 }
264
265 pub fn elapsed_restart_stop(&self, duration: Duration, max_restarts: usize) -> EasingTime {
270 let t = self.elapsed(duration);
271 if t.is_end() {
272 if self.restart_count() < max_restarts {
273 self.restart();
274 } else {
275 self.stop();
276 }
277 }
278 t
279 }
280
281 pub fn stop(&self) {
283 self.0.lock().stop = true;
284 }
285
286 pub fn stop_requested(&self) -> bool {
288 self.0.lock().stop
289 }
290
291 pub fn restart(&self) {
293 let now = self.0.lock().now;
294 self.set_start_time(now);
295 let mut me = self.0.lock();
296 me.restart_count += 1;
297 }
298
299 pub fn restart_count(&self) -> usize {
301 self.0.lock().restart_count
302 }
303
304 pub fn set_start_time(&self, instant: DInstant) {
308 self.0.lock().start_time = instant;
309 }
310
311 pub fn set_elapsed(&self, elapsed: EasingTime, duration: Duration) {
316 let now = self.0.lock().now;
317 self.set_start_time(now.checked_sub(duration * elapsed.fct()).unwrap());
318 }
319}
320
321pub trait Transitionable: VarValue {
328 fn lerp(self, to: &Self, step: EasingStep) -> Self;
330}
331
332pub struct Transition<T> {
334 pub from: T,
336 pub to: T,
339}
340impl<T> Transition<T>
341where
342 T: Transitionable,
343{
344 pub fn new(from: T, to: T) -> Self {
346 Self { from, to }
347 }
348
349 pub fn sample(&self, step: EasingStep) -> T {
351 self.from.clone().lerp(&self.to, step)
352 }
353}
354
355#[derive(Clone, Debug)]
357pub struct TransitionKeyed<T> {
358 keys: Vec<(Factor, T)>,
359}
360impl<T> TransitionKeyed<T>
361where
362 T: Transitionable,
363{
364 pub fn new(mut keys: Vec<(Factor, T)>) -> Option<Self> {
368 if keys.is_empty() {
369 return None;
370 }
371
372 for i in 1..keys.len() {
374 if keys[i].0 < keys[i - 1].0 {
375 keys[i].0 = keys[i - 1].0;
376 }
377 }
378
379 Some(TransitionKeyed { keys })
380 }
381
382 pub fn keys(&self) -> &[(Factor, T)] {
384 &self.keys
385 }
386
387 pub fn sample(&self, step: EasingStep) -> T {
389 if let Some(i) = self.keys.iter().position(|(f, _)| *f > step) {
390 if i == 0 {
391 self.keys[0].1.clone()
393 } else {
394 let (from_step, from_value) = self.keys[i - 1].clone();
395 if from_step == step {
396 from_value
398 } else {
399 let (_, to_value) = &self.keys[i];
402 let step = step - from_step;
403
404 from_value.lerp(to_value, step)
405 }
406 }
407 } else {
408 self.keys[self.keys.len() - 1].1.clone()
410 }
411 }
412}
413
414pub(super) struct Animations {
415 animations: Mutex<Vec<AnimationFn>>,
416 animation_imp: usize,
417 pub(super) current_modify: ModifyInfo,
418 pub(super) animation_start_time: Option<DInstant>,
419 next_frame: Option<Deadline>,
420 pub(super) animations_enabled: ArcCowVar<bool, ArcVar<bool>>,
421 pub(super) sys_animations_enabled: ArcVar<bool>,
422 pub(super) frame_duration: ArcVar<Duration>,
423 pub(super) animation_time_scale: ArcVar<Factor>,
424}
425impl Animations {
426 pub(crate) fn new() -> Self {
427 let sys_animations_enabled = var(true);
428 Self {
429 animations: Mutex::default(),
430 animation_imp: 1,
431 current_modify: ModifyInfo {
432 handle: None,
433 importance: 1,
434 },
435 animation_start_time: None,
436 next_frame: None,
437 animations_enabled: sys_animations_enabled.cow(),
438 sys_animations_enabled,
439 frame_duration: var((1.0 / 60.0).secs()),
440 animation_time_scale: var(1.fct()),
441 }
442 }
443
444 pub(super) fn update_animations(timer: &mut impl AnimationTimer) {
445 let mut vars = VARS_SV.write();
446 if let Some(next_frame) = vars.ans.next_frame {
447 if timer.elapsed(next_frame) {
448 let mut animations = mem::take(vars.ans.animations.get_mut());
449 debug_assert!(!animations.is_empty());
450
451 let info = AnimationUpdateInfo {
452 animations_enabled: vars.ans.animations_enabled.get(),
453 time_scale: vars.ans.animation_time_scale.get(),
454 now: timer.now(),
455 next_frame: next_frame + vars.ans.frame_duration.get(),
456 };
457
458 let mut min_sleep = Deadline(info.now + Duration::from_secs(60 * 60));
459
460 drop(vars);
461
462 animations.retain_mut(|animate| {
463 if let Some(sleep) = animate(info) {
464 min_sleep = min_sleep.min(sleep);
465 true
466 } else {
467 false
468 }
469 });
470
471 let mut vars = VARS_SV.write();
472
473 let self_animations = vars.ans.animations.get_mut();
474 if !self_animations.is_empty() {
475 min_sleep = Deadline(info.now);
476 }
477 animations.append(self_animations);
478 *self_animations = animations;
479
480 if !self_animations.is_empty() {
481 vars.ans.next_frame = Some(min_sleep);
482 timer.register(min_sleep);
483 } else {
484 vars.ans.next_frame = None;
485 }
486 }
487 }
488 }
489
490 pub(super) fn next_deadline(timer: &mut impl AnimationTimer) {
491 if let Some(next_frame) = VARS_SV.read().ans.next_frame {
492 timer.register(next_frame);
493 }
494 }
495
496 pub(crate) fn animate<A>(mut animation: A) -> AnimationHandle
497 where
498 A: FnMut(&Animation) + Send + 'static,
499 {
500 let mut vars = VARS_SV.write();
501
502 let start_time = if let Some(t) = vars.ans.animation_start_time {
529 t
530 } else {
531 let t = INSTANT.now();
532 vars.ans.animation_start_time = Some(t);
533 t
534 };
535
536 let mut anim_imp = None;
537 if let Some(c) = VARS_MODIFY_CTX.get_clone() {
538 if c.is_animating() {
539 anim_imp = Some(c.importance);
541 }
542 }
543 let anim_imp = match anim_imp {
544 Some(i) => i,
545 None => {
546 let mut imp = vars.ans.animation_imp.wrapping_add(1);
548 if imp == 0 {
549 imp = 1;
550 }
551
552 let mut next_imp = imp.wrapping_add(1);
553 if next_imp == 0 {
554 next_imp = 1;
555 }
556
557 vars.ans.animation_imp = next_imp;
558 vars.ans.current_modify.importance = next_imp;
559
560 imp
561 }
562 };
563
564 let (handle_owner, handle) = AnimationHandle::new();
565 let weak_handle = handle.downgrade();
566
567 let controller = VARS_ANIMATION_CTRL_CTX.get();
568
569 let anim = Animation::new(vars.ans.animations_enabled.get(), start_time, vars.ans.animation_time_scale.get());
570
571 drop(vars);
572
573 controller.on_start(&anim);
574 let mut controller = Some(controller);
575 let mut anim_modify_info = Some(Arc::new(Some(ModifyInfo {
576 handle: Some(weak_handle.clone()),
577 importance: anim_imp,
578 })));
579
580 let mut vars = VARS_SV.write();
581
582 vars.ans.animations.get_mut().push(Box::new(move |info| {
583 let _handle_owner = &handle_owner; if weak_handle.upgrade().is_some() {
586 if anim.stop_requested() {
587 controller.as_ref().unwrap().on_stop(&anim);
589 return None;
590 }
591
592 if let Some(sleep) = anim.sleep_deadline() {
593 if sleep > info.next_frame {
594 return Some(sleep);
596 } else if sleep.0 > info.now {
597 anim.reset_sleep();
599 return Some(info.next_frame);
600 }
601 }
602
603 anim.reset_state(info.animations_enabled, info.now, info.time_scale);
604
605 VARS_ANIMATION_CTRL_CTX.with_context(&mut controller, || {
606 VARS_MODIFY_CTX.with_context(&mut anim_modify_info, || animation(&anim))
607 });
608
609 Some(info.next_frame)
614 } else {
615 controller.as_ref().unwrap().on_stop(&anim);
617 None
618 }
619 }));
620
621 vars.ans.next_frame = Some(Deadline(DInstant::EPOCH));
622
623 vars.wake_app();
624
625 handle
626 }
627}
628
629type AnimationFn = Box<dyn FnMut(AnimationUpdateInfo) -> Option<Deadline> + Send>;
630
631#[derive(Clone, Copy)]
632struct AnimationUpdateInfo {
633 animations_enabled: bool,
634 now: DInstant,
635 time_scale: Factor,
636 next_frame: Deadline,
637}
638
639pub(super) fn var_animate<T: VarValue>(
640 target: &impl Var<T>,
641 animate: impl FnMut(&Animation, &mut VarModify<T>) + Send + 'static,
642) -> AnimationHandle {
643 if !target.capabilities().is_always_read_only() {
644 let target = target.clone().actual_var();
645 if !target.capabilities().is_always_read_only() {
646 let wk_target = target.downgrade();
649 let animate = Arc::new(Mutex::new(animate));
650
651 return VARS.animate(move |args| {
652 if let Some(target) = wk_target.upgrade() {
655 if target.modify_importance() > VARS.current_modify().importance {
658 args.stop();
661 return;
662 }
663
664 let r = target.modify(clmv!(animate, args, |value| {
666 (animate.lock())(&args, value);
667 }));
668
669 if let Err(VarIsReadOnlyError { .. }) = r {
670 args.stop();
672 }
673 } else {
674 args.stop();
676 }
677 });
678 }
679 }
680 AnimationHandle::dummy()
681}
682
683pub(super) fn var_sequence<T: VarValue, V: Var<T>>(
684 target: &V,
685 animate: impl FnMut(&<<V::ActualVar as Var<T>>::Downgrade as WeakVar<T>>::Upgrade) -> AnimationHandle + Send + 'static,
686) -> VarHandle {
687 if !target.capabilities().is_always_read_only() {
688 let target = target.clone().actual_var();
689 if !target.capabilities().is_always_read_only() {
690 let (handle, handle_hook) = VarHandle::new(Box::new(|_| true));
693
694 let wk_target = target.downgrade();
695
696 #[derive(Clone)]
697 struct SequenceController(Arc<dyn Fn() + Send + Sync + 'static>);
698 impl AnimationController for SequenceController {
699 fn on_stop(&self, _: &Animation) {
700 let ctrl = self.clone();
701 VARS.with_animation_controller(ctrl, || (self.0)());
702 }
703 }
704 let animate = Mutex::new(animate);
705 let animate = Arc::new(move || {
706 if let Some(target) = wk_target.upgrade() {
707 if target.modify_importance() <= VARS.current_modify().importance()
708 && handle_hook.is_alive()
709 && VARS.animations_enabled().get()
710 {
711 (animate.lock())(&target).perm();
712 }
713 }
714 });
715 VARS.with_animation_controller(SequenceController(animate.clone()), || {
716 animate();
717 });
718
719 return handle;
720 }
721 }
722 VarHandle::dummy()
723}
724
725pub(super) fn var_set_ease_with<T>(
726 start_value: T,
727 end_value: T,
728 duration: Duration,
729 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
730 init_step: EasingStep, sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
732) -> impl FnMut(&Animation, &mut VarModify<T>) + Send
733where
734 T: VarValue + Transitionable,
735{
736 let transition = Transition::new(start_value, end_value);
737 let mut prev_step = init_step;
738 move |a, vm| {
739 let step = easing(a.elapsed_stop(duration));
740
741 if prev_step != step {
742 vm.set(sampler(&transition, step));
743 prev_step = step;
744 }
745 }
746}
747
748pub(super) fn var_set_ease_oci_with<T>(
749 start_value: T,
750 end_value: T,
751 duration: Duration,
752 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
753 init_step: EasingStep, sampler: impl Fn(&Transition<T>, EasingStep) -> T + Send + 'static,
755) -> impl FnMut(&Animation, &mut VarModify<T>) + Send
756where
757 T: VarValue + Transitionable,
758{
759 let transition = Transition::new(start_value, end_value);
760 let mut prev_step = init_step;
761 move |a, vm| {
762 let t = a.elapsed(duration);
763 let mut step = easing(t);
764 if a.restart_count() % 2 != 0 {
765 step = step.flip()
766 }
767 if t.is_end() {
768 a.restart();
769 }
770
771 if prev_step != step {
772 vm.set(sampler(&transition, step));
773 prev_step = step;
774 }
775 }
776}
777
778pub(super) fn var_set_ease_keyed_with<T>(
779 transition: TransitionKeyed<T>,
780 duration: Duration,
781 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
782 init_step: EasingStep,
783 sampler: impl Fn(&TransitionKeyed<T>, EasingStep) -> T + Send + 'static,
784) -> impl FnMut(&Animation, &mut VarModify<T>) + Send
785where
786 T: VarValue + Transitionable,
787{
788 let mut prev_step = init_step;
789 move |a, value| {
790 let step = easing(a.elapsed_stop(duration));
791
792 if prev_step != step {
793 value.set(sampler(&transition, step));
794 prev_step = step;
795 }
796 }
797}
798
799pub(super) fn var_step<T>(new_value: T, delay: Duration) -> impl FnMut(&Animation, &mut VarModify<T>)
800where
801 T: VarValue,
802{
803 let mut new_value = Some(new_value);
804 move |a, vm| {
805 if !a.animations_enabled() || a.elapsed_dur() >= delay {
806 a.stop();
807 if let Some(nv) = new_value.take() {
808 vm.set(nv);
809 }
810 } else {
811 a.sleep(delay);
812 }
813 }
814}
815
816pub(super) fn var_step_oci<T>(values: [T; 2], delay: Duration, mut set: bool) -> impl FnMut(&Animation, &mut VarModify<T>)
817where
818 T: VarValue,
819{
820 let mut first = false;
821 move |a, vm| {
822 if !a.animations_enabled() || mem::take(&mut set) {
823 vm.set(values[0].clone());
824 } else if a.elapsed_dur() >= delay {
825 if first {
826 vm.set(values[0].clone());
827 } else {
828 vm.set(values[1].clone());
829 }
830 first = !first;
831 }
832 a.sleep(delay);
833 }
834}
835
836pub(super) fn var_steps<T: VarValue>(
837 steps: Vec<(Factor, T)>,
838 duration: Duration,
839 easing: impl Fn(EasingTime) -> EasingStep + 'static,
840) -> impl FnMut(&Animation, &mut VarModify<T>) {
841 let mut prev_step = 999.fct();
842 move |a, vm| {
843 let step = easing(a.elapsed_stop(duration));
844 if step != prev_step {
845 prev_step = step;
846 if let Some(val) = steps.iter().find(|(f, _)| *f >= step).map(|(_, step)| step.clone()) {
847 vm.set(val);
848 }
849 }
850 }
851}
852
853pub struct ChaseAnimation<T: VarValue + animation::Transitionable> {
855 target: T,
856 var: BoxedVar<T>,
857 handle: animation::AnimationHandle,
858}
859impl<T> fmt::Debug for ChaseAnimation<T>
860where
861 T: VarValue + animation::Transitionable,
862{
863 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
864 f.debug_struct("ChaseAnimation")
865 .field("target", &self.target)
866 .finish_non_exhaustive()
867 }
868}
869impl<T> ChaseAnimation<T>
870where
871 T: VarValue + animation::Transitionable,
872{
873 pub fn target(&self) -> &T {
875 &self.target
876 }
877
878 pub fn modify(&mut self, modify: impl FnOnce(&mut T), duration: Duration, easing: impl Fn(EasingTime) -> EasingStep + Send + 'static) {
880 if self.handle.is_stopped() {
881 self.target = self.var.get();
883 }
884 modify(&mut self.target);
885 self.handle = self.var.ease(self.target.clone(), duration, easing);
886 }
887
888 pub fn set(&mut self, value: impl Into<T>, duration: Duration, easing: impl Fn(EasingTime) -> EasingStep + Send + 'static) {
890 self.target = value.into();
891 self.handle = self.var.ease(self.target.clone(), duration, easing);
892 }
893}
894
895pub(super) fn var_chase<T>(
896 var: BoxedVar<T>,
897 first_target: T,
898 duration: Duration,
899 easing: impl Fn(EasingTime) -> EasingStep + Send + 'static,
900) -> ChaseAnimation<T>
901where
902 T: VarValue + animation::Transitionable,
903{
904 ChaseAnimation {
905 handle: var.ease(first_target.clone(), duration, easing),
906 target: first_target,
907 var,
908 }
909}
910
911#[derive(Clone)]
913pub struct ModifyInfo {
914 handle: Option<WeakAnimationHandle>,
915 pub(crate) importance: usize,
916}
917impl ModifyInfo {
918 pub fn never() -> Self {
920 ModifyInfo {
921 handle: None,
922 importance: 0,
923 }
924 }
925
926 pub fn importance(&self) -> usize {
932 self.importance
933 }
934
935 pub fn is_animating(&self) -> bool {
943 self.handle.as_ref().map(|h| h.upgrade().is_some()).unwrap_or(false)
944 }
945
946 pub fn animation_eq(&self, other: &Self) -> bool {
948 self.handle == other.handle
949 }
950
951 pub fn hook_animation_stop(&self, handler: Box<dyn FnOnce() + Send>) -> Result<(), Box<dyn FnOnce() + Send>> {
955 if let Some(h) = &self.handle {
956 if let Some(h) = h.upgrade() {
957 return h.hook_animation_stop(handler);
958 }
959 }
960 Err(handler)
961 }
962}
963impl fmt::Debug for ModifyInfo {
964 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
965 f.debug_struct("ModifyInfo")
966 .field("is_animating()", &self.is_animating())
967 .field("importance()", &self.importance)
968 .finish()
969 }
970}
971
972pub trait AnimationController: Send + Sync + Any {
978 fn on_start(&self, animation: &Animation) {
982 let _ = animation;
983 }
984
985 fn on_stop(&self, animation: &Animation) {
989 let _ = animation;
990 }
991}
992
993impl AnimationController for () {}
994
995pub struct ForceAnimationController;
997impl AnimationController for ForceAnimationController {
998 fn on_start(&self, animation: &Animation) {
999 animation.force_enable();
1000 }
1001}
1002
1003context_local! {
1004 pub(crate) static VARS_ANIMATION_CTRL_CTX: Box<dyn AnimationController> = {
1005 let r: Box<dyn AnimationController> = Box::new(());
1006 r
1007 };
1008}
1009
1010pub trait AnimationTimer {
1012 fn elapsed(&mut self, deadline: Deadline) -> bool;
1015
1016 fn register(&mut self, deadline: Deadline);
1018
1019 fn now(&self) -> DInstant;
1021}