cyclonedds/sample.rs
1//! Types representing received DDS samples and their associated metadata.
2//!
3//! A received sample is either a full data sample of type
4//! [`T`](crate::Topicable) or a key-only sample carrying the instance key
5//! [`T::Key`](crate::Topicable::Key).
6//!
7//! This distinction arises in DDS when an instance is disposed or unregistered,
8//! the reader receives a notification carrying only the key rather than a full
9//! payload.
10//!
11//! Samples are obtained via [`Reader::peek`](crate::Reader::peek),
12//! [`Reader::read`](crate::Reader::read), and
13//! [`Reader::take`](crate::Reader::take), or their equivalents on
14//! [`ReadCondition`](crate::ReadCondition) and
15//! [`QueryCondition`](crate::QueryCondition).
16
17use crate::Topicable;
18
19#[derive(Clone, Debug)]
20pub(crate) enum SampleOrKeyInner<T>
21where
22 T: crate::Topicable,
23{
24 Sample {
25 sample: Box<T>,
26 materialized_key: std::cell::OnceCell<Box<T::Key>>,
27 },
28 Key {
29 key: Box<T::Key>,
30 materialized_sample: std::cell::OnceCell<Box<T>>,
31 },
32}
33
34impl<T> SampleOrKeyInner<T>
35where
36 T: crate::Topicable,
37{
38 pub fn new_sample(sample: T) -> Self {
39 Self::Sample {
40 sample: Box::new(sample),
41 materialized_key: std::cell::OnceCell::new(),
42 }
43 }
44
45 pub fn new_key(key: T::Key) -> Self {
46 Self::Key {
47 key: Box::new(key),
48 materialized_sample: std::cell::OnceCell::new(),
49 }
50 }
51
52 pub fn key(&self) -> &T::Key {
53 match self {
54 Self::Sample {
55 sample,
56 materialized_key,
57 } => materialized_key.get_or_init(|| Box::new(sample.as_key())),
58 Self::Key { key, .. } => key,
59 }
60 }
61
62 pub fn sample(&self) -> &T {
63 match self {
64 Self::Sample { sample, .. } => sample,
65 Self::Key {
66 key,
67 materialized_sample,
68 } => materialized_sample.get_or_init(|| Box::new(T::from_key(key))),
69 }
70 }
71}
72
73/// A received sample, which is either a full payload of type
74/// [`T`](crate::Topicable) or a key-only payload carrying
75/// [`T::Key`](crate::Topicable::Key).
76///
77/// Key-only samples are produced when an instance is disposed or unregistered
78/// by a writer. [`SampleOrKey`] derefs to `T` in both cases: for key-only
79/// samples this materializes a default `T` from the key via
80/// [`Topicable::from_key`].
81///
82/// Use [`view`](SampleOrKey::view) to distinguish between the two cases without
83/// triggering materialisation.
84pub struct SampleOrKey<T>
85where
86 T: crate::Topicable,
87{
88 inner: SampleOrKeyInner<T>,
89 pub(crate) info: Info,
90}
91
92impl<T> std::clone::Clone for SampleOrKey<T>
93where
94 T: Topicable + std::clone::Clone,
95 T::Key: std::clone::Clone,
96{
97 fn clone(&self) -> Self {
98 Self {
99 inner: self.inner.clone(),
100 info: self.info,
101 }
102 }
103}
104
105impl<T> std::fmt::Debug for SampleOrKey<T>
106where
107 T: Topicable + std::fmt::Debug,
108 T::Key: std::fmt::Debug,
109{
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 let mut f = f.debug_struct("SampleOrKey");
112
113 let f = match &self.inner {
114 SampleOrKeyInner::Sample { sample, .. } => f.field("sample", sample),
115 SampleOrKeyInner::Key { key, .. } => f.field("key", key),
116 };
117
118 f.field("info", &self.info).finish()
119 }
120}
121
122impl<T> SampleOrKey<T>
123where
124 T: crate::Topicable,
125{
126 /// Create a new sample or key provided a full sample and sample info.
127 pub(crate) fn new_sample(sample: T, info: Info) -> Self {
128 let inner = SampleOrKeyInner::new_sample(sample);
129 Self { inner, info }
130 }
131
132 /// Create a new sample or key provided a key and sample info.
133 pub(crate) fn new_key(key: T::Key, info: Info) -> Self {
134 let inner = SampleOrKeyInner::new_key(key);
135 Self { inner, info }
136 }
137
138 /// Returns the metadata associated with this sample.
139 ///
140 /// # Examples
141 ///
142 /// ```
143 /// # use cyclonedds::{Domain, Participant, Topic, Reader, Writer};
144 /// # let domain = Domain::default();
145 /// # let participant = Participant::new(&domain)?;
146 /// # #[derive(
147 /// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
148 /// # )]
149 /// # struct Data {
150 /// # x: i32,
151 /// # }
152 /// # let topic = Topic::<Data>::new(&participant, "MyTopic")?;
153 /// # let reader = Reader::new(&topic)?;
154 /// # let writer = Writer::new(&topic)?;
155 /// # writer.write(&Data::default())?;
156 /// let sample = &reader.take()?[0];
157 /// let info = sample.info();
158 /// println!("source timestamp: {:?}", info.source_timestamp);
159 /// # Ok::<_, cyclonedds::Error>(())
160 /// ```
161 pub const fn info(&self) -> &Info {
162 &self.info
163 }
164
165 /// Returns a reference to the full sample payload, or `None` if this is a
166 /// key-only sample.
167 ///
168 /// # Examples
169 ///
170 /// ```
171 /// # use cyclonedds::{Domain, Participant, Topic, Reader, Writer};
172 /// # let domain = Domain::default();
173 /// # let participant = Participant::new(&domain)?;
174 /// # #[derive(
175 /// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
176 /// # )]
177 /// # struct Data {
178 /// # x: i32,
179 /// # }
180 /// # let topic = Topic::<Data>::new(&participant, "MyTopic")?;
181 /// # let reader = Reader::new(&topic)?;
182 /// # let writer = Writer::new(&topic)?;
183 /// # writer.write(&Data::default())?;
184 /// let sample = &reader.take()?[0];
185 /// if let Some(data) = sample.sample() {
186 /// println!("payload: {data:?}");
187 /// }
188 /// # Ok::<_, cyclonedds::Error>(())
189 /// ```
190 pub fn sample(&self) -> Option<&T> {
191 match &self.inner {
192 SampleOrKeyInner::Sample { sample, .. } => Some(sample),
193 SampleOrKeyInner::Key { .. } => None,
194 }
195 }
196
197 /// Consumes `self` and returns the full sample payload, or `None` if this
198 /// is a key-only sample.
199 ///
200 /// # Examples
201 ///
202 /// ```
203 /// # use cyclonedds::{Domain, Participant, Topic, Reader, Writer};
204 /// # let domain = Domain::default();
205 /// # let participant = Participant::new(&domain)?;
206 /// # #[derive(
207 /// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
208 /// # )]
209 /// # struct Data {
210 /// # x: i32,
211 /// # }
212 /// # let topic = Topic::<Data>::new(&participant, "MyTopic")?;
213 /// # let reader = Reader::new(&topic)?;
214 /// # let writer = Writer::new(&topic)?;
215 /// # writer.write(&Data::default())?;
216 /// let sample = reader.take()?.into_iter().next().unwrap();
217 /// if let Some(data) = sample.into_sample() {
218 /// println!("payload: {data:?}");
219 /// }
220 /// # Ok::<_, cyclonedds::Error>(())
221 /// ```
222 pub fn into_sample(self) -> Option<T> {
223 match self.inner {
224 SampleOrKeyInner::Sample { sample, .. } => Some(*sample),
225 SampleOrKeyInner::Key { .. } => None,
226 }
227 }
228
229 /// Returns `true` if this is a full sample.
230 ///
231 /// # Examples
232 ///
233 /// ```
234 /// # use cyclonedds::{Domain, Participant, Topic, Reader, Writer};
235 /// # let domain = Domain::default();
236 /// # let participant = Participant::new(&domain)?;
237 /// # #[derive(
238 /// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
239 /// # )]
240 /// # struct Data {
241 /// # x: i32,
242 /// # }
243 /// # let topic = Topic::<Data>::new(&participant, "MyTopic")?;
244 /// # let reader = Reader::new(&topic)?;
245 /// # let writer = Writer::new(&topic)?;
246 /// # writer.write(&Data::default())?;
247 /// let sample = reader.take()?.into_iter().next().unwrap();
248 /// assert!(sample.is_sample());
249 /// # Ok::<_, cyclonedds::Error>(())
250 /// ```
251 pub const fn is_sample(&self) -> bool {
252 matches!(self.inner, SampleOrKeyInner::Sample { .. })
253 }
254
255 /// Returns `true` if this is a full sample and `f` returns `true` for its
256 /// payload.
257 ///
258 /// # Examples
259 ///
260 /// ```
261 /// # use cyclonedds::{Domain, Participant, Topic, Reader, Writer};
262 /// # let domain = Domain::default();
263 /// # let participant = Participant::new(&domain)?;
264 /// # #[derive(
265 /// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
266 /// # )]
267 /// # struct Data {
268 /// # #[dds(key)]
269 /// # x: i32,
270 /// # }
271 /// # let topic = Topic::<Data>::new(&participant, "MyTopic")?;
272 /// # let reader = Reader::new(&topic)?;
273 /// # let writer = Writer::new(&topic)?;
274 /// # writer.write(&Data::default())?;
275 /// let sample = reader.take()?.into_iter().next().unwrap();
276 /// assert!(sample.is_sample_and(|data| data.x == 0));
277 /// # Ok::<_, cyclonedds::Error>(())
278 /// ```
279 pub fn is_sample_and(&self, f: impl FnOnce(&T) -> bool) -> bool {
280 match &self.inner {
281 SampleOrKeyInner::Sample { sample, .. } => f(sample),
282 SampleOrKeyInner::Key { .. } => false,
283 }
284 }
285
286 /// Returns a reference to the instance key, or `None` if this is a full
287 /// sample.
288 ///
289 /// # Examples
290 ///
291 /// ```
292 /// # use cyclonedds::{Domain, Participant, Topic, Reader, Writer};
293 /// # let domain = Domain::default();
294 /// # let participant = Participant::new(&domain)?;
295 /// # #[derive(
296 /// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
297 /// # )]
298 /// # struct Data {
299 /// # x: i32,
300 /// # }
301 /// # let topic = Topic::<Data>::new(&participant, "MyTopic")?;
302 /// # let reader = Reader::new(&topic)?;
303 /// # let writer = Writer::new(&topic)?;
304 /// # writer.write(&Data::default())?;
305 /// let sample = reader.take()?.into_iter().next().unwrap();
306 /// if let Some(key) = sample.key() {
307 /// println!("key-only notification: {key:?}");
308 /// }
309 /// # Ok::<_, cyclonedds::Error>(())
310 /// ```
311 pub fn key(&self) -> Option<&T::Key> {
312 match &self.inner {
313 SampleOrKeyInner::Sample { .. } => None,
314 SampleOrKeyInner::Key { key, .. } => Some(key),
315 }
316 }
317
318 /// Consumes `self` and returns the instance key, or `None` if this is a
319 /// full sample.
320 ///
321 /// # Examples
322 ///
323 /// ```
324 /// # use cyclonedds::{Domain, Participant, Topic, Reader, Writer};
325 /// # let domain = Domain::default();
326 /// # let participant = Participant::new(&domain)?;
327 /// # #[derive(
328 /// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
329 /// # )]
330 /// # struct Data {
331 /// # x: i32,
332 /// # }
333 /// # let topic = Topic::<Data>::new(&participant, "MyTopic")?;
334 /// # let reader = Reader::new(&topic)?;
335 /// # let writer = Writer::new(&topic)?;
336 /// # writer.write(&Data::default())?;
337 /// let sample = reader.take()?.into_iter().next().unwrap();
338 /// if let Some(key) = sample.into_key() {
339 /// println!("key-only notification: {key:?}");
340 /// }
341 /// # Ok::<_, cyclonedds::Error>(())
342 /// ```
343 pub fn into_key(self) -> Option<T::Key> {
344 match self.inner {
345 SampleOrKeyInner::Sample { .. } => None,
346 SampleOrKeyInner::Key { key, .. } => Some(*key),
347 }
348 }
349
350 /// Returns `true` if this is a key-only sample.
351 ///
352 /// # Examples
353 ///
354 /// ```
355 /// # use cyclonedds::{Domain, Participant, Topic, Reader, Writer};
356 /// # let domain = Domain::default();
357 /// # let participant = Participant::new(&domain)?;
358 /// # #[derive(
359 /// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
360 /// # )]
361 /// # struct Data {
362 /// # x: i32,
363 /// # }
364 /// # let topic = Topic::<Data>::new(&participant, "MyTopic")?;
365 /// # let reader = Reader::new(&topic)?;
366 /// # let writer = Writer::new(&topic)?;
367 /// # writer.write(&Data::default())?;
368 /// let sample = reader.take()?.into_iter().next().unwrap();
369 /// assert!(!sample.is_key());
370 /// # Ok::<_, cyclonedds::Error>(())
371 /// ```
372 pub const fn is_key(&self) -> bool {
373 matches!(self.inner, SampleOrKeyInner::Key { .. })
374 }
375
376 /// Returns `true` if this is a key-only sample and `f` returns `true` for
377 /// its key.
378 ///
379 /// # Examples
380 ///
381 /// ```
382 /// # use cyclonedds::{Domain, Participant, Topic, Reader, Writer};
383 /// # let domain = Domain::default();
384 /// # let participant = Participant::new(&domain)?;
385 /// # #[derive(
386 /// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
387 /// # )]
388 /// # struct Data {
389 /// # #[dds(key)]
390 /// # x: i32,
391 /// # }
392 /// # let topic = Topic::<Data>::new(&participant, "MyTopic")?;
393 /// # let reader = Reader::new(&topic)?;
394 /// # let writer = Writer::new(&topic)?;
395 /// # writer.write(&Data::default())?;
396 /// let sample = reader.take()?.into_iter().next().unwrap();
397 /// assert!(!sample.is_key_and(|key| key.x == 1));
398 /// # Ok::<_, cyclonedds::Error>(())
399 /// ```
400 pub fn is_key_and(&self, f: impl FnOnce(&T::Key) -> bool) -> bool {
401 match &self.inner {
402 SampleOrKeyInner::Sample { .. } => false,
403 SampleOrKeyInner::Key { key, .. } => f(key),
404 }
405 }
406
407 /// Returns a borrowed [`View`] of this sample for pattern matching without
408 /// triggering key or sample materialisation.
409 ///
410 /// # Examples
411 ///
412 /// ```
413 /// use cyclonedds::sample::View;
414 /// # use cyclonedds::{Domain, Participant, Topic, Reader, Writer};
415 /// # let domain = Domain::default();
416 /// # let participant = Participant::new(&domain)?;
417 /// # #[derive(
418 /// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
419 /// # )]
420 /// # struct Data {
421 /// # x: i32,
422 /// # }
423 /// # let topic = Topic::<Data>::new(&participant, "MyTopic")?;
424 /// # let reader = Reader::new(&topic)?;
425 /// # let writer = Writer::new(&topic)?;
426 /// # writer.write(&Data::default())?;
427 ///
428 /// for sample in reader.take()? {
429 /// match sample.view() {
430 /// View::Sample(data) => println!("sample: {data:?}"),
431 /// View::Key(key) => println!("key-only: {key:?}"),
432 /// }
433 /// }
434 /// # Ok::<_, cyclonedds::Error>(())
435 /// ```
436 pub fn view(&self) -> View<'_, T> {
437 match &self.inner {
438 SampleOrKeyInner::Sample { sample, .. } => View::Sample(sample.as_ref()),
439 SampleOrKeyInner::Key { key, .. } => View::Key(key.as_ref()),
440 }
441 }
442}
443
444impl<T> std::ops::Deref for SampleOrKey<T>
445where
446 T: crate::Topicable,
447{
448 type Target = T;
449
450 fn deref(&self) -> &Self::Target {
451 self.inner.sample()
452 }
453}
454
455/// A borrowed view into a [`SampleOrKey`] for pattern matching.
456///
457/// Obtained via [`SampleOrKey::view`]. Distinguishes between a full sample and
458/// a key-only sample without consuming the [`SampleOrKey`] and without
459/// implicitly materializing the other half.
460///
461/// # Examples
462///
463/// ```
464/// use cyclonedds::sample::View;
465/// # use cyclonedds::{Reader, Topic};
466/// # #[derive(
467/// # cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Clone, Debug, Default,
468/// # )]
469/// # struct Data {
470/// # x: i32,
471/// # }
472/// # let domain = cyclonedds::Domain::default();
473/// # let participant = cyclonedds::Participant::new(&domain)?;
474/// # let topic = Topic::<Data>::new(&participant, "MyData")?;
475/// # let reader = Reader::<Data>::new(&topic)?;
476///
477/// for sample in reader.read()? {
478/// match sample.view() {
479/// View::Sample(sample) => println!("got sample: {sample:?}"),
480/// View::Key(key) => println!("got key-only: {key:?}"),
481/// }
482/// }
483/// # Ok::<_, cyclonedds::Error>(())
484/// ```
485pub enum View<'sample, T>
486where
487 T: Topicable,
488{
489 /// A full data sample.
490 Sample(&'sample T),
491 /// A key-only notification, produced when an instance is disposed or
492 /// unregistered.
493 Key(&'sample T::Key),
494}
495
496impl<T> std::fmt::Debug for View<'_, T>
497where
498 T: Topicable,
499 T::Key: std::fmt::Debug,
500{
501 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
502 match self {
503 Self::Sample(sample) => f.debug_tuple("Sample").field(sample).finish(),
504 Self::Key(key) => f.debug_tuple("Key").field(key).finish(),
505 }
506 }
507}
508
509impl<T> std::cmp::PartialEq for View<'_, T>
510where
511 T: Topicable + std::cmp::PartialEq,
512 T::Key: std::cmp::PartialEq,
513{
514 fn eq(&self, other: &Self) -> bool {
515 match (self, other) {
516 (View::Sample(lhs), View::Sample(rhs)) => lhs == rhs,
517 (View::Key(lhs), View::Key(rhs)) => lhs == rhs,
518 _ => false,
519 }
520 }
521}
522
523/// Metadata associated with a received sample.
524///
525/// Attached to every [`SampleOrKey`] and carries the metadata related to the
526/// transmission of the sample.
527///
528/// <div class="warning">
529///
530/// The `valid_data` flag from the DDS specification is not present here as it
531/// is encoded structurally in the type system via [`SampleOrKey`]. A
532/// [`View::Sample`] variant guarantees valid data and a [`View::Key`] variant
533/// guarantees the absence of it.
534///
535/// </div>
536#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
537pub struct Info {
538 /// [`sample`](crate::state::sample), [`view`](crate::state::view), and
539 /// [`instance`](crate::state::instance) state flags at the time of receipt.
540 pub state: crate::State,
541 /// Timestamp at which the sample was written by the publisher.
542 pub source_timestamp: crate::Time,
543 /// Handle identifying the instance this sample belongs to.
544 pub instance_handle: crate::entity::InstanceHandle,
545 /// Handle identifying the writer that published this sample.
546 pub publication_handle: crate::entity::InstanceHandle,
547 /// Number of times the instance was disposed before this sample was
548 /// received.
549 pub disposed_generation_count: u32,
550 /// Number of times the instance transitioned to the no-writers state before
551 /// this sample was received.
552 pub no_writers_generation_count: u32,
553 /// Position of this sample relative to other samples for the same instance
554 /// in the current read or take call.
555 pub sample_rank: u32,
556 /// Difference in generation count between this sample and the most recent
557 /// sample for the same instance in the current read or take call.
558 pub generation_rank: u32,
559 /// Difference in generation count between this sample and the most recent
560 /// sample for the same instance in the reader's cache.
561 pub absolute_generation_rank: u32,
562}
563
564impl From<&cyclonedds_sys::dds_sample_info> for Info {
565 fn from(sample_info: &cyclonedds_sys::dds_sample_info) -> Self {
566 #[allow(clippy::cast_sign_loss, clippy::unnecessary_cast)]
567 let state = crate::State::from_bits_truncate(sample_info.sample_state as u32)
568 | crate::State::from_bits_truncate(sample_info.view_state as u32)
569 | crate::State::from_bits_truncate(sample_info.instance_state as u32);
570 let instance_handle = crate::entity::InstanceHandle {
571 inner: sample_info.instance_handle,
572 };
573 let publication_handle = crate::entity::InstanceHandle {
574 inner: sample_info.publication_handle,
575 };
576 let source_timestamp = crate::Time::from_nanos(sample_info.source_timestamp);
577
578 let disposed_generation_count = sample_info.disposed_generation_count;
579 let no_writers_generation_count = sample_info.no_writers_generation_count;
580 let sample_rank = sample_info.sample_rank;
581 let generation_rank = sample_info.generation_rank;
582 let absolute_generation_rank = sample_info.absolute_generation_rank;
583
584 Self {
585 state,
586 source_timestamp,
587 instance_handle,
588 publication_handle,
589 disposed_generation_count,
590 no_writers_generation_count,
591 sample_rank,
592 generation_rank,
593 absolute_generation_rank,
594 }
595 }
596}
597
598#[cfg(test)]
599mod tests {
600 use super::*;
601
602 fn is_sample_callback(sample: &crate::tests::topic::Data) -> bool {
603 sample.x.is_multiple_of(2)
604 }
605
606 // NOTE: the general interface expects the key to be passed by ref (even if the
607 // key is trivially copyable and small).
608 #[allow(clippy::trivially_copy_pass_by_ref)]
609 fn is_key_callback(key: &(u32, i32)) -> bool {
610 key.0.is_multiple_of(2)
611 }
612
613 #[test]
614 fn test_sample_or_key_sample_ref() {
615 let info = Info {
616 state: crate::State::empty(),
617 source_timestamp: crate::Time::default(),
618 instance_handle: crate::entity::InstanceHandle { inner: 0 },
619 publication_handle: crate::entity::InstanceHandle { inner: 0 },
620 disposed_generation_count: Default::default(),
621 no_writers_generation_count: Default::default(),
622 sample_rank: Default::default(),
623 generation_rank: Default::default(),
624 absolute_generation_rank: Default::default(),
625 };
626 let data = crate::tests::topic::Data {
627 x: 10,
628 y: 11,
629 message: "sample".to_string(),
630 };
631 let sample = SampleOrKey::new_sample(data.clone(), info);
632
633 assert!(sample.is_sample());
634 assert!(sample.is_sample_and(is_sample_callback));
635 assert!(!sample.is_key_and(is_key_callback));
636 assert!(!sample.is_key());
637 assert_eq!(sample.info(), &info);
638 assert_eq!(*sample, data);
639 assert_eq!(sample.sample().unwrap(), &data);
640 assert_eq!(sample.key(), None);
641 assert_eq!(sample.clone().into_sample().unwrap(), data);
642 assert_eq!(sample.clone().into_key(), None);
643 }
644
645 #[test]
646 fn test_sample_or_key_key_ref() {
647 let info = Info {
648 state: crate::State::empty(),
649 source_timestamp: crate::Time::default(),
650 instance_handle: crate::entity::InstanceHandle { inner: 0 },
651 publication_handle: crate::entity::InstanceHandle { inner: 0 },
652 disposed_generation_count: Default::default(),
653 no_writers_generation_count: Default::default(),
654 sample_rank: Default::default(),
655 generation_rank: Default::default(),
656 absolute_generation_rank: Default::default(),
657 };
658 let data = crate::tests::topic::Data {
659 x: 10,
660 y: 11,
661 message: String::new(),
662 };
663 let key = data.as_key();
664 let sample = SampleOrKey::<crate::tests::topic::Data>::new_key(key, info);
665
666 assert!(sample.is_key());
667 assert!(sample.is_key_and(is_key_callback));
668 assert!(!sample.is_sample_and(is_sample_callback));
669 assert!(!sample.is_sample());
670 assert_eq!(sample.info(), &info);
671 assert_eq!(*sample, data);
672 assert_eq!(sample.key().unwrap(), &key);
673 assert_eq!(sample.sample(), None);
674 assert_eq!(sample.clone().into_key().unwrap(), key);
675 assert_eq!(sample.clone().into_sample(), None);
676 }
677
678 #[test]
679 fn test_sample_or_key_view() {
680 let info = Info {
681 state: crate::State::empty(),
682 source_timestamp: crate::Time::default(),
683 instance_handle: crate::entity::InstanceHandle { inner: 0 },
684 publication_handle: crate::entity::InstanceHandle { inner: 0 },
685 disposed_generation_count: Default::default(),
686 no_writers_generation_count: Default::default(),
687 sample_rank: Default::default(),
688 generation_rank: Default::default(),
689 absolute_generation_rank: Default::default(),
690 };
691 let sample_data = crate::tests::topic::Data {
692 x: 10,
693 y: 11,
694 message: "sample".to_string(),
695 };
696 let sample_key = sample_data.as_key();
697
698 let sample =
699 SampleOrKey::<crate::tests::topic::Data>::new_sample(sample_data.clone(), info);
700 let key = SampleOrKey::<crate::tests::topic::Data>::new_key(sample_key, info);
701
702 let sample_display = format!("{sample:?}");
703 let key_display = format!("{key:?}");
704 assert!(sample_display.contains(&format!("{sample_data:?}")));
705 assert!(key_display.contains(&format!("{sample_key:?}")));
706 assert!(sample_display.contains(&format!("{sample_data:?}")));
707 assert!(sample_display.contains(&format!("{info:?}")));
708 assert!(key_display.contains(&format!("{sample_key:?}")));
709 assert!(key_display.contains(&format!("{info:?}")));
710
711 let view_sample_display = format!("{:?}", sample.view());
712 let view_key_display = format!("{:?}", key.view());
713 assert!(view_sample_display.contains(&format!("{sample_data:?}")));
714 assert!(view_key_display.contains(&format!("{sample_key:?}")));
715 assert!(view_sample_display.contains(&format!("{sample_data:?}")));
716
717 assert!(sample.view() != key.view());
718 assert_eq!(sample.view(), View::Sample(&sample_data));
719 assert_eq!(key.view(), View::Key(&sample_key));
720 }
721}