Skip to main content

prettyping_rs/engine/
mod.rs

1use std::net::IpAddr;
2use std::time::Duration;
3
4use thiserror::Error;
5
6pub mod mock;
7
8#[cfg(any(target_os = "linux", target_os = "macos"))]
9pub mod unix_surge;
10
11#[cfg(target_os = "windows")]
12pub mod windows_ping_async;
13
14pub type SequenceNumber = u64;
15pub type EngineTime = Duration;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct ProbeRequest {
19    pub seq: SequenceNumber,
20    pub target: IpAddr,
21    pub sent_at: EngineTime,
22    pub payload_size: usize,
23    pub ttl: Option<u8>,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct PingReply {
28    pub seq: SequenceNumber,
29    pub ttl: Option<u8>,
30    pub payload_size: usize,
31    pub source: Option<IpAddr>,
32}
33
34impl PingReply {
35    #[must_use]
36    pub fn for_seq(seq: SequenceNumber) -> Self {
37        Self {
38            seq,
39            ttl: None,
40            payload_size: 0,
41            source: None,
42        }
43    }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub enum PingEvent {
48    Reply(PingReply),
49    Interrupt,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct TimedEvent {
54    pub at: EngineTime,
55    pub event: PingEvent,
56}
57
58#[derive(Debug, Error, Clone, PartialEq, Eq)]
59pub enum PingEngineError {
60    #[error("send failed for seq {seq}: {message}")]
61    SendFailed {
62        seq: SequenceNumber,
63        message: String,
64    },
65    #[error("poll failed: {message}")]
66    PollFailed { message: String },
67    #[error("invalid engine timeline: poll deadline moved backwards")]
68    NonMonotonicPoll,
69    #[error("invalid probe request for seq {seq}: {message}")]
70    InvalidProbeRequest {
71        seq: SequenceNumber,
72        message: String,
73    },
74}
75
76pub trait PingEngine {
77    fn now(&self) -> EngineTime;
78
79    fn send_probe(&mut self, request: ProbeRequest) -> Result<(), PingEngineError>;
80
81    /// Polls for the next event up to `deadline`.
82    ///
83    /// Implementations must keep time monotonic. If there is an event at or before
84    /// `deadline`, return all events for that exact timestamp and advance `now()` to
85    /// that timestamp. If no event exists before `deadline`, advance to at least
86    /// `deadline` and return an empty vector.
87    ///
88    /// Real-time backends may need to catch up after a process pause/sleep. If
89    /// `deadline` is already behind the backend's wall-clock elapsed time, they may
90    /// advance to "now" instead of stalling behind real time.
91    fn poll_until(&mut self, deadline: EngineTime) -> Result<Vec<TimedEvent>, PingEngineError>;
92}