Skip to main content

defi_tracker_lifecycle/lifecycle/
mapping.rs

1use crate::lifecycle::{LifecycleTransition, TerminalStatus};
2use crate::protocols::EventType;
3
4/// Canonical mapping from [`EventType`] to [`LifecycleTransition`].
5///
6/// `closed_status` is only used when `event_type` is [`EventType::Closed`] — it provides
7/// the terminal status derived from protocol-specific fields (e.g. DCA's `user_closed` + `unfilled_amount`).
8/// When `Closed` has no `closed_status`, falls back to `MetadataOnly`.
9pub fn event_type_to_transition(
10    event_type: &EventType,
11    closed_status: Option<TerminalStatus>,
12) -> LifecycleTransition {
13    match event_type {
14        EventType::Created => LifecycleTransition::Create,
15        EventType::FillInitiated | EventType::FillCompleted => LifecycleTransition::FillDelta,
16        EventType::Cancelled => LifecycleTransition::Close {
17            status: TerminalStatus::Cancelled,
18        },
19        EventType::Expired => LifecycleTransition::Close {
20            status: TerminalStatus::Expired,
21        },
22        EventType::Closed => match closed_status {
23            Some(s) => LifecycleTransition::Close { status: s },
24            None => LifecycleTransition::MetadataOnly,
25        },
26        EventType::FeeCollected | EventType::Withdrawn | EventType::Deposited => {
27            LifecycleTransition::MetadataOnly
28        }
29    }
30}
31
32/// Human-readable display string for a transition.
33pub fn transition_to_display(transition: &LifecycleTransition) -> String {
34    match transition {
35        LifecycleTransition::Create => "Create".to_string(),
36        LifecycleTransition::FillDelta => "FillDelta".to_string(),
37        LifecycleTransition::Close { status } => {
38            let s = status.as_ref();
39            let capitalized = format!(
40                "{}{}",
41                s.get(..1).unwrap_or_default().to_uppercase(),
42                s.get(1..).unwrap_or_default()
43            );
44            format!("Close({capitalized})")
45        }
46        LifecycleTransition::MetadataOnly => "MetadataOnly".to_string(),
47    }
48}
49
50/// Returns the target status string after applying a transition, or `None` for status-preserving transitions.
51pub fn transition_target(transition: &LifecycleTransition) -> Option<&'static str> {
52    match transition {
53        LifecycleTransition::Create => Some("active"),
54        LifecycleTransition::Close { status } => match status {
55            TerminalStatus::Completed => Some("completed"),
56            TerminalStatus::Cancelled => Some("cancelled"),
57            TerminalStatus::Expired => Some("expired"),
58        },
59        LifecycleTransition::FillDelta | LifecycleTransition::MetadataOnly => None,
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn event_type_to_transition_covers_all_variants() {
69        assert_eq!(
70            event_type_to_transition(&EventType::Created, None),
71            LifecycleTransition::Create
72        );
73        assert_eq!(
74            event_type_to_transition(&EventType::FillInitiated, None),
75            LifecycleTransition::FillDelta
76        );
77        assert_eq!(
78            event_type_to_transition(&EventType::FillCompleted, None),
79            LifecycleTransition::FillDelta
80        );
81        assert_eq!(
82            event_type_to_transition(&EventType::Cancelled, None),
83            LifecycleTransition::Close {
84                status: TerminalStatus::Cancelled
85            }
86        );
87        assert_eq!(
88            event_type_to_transition(&EventType::Expired, None),
89            LifecycleTransition::Close {
90                status: TerminalStatus::Expired
91            }
92        );
93        assert_eq!(
94            event_type_to_transition(&EventType::Closed, Some(TerminalStatus::Completed)),
95            LifecycleTransition::Close {
96                status: TerminalStatus::Completed
97            }
98        );
99        assert_eq!(
100            event_type_to_transition(&EventType::Closed, None),
101            LifecycleTransition::MetadataOnly
102        );
103        assert_eq!(
104            event_type_to_transition(&EventType::FeeCollected, None),
105            LifecycleTransition::MetadataOnly
106        );
107        assert_eq!(
108            event_type_to_transition(&EventType::Withdrawn, None),
109            LifecycleTransition::MetadataOnly
110        );
111        assert_eq!(
112            event_type_to_transition(&EventType::Deposited, None),
113            LifecycleTransition::MetadataOnly
114        );
115    }
116
117    #[test]
118    fn transition_display_strings() {
119        assert_eq!(
120            transition_to_display(&LifecycleTransition::Create),
121            "Create"
122        );
123        assert_eq!(
124            transition_to_display(&LifecycleTransition::FillDelta),
125            "FillDelta"
126        );
127        assert_eq!(
128            transition_to_display(&LifecycleTransition::Close {
129                status: TerminalStatus::Completed
130            }),
131            "Close(Completed)"
132        );
133        assert_eq!(
134            transition_to_display(&LifecycleTransition::Close {
135                status: TerminalStatus::Cancelled
136            }),
137            "Close(Cancelled)"
138        );
139        assert_eq!(
140            transition_to_display(&LifecycleTransition::MetadataOnly),
141            "MetadataOnly"
142        );
143    }
144
145    #[test]
146    fn transition_targets() {
147        assert_eq!(
148            transition_target(&LifecycleTransition::Create),
149            Some("active")
150        );
151        assert_eq!(
152            transition_target(&LifecycleTransition::Close {
153                status: TerminalStatus::Completed
154            }),
155            Some("completed")
156        );
157        assert_eq!(transition_target(&LifecycleTransition::FillDelta), None);
158        assert_eq!(transition_target(&LifecycleTransition::MetadataOnly), None);
159    }
160}