1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
use core::iter::Fuse;

use arrayvec::ArrayVec;

use crate::{
    datastructures::common::{PortIdentity, Tlv, TlvSetIterator},
    filters::FilterUpdate,
};

#[derive(Debug, Clone)]
/// TLV that needs to be forwarded in the announce messages of other ports.
pub struct ForwardedTLV<'a> {
    pub(super) tlv: Tlv<'a>,
    pub(super) sender_identity: PortIdentity,
}

impl<'a> ForwardedTLV<'a> {
    /// Wire size of the TLV. Can be used to determine how many TLV's to keep
    pub fn size(&self) -> usize {
        self.tlv.wire_size()
    }

    /// Get an owned version of the struct.
    #[cfg(feature = "std")]
    pub fn into_owned(self) -> ForwardedTLV<'static> {
        ForwardedTLV {
            tlv: self.tlv.into_owned(),
            sender_identity: self.sender_identity,
        }
    }
}

/// Source of TLVs that need to be forwarded, provided to announce sender.
pub trait ForwardedTLVProvider {
    /// Should provide the next available TLV, unless it is larger than max_size
    fn next_if_smaller(&mut self, max_size: usize) -> Option<ForwardedTLV>;
}

/// Simple implementation when
#[derive(Debug, Copy, Clone)]
pub struct NoForwardedTLVs;

impl ForwardedTLVProvider for NoForwardedTLVs {
    fn next_if_smaller(&mut self, _max_size: usize) -> Option<ForwardedTLV> {
        None
    }
}

/// Identification of a packet that should be sent out.
///
/// The caller receives this from a [`PortAction::SendEvent`] and should return
/// it to the [`Port`](`super::Port`) with
/// [`Port::handle_send_timestamp`](`super::Port::handle_send_timestamp`) once
/// the transmit timestamp of that packet is known.
///
/// This type is non-copy and non-clone on purpose to ensures a single
/// [`handle_send_timestamp`](`super::Port::handle_send_timestamp`) per
/// [`SendEvent`](`PortAction::SendEvent`).
#[derive(Debug)]
pub struct TimestampContext {
    pub(super) inner: TimestampContextInner,
}

#[derive(Debug)]
pub(super) enum TimestampContextInner {
    Sync {
        id: u16,
    },
    DelayReq {
        id: u16,
    },
    PDelayReq {
        id: u16,
    },
    PDelayResp {
        id: u16,
        requestor_identity: PortIdentity,
    },
}

/// An action the [`Port`](`super::Port`) needs the user to perform
#[derive(Debug)]
#[must_use]
#[allow(missing_docs)] // Explaining the fields as well as the variants does not add value
pub enum PortAction<'a> {
    /// Send a time-critical packet
    ///
    /// Once the packet is sent and the transmit timestamp known the user should
    /// return the given [`TimestampContext`] using
    /// [`Port::handle_send_timestamp`](`super::Port::handle_send_timestamp`).
    ///
    /// Packets marked as link local should be sent per the instructions
    /// for sending peer to peer delay mechanism messages of the relevant
    /// transport specification of PTP.
    SendEvent {
        context: TimestampContext,
        data: &'a [u8],
        link_local: bool,
    },
    /// Send a general packet
    ///
    /// For a packet sent this way no timestamp needs to be captured.
    ///
    /// Packets marked as link local should be sent per the instructions
    /// for sending peer to peer delay mechanism messages of the relevant
    /// transport specification of PTP.
    SendGeneral { data: &'a [u8], link_local: bool },
    /// Call [`Port::handle_announce_timer`](`super::Port::handle_announce_timer`) in `duration` from now
    ResetAnnounceTimer { duration: core::time::Duration },
    /// Call [`Port::handle_sync_timer`](`super::Port::handle_sync_timer`) in
    /// `duration` from now
    ResetSyncTimer { duration: core::time::Duration },
    /// Call [`Port::handle_delay_request_timer`](`super::Port::handle_delay_request_timer`) in `duration` from now
    ResetDelayRequestTimer { duration: core::time::Duration },
    /// Call [`Port::handle_announce_receipt_timer`](`super::Port::handle_announce_receipt_timer`) in `duration` from now
    ResetAnnounceReceiptTimer { duration: core::time::Duration },
    /// Call [`Port::handle_filter_update_timer`](`super::Port::handle_filter_update_timer`) in `duration` from now
    ResetFilterUpdateTimer { duration: core::time::Duration },
    /// Forward this TLV to the announce timer call of all other ports.
    /// The receiver must ensure the TLV is yielded only once to the announce
    /// method of a port.
    ///
    /// This can be ignored when implementing a single port or slave only ptp
    /// instance.
    ForwardTLV { tlv: ForwardedTLV<'a> },
}

const MAX_ACTIONS: usize = 2;

/// An Iterator over [`PortAction`]s
///
/// These are returned by [`Port`](`super::Port`) when ever the library needs
/// the user to perform actions to the system.
///
/// **Guarantees to end user:** Any set of actions will only ever contain a
/// single event send
#[derive(Debug)]
#[must_use]
pub struct PortActionIterator<'a> {
    internal: Fuse<<ArrayVec<PortAction<'a>, MAX_ACTIONS> as IntoIterator>::IntoIter>,
    tlvs: TlvSetIterator<'a>,
    sender_identity: PortIdentity,
}

impl<'a> PortActionIterator<'a> {
    /// Get an empty Iterator
    ///
    /// This can for example be used to have a default value in chained `if`
    /// statements.
    pub fn empty() -> Self {
        Self {
            internal: ArrayVec::new().into_iter().fuse(),
            tlvs: TlvSetIterator::empty(),
            sender_identity: Default::default(),
        }
    }
    pub(super) fn from(list: ArrayVec<PortAction<'a>, MAX_ACTIONS>) -> Self {
        Self {
            internal: list.into_iter().fuse(),
            tlvs: TlvSetIterator::empty(),
            sender_identity: Default::default(),
        }
    }
    pub(super) fn from_filter(update: FilterUpdate) -> Self {
        if let Some(duration) = update.next_update {
            actions![PortAction::ResetFilterUpdateTimer { duration }]
        } else {
            actions![]
        }
    }
    pub(super) fn with_forward_tlvs(
        self,
        tlvs: TlvSetIterator<'a>,
        sender_identity: PortIdentity,
    ) -> Self {
        Self {
            internal: self.internal,
            tlvs,
            sender_identity,
        }
    }
}

impl<'a> Iterator for PortActionIterator<'a> {
    type Item = PortAction<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        self.internal.next().or_else(|| loop {
            let tlv = self.tlvs.next()?;
            if tlv.tlv_type.announce_propagate() {
                return Some(PortAction::ForwardTLV {
                    tlv: ForwardedTLV {
                        tlv,
                        sender_identity: self.sender_identity,
                    },
                });
            }
        })
    }
}