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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
use enumflags2::{bitflags, BitFlags};

use crate::{
  dds::with_key::datawriter::WriteOptions,
  structure::{guid::GUID, rpc::SampleIdentity, sequence_number::SequenceNumber, time::Timestamp},
};

// use std::num::Zero; // unstable

/// indicates whether or not the corresponding data sample has already
/// been read by this `DataReader`.
///
/// > For each sample received, the middleware internally maintains a
/// > sample_state relative to each DataReader. The sample_state can either be
/// > READ or NOT_READ.
///
/// > The sample_state will, in general, be different for each sample in the
/// > collection returned by [`read()`](crate::with_key::DataReader::read())
/// > or [`take()`](crate::with_key::DataReader::take()).
///
/// See DDS spec v1.4 Section 2.2.2.5.4 and Section "2.2.2.5.1.2 Interpretation
/// of the SampleInfo sample_state".
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[bitflags]
#[repr(u32)] // DDS Spec 1.4 section 2.3.3 DCPS PSM : IDL defines these as "unsigned long",
             // so u32
pub enum SampleState {
  /// > indicates that the DataReader has already accessed that sample by means
  /// of `read()` ... or corresponding iterator.
  Read = 0b0001,
  /// > indicates that the DataReader has not accessed that sample before
  NotRead = 0b0010,
}

impl SampleState {
  /// Set that contains all possible states
  pub fn any() -> BitFlags<Self> {
    BitFlags::<Self>::all()
  }
}

/// Indicates if this data *instance* has been seen (viewed).
///
/// > For each instance (identified by the [key](crate::Key)), the middleware
/// > internally maintains a view_state relative to each DataReader. The
/// > view_state can either be NEW or NOT_NEW.
///
/// > The view_state available in the SampleInfo is a snapshot of the view_state
/// > of the instance relative to the DataReader used to access the samples at
/// > the time the collection was obtained (i.e., at the time read or take was
/// > called). The view_state is therefore the same for all samples in the
/// > returned collection that refer to the same instance.
/// > Once an instance has been detected as not having any "live" writers and
/// > all the samples associated with the instance are ‘taken’ from the
/// > DataReader, the middleware can reclaim all local resources regarding the
/// > instance. Future samples will be treated as 'never seen'.
///
/// Cf. [`SampleState`]
///
/// See DDS spec v.14 Section 2.2.2.5.1.8 Interpretation of the SampleInfo
/// view_state
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
#[bitflags]
pub enum ViewState {
  /// > indicates that either this is the first time that the DataReader has
  /// > ever accessed samples of that instance, or else that the DataReader
  /// > has accessed previous samples of the instance, but the instance has
  /// > since been reborn (i.e., become not-alive and then alive again).
  New = 0b0001,
  /// > indicates that the DataReader has already accessed samples of the same
  /// > instance and that the instance has not been reborn since
  NotNew = 0b0010,
}
impl ViewState {
  /// Set that contains all possible states
  pub fn any() -> BitFlags<Self> {
    BitFlags::<Self>::all()
  }
}

/// Is this data instance alive or not and why.
///
/// > The instance_state available in the SampleInfo is a snapshot of the
/// > instance_state of the instance at the time the collection was obtained
/// > (i.e., at the time read or take was called). The instance_state is
/// > therefore be the same for all samples in the returned collection that
/// > refer to the same instance.
///
/// DDS spec v1.4 Section "2.2.2.5.1.3 Interpretation of the SampleInfo
/// instance_state"
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
#[bitflags]
pub enum InstanceState {
  /// > indicates that (a) samples have been received for the instance, (b)
  /// > there are live DataWriter entities writing the instance, and (c) the
  /// > instance has not been explicitly disposed (or else more samples have
  /// > been received after it was disposed).
  Alive = 0b0001,

  /// > indicates the instance was explicitly disposed by a DataWriter by means
  /// > of the dispose operation.
  NotAliveDisposed = 0b0010,

  /// > indicates the instance has been declared as not-alive by the DataReader
  /// > because it  detected that there are no live DataWriter entities writing
  /// > that instance
  NotAliveNoWriters = 0b0100,
}

impl InstanceState {
  /// Set that contains all possible states
  pub fn any() -> BitFlags<Self> {
    BitFlags::<Self>::all()
  }
  /// Set that contains both not_alive states.
  pub fn not_alive() -> BitFlags<Self> {
    Self::NotAliveDisposed | Self::NotAliveNoWriters
  }
}

/// A double counter for counting how many times an instance as become Alive.
///
/// > For each instance the middleware internally maintains two counts: the
/// > disposed_generation_count and no_writers_generation_count, relative to
/// > each DataReader:
/// > * The disposed_generation_count and
/// > no_writers_generation_count are initialized to zero when the DataReader
/// > first detects the presence of a never-seen-before instance.
/// > * The disposed_generation_count is incremented each time the
/// > instance_state of the corresponding instance changes
/// > from NOT_ALIVE_DISPOSED to ALIVE.
/// > * The no_writers_generation_count is incremented each time the
/// > instance_state of the corresponding instance changes
/// > from NOT_ALIVE_NO_WRITERS to ALIVE.
/// > The disposed_generation_count and no_writers_generation_count available in
/// > the SampleInfo capture a snapshot of the corresponding counters at the
/// > time the sample was received.
///
/// See DDS spec v1.4 Section "2.2.2.5.1.5 Interpretation of the SampleInfo
/// disposed_generation_count and no_writers_generation_count"
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NotAliveGenerationCounts {
  pub disposed_generation_count: i32,
  pub no_writers_generation_count: i32,
}

impl NotAliveGenerationCounts {
  /// Initial count value
  pub fn zero() -> Self {
    Self {
      disposed_generation_count: 0,
      no_writers_generation_count: 0,
    }
  }

  /// Marker value for "never accessed"
  pub fn sub_zero() -> Self {
    Self {
      disposed_generation_count: -1,
      no_writers_generation_count: -1,
    }
  }

  pub fn total(&self) -> i32 {
    self.disposed_generation_count + self.no_writers_generation_count
  }
}

/// SampleInfo is metadata attached to each received data sample.
/// It exists only at the receiving end of DDS, and is (mostly) generated by
/// DDS.
///
/// Some of the SampleInfo field description texts are quoted from the DDS
/// Specification.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SampleInfo {
  /// sample_state indicates whether or not the corresponding data sample has
  /// already been read through this DataReader.
  pub(crate) sample_state: SampleState,

  /// Indicates that either this is the first time that the DataReader has ever
  /// accessed samples of that instance, or else that the DataReader has
  /// accessed previous samples of the instance, but the instance has since
  /// been reborn (i.e., become not-alive and then alive again).
  pub(crate) view_state: ViewState,

  /// Indicates whether this instance is alive or not.
  /// The instance can be not alive either because some writer has actively
  /// disposed it, or there are no writers alive.
  pub(crate) instance_state: InstanceState,

  /// For each instance the middleware internally maintains these counts
  /// relative to each DataReader. The counts capture snapshots of the
  /// corresponding counters at the time the sample was received.
  pub(crate) generation_counts: NotAliveGenerationCounts,

  /// The ranks are are computed based solely on the actual samples in the
  /// ordered collection returned by the read or take.
  /// The sample_rank indicates the number of samples of the same instance that
  /// follow the current one in the collection.
  pub(crate) sample_rank: i32,

  /// The generation_rank indicates the difference in generations between the
  /// samples S and the Most Recent Sample of the same instance that appears In
  /// the returned Collection (MRSIC). It counts the number of times the
  /// instance transitioned from not-alive to alive in the time from the
  /// reception of the S to the  reception of MRSIC. The generation rank is
  /// computed with: generation_rank =
  /// (MRSIC.disposed_generation_count + MRSIC.no_writers_generation_count)
  ///   -- (S.disposed_generation_count + S.no_writers_generation_count)
  pub(crate) generation_rank: i32,

  /// The absolute_generation_rank indicates the difference in "generations"
  /// between sample S and the Most Recent Sample of the instance that the
  /// middleware has received (MRS). It counts the number of times the instance
  /// transitioned from not-alive to alive in the time from the reception of the
  /// S to the time when the read or take was called. absolute_generation_rank =
  /// (MRS.disposed_generation_count + MRS.no_writers_generation_count)
  ///   -- (S.disposed_generation_count + S.no_writers_generation_count)
  pub(crate) absolute_generation_rank: i32,

  pub(crate) write_options: WriteOptions,

  /// publication_handle identifies the DataWriter that modified
  /// the instance (i.e. wrote this sample)
  pub(crate) publication_handle: GUID,
  pub(crate) sequence_number: SequenceNumber,
}

impl SampleInfo {
  /// Source timestamp is the timestamp that was supplied by the DataWriter
  /// that sent this sample. It is optional to timestamp samples when writing.
  pub fn source_timestamp(&self) -> Option<Timestamp> {
    self.write_options.source_timestamp()
  }

  pub fn sample_state(&self) -> SampleState {
    self.sample_state
  }

  // pub fn set_sample_state(&mut self, sample_state: SampleState) {
  //   self.sample_state = sample_state
  // }

  pub fn view_state(&self) -> ViewState {
    self.view_state
  }

  // pub fn set_view_state(&mut self, view_state: ViewState) {
  //   self.view_state = view_state;
  // }

  pub fn instance_state(&self) -> InstanceState {
    self.instance_state
  }

  // pub fn set_instance_state(&mut self, instance_state: InstanceState) {
  //   self.instance_state = instance_state;
  // }

  pub fn disposed_generation_count(&self) -> i32 {
    self.generation_counts.disposed_generation_count
  }

  pub fn no_writers_generation_count(&self) -> i32 {
    self.generation_counts.no_writers_generation_count
  }

  pub fn sample_rank(&self) -> i32 {
    self.sample_rank
  }

  pub fn generation_rank(&self) -> i32 {
    self.generation_rank
  }

  pub fn absolute_generation_rank(&self) -> i32 {
    self.absolute_generation_rank
  }

  /// publication_handle identifies the DataWriter that modified
  /// the instance (i.e. wrote this sample)
  pub fn publication_handle(&self) -> GUID {
    self.publication_handle
  }

  pub fn writer_guid(&self) -> GUID {
    self.publication_handle
  }

  pub fn related_sample_identity(&self) -> Option<SampleIdentity> {
    self.write_options.related_sample_identity()
  }

  pub fn sample_identity(&self) -> SampleIdentity {
    SampleIdentity {
      writer_guid: self.publication_handle,
      sequence_number: self.sequence_number,
    }
  }

  // pub fn set_publication_handle(&mut self, publication_handle: GUID) {
  //   self.publication_handle = publication_handle
  // }
}