Skip to main content

QueryCondition

Struct QueryCondition 

Source
pub struct QueryCondition<'domain, 'participant, 'topic, 'reader, T, F>
where T: Topicable, F: Fn(&T) -> bool,
{ /* private fields */ }
Expand description

A filter on a Reader that restricts samples by their State and a predicate.

A QueryCondition extends ReadCondition with a user-supplied predicate F that is applied to each sample’s payload. Only samples that both match the state mask and satisfy the predicate are returned by reads and trigger waitset wakeups.

§Predicate requirements

The predicate closure provided to the QueryCondition must be zero-sized.

This restriction comes from how the callback is integrated with the underlying C API. For ergonomics, the closure is reconstructed inside a wrapper that converts raw C types into Rust types before invoking it. That reconstruction depends only on the closure’s type, so it cannot rely on any captured state.

In practice, this means the callback must be either:

  • a function item, which is always zero-sized, or
  • a closure that does not capture any variables from its environment

The following example will fail to compile because the closure captures x, making it non-zero-sized:

use cyclonedds as dds;
use dds::state;

struct Data {
    x: i32,
}
fn create_your_reader() -> dds::Reader<'static, 'static, 'static, Data> {
    unimplemented!()
}
let reader: dds::Reader<Data> = create_your_reader();
let x = 10;
let result = dds::QueryCondition::new(
    &reader,
    state::sample::Any | state::instance::Any | state::view::Any,
    // Error: closure captures `x`, so it is not zero-sized.
    |sample| sample.x < x,
)?;

Instead, use a function item or a non-capturing closure, for example:

|sample| sample.x < 10

The compiler will emit an error similar to:

error[E0080]: evaluation panicked: the provided callback is not zero-sized
  = note: closures that capture values from their environment are not zero-sized
  = help: ensure the callback is either:
          - a function item, e.g. `fn my_callback() {}`
          - a closure that does not capture any external state

This is enforced via an internal compile-time assertion assert!(size_of::<F>() == 0) but note that the associated compiler output can be quite lengthy.

Click to see a sample of the full compiler output
error[E0080]: evaluation panicked: the provided callback is not zero-sized
                = note: closures that capture values from their environment are not zero-sized
                = help: ensure the callback is either:
                        - a function item, e.g. `fn my_callback() {}`
                        - a closure that does not capture any external state
--> cyclonedds/src/internal/ffi.rs
 |
 |       const IS_PROVIDED_CALLBACK_ZERO_SIZED: () = assert!(
 |  _________________________________________________^
 | |         size_of::<F>() == 0,
 | |         "\
 | | the provided callback is not zero-sized
   |
 | | "
 | | );
 | |_^ evaluation of `<QueryCondition as Filter>::IS_PROVIDED_CALLBACK_ZERO_SIZED` failed here

note: erroneous constant encountered
--> cyclonedds/src/query_condition.rs:84:17
 |
 |         Self::IS_PROVIDED_CALLBACK_ZERO_SIZED;
 |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

...

note: erroneous constant encountered
--> cyclonedds/src/internal/ffi.rs
 |
 |     Callback::IS_PROVIDED_CALLBACK_ZERO_SIZED;
 |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Implementations§

Source§

impl<'d, 'p, 't, 'r, T, F> QueryCondition<'d, 'p, 't, 'r, T, F>
where T: Topicable + UnwindSafe + RefUnwindSafe, F: Fn(&T) -> bool,

Source

pub fn new(reader: &'r Reader<'d, 'p, 't, T>, mask: State, _: F) -> Result<Self>

Creates a new QueryCondition on reader that matches samples whose state satisfies mask and whose payload satisfies the predicate F.

The predicate is passed by value but must be zero-sized. Non-capturing closures and function pointers satisfy this requirement. The UnwindSafe bound is required because the predicate is called across the FFI boundary from within Cyclone DDS.

§Errors

Returns an Error if F is not zero-sized or if the query condition fails to create.

§Examples
use cyclonedds::{QueryCondition, state};

let topic = Topic::<Data>::new(&participant, "MyTopic")?;
let reader = Reader::new(&topic)?;
let condition =
    QueryCondition::new(&reader, state::sample::Fresh, |sample: &Data| sample.x > 10)?;
Source

pub fn mask(&self) -> Result<State>

Returns the state mask this condition was created with.

§Errors

Returns an Error if the mask returned by the query condition is invalid.

§Examples
use cyclonedds::{QueryCondition, state};

let topic = Topic::<Data>::new(&participant, "MyTopic")?;
let reader = Reader::new(&topic)?;
let condition = QueryCondition::new(&reader, state::sample::Fresh, |_: &Data| true)?;
assert_eq!(condition.mask()?, state::sample::Fresh);
Source

pub fn triggered(&self) -> Result<bool>

Returns true if this condition is currently triggered.

A condition is triggered when samples matching its mask are available in the reader cache.

§Errors

returns an Error if the query condition fails to read the trigger state.

§Examples
use cyclonedds::{QueryCondition, state};

let topic = Topic::<Data>::new(&participant, "MyTopic")?;
let reader = Reader::new(&topic)?;
let writer = Writer::new(&topic)?;

let condition = QueryCondition::new(
    &reader,
    state::sample::Fresh | state::view::Any | state::instance::Any,
    |sample: &Data| sample.x == 4 && sample.y == 0,
)?;
writer.write(&Data { x: 4, y: 0 })?;
assert!(condition.triggered()?);
Source

pub fn take(&self) -> Result<Vec<SampleOrKey<T>>>
where T: Clone,

Removes and returns all samples matching this condition’s mask and predicate from the reader cache.

§Errors

Returns an Error if the query condition fails to take samples.

§Examples
use cyclonedds::{QueryCondition, state};

let topic = Topic::<Data>::new(&participant, "MyTopic")?;
let reader = Reader::new(&topic)?;
let writer = Writer::new(&topic)?;

let condition = QueryCondition::new(
    &reader,
    state::sample::Any | state::view::Any | state::instance::Any,
    |sample: &Data| true,
)?;

writer.write(&Data { x: 1, y: 0 })?;
writer.write(&Data { x: 100, y: 0 })?;

// Attempt a normal read.
assert_eq!(reader.peek()?.len(), 2);

// Both samples should match.
let samples = condition.take()?;
assert_eq!(samples.len(), 2);

// Samples should be removed from the cache.
assert_eq!(condition.take()?.len(), 0);
Source

pub fn read(&self) -> Result<Vec<SampleOrKey<T>>>
where T: Clone,

Returns all samples matching this condition’s mask and predicate without marking them as read or removing them from the cache.

§Errors

Returns an Error if the query condition fails to peek samples.

§Examples
use cyclonedds::{QueryCondition, state};

let topic = Topic::<Data>::new(&participant, "MyTopic")?;
let reader = Reader::new(&topic)?;
let writer = Writer::new(&topic)?;

let condition = QueryCondition::new(
    &reader,
    state::sample::Any | state::view::Any | state::instance::Any,
    |sample: &Data| true,
)?;

writer.write(&Data { x: 1, y: 0 })?;
writer.write(&Data { x: 100, y: 0 })?;

// Attempt a normal read.
assert_eq!(reader.read()?.len(), 2);

// Both samples should match.
let samples = condition.read()?;
assert_eq!(samples.len(), 2);

// Samples remain in the cache.
assert_eq!(condition.read()?.len(), 2);
Source

pub fn peek(&self) -> Result<Vec<SampleOrKey<T>>>
where T: Clone,

Returns all samples matching this condition’s mask and predicate without marking them as read or removing them from the cache.

§Errors

Returns an Error if the query condition fails to peek samples.

§Examples
use cyclonedds::{QueryCondition, state};

let topic = Topic::<Data>::new(&participant, "MyTopic")?;
let reader = Reader::new(&topic)?;
let writer = Writer::new(&topic)?;

let condition = QueryCondition::new(
    &reader,
    state::sample::Any | state::view::Any | state::instance::Any,
    |sample: &Data| true,
)?;

writer.write(&Data { x: 1, y: 0 })?;
writer.write(&Data { x: 100, y: 0 })?;

// Attempt a normal peek.
assert_eq!(reader.peek()?.len(), 2);

// Both samples should match.
let samples = condition.peek()?;
assert_eq!(samples.len(), 2);

// Samples remain in the cache.
assert_eq!(condition.peek()?.len(), 2);

Trait Implementations§

Source§

impl<T, F> Debug for QueryCondition<'_, '_, '_, '_, T, F>
where T: Topicable, F: Fn(&T) -> bool,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T, F> Drop for QueryCondition<'_, '_, '_, '_, T, F>
where T: Topicable, F: Fn(&T) -> bool,

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<T: Topicable, F: Fn(&T) -> bool> Entity for QueryCondition<'_, '_, '_, '_, T, F>

Source§

fn id(&self) -> EntityId

Returns the EntityId of this entity. Read more
Source§

fn instance_handle(&self) -> Result<InstanceHandle>

Returns the InstanceHandle of this entity. Read more
Source§

fn status_changes(&self) -> Result<Status>

Returns the set of status flags that have changed since they were last read or taken. Read more
Source§

fn take_status(&self, mask: Option<Status>) -> Result<Status>

Takes and clears the status flags matching mask, or all flags if mask is None. Read more
Source§

fn read_status(&self, mask: Option<Status>) -> Result<Status>

Reads the status flags matching mask without clearing them, or all flags if mask is None. Read more
Source§

fn status_mask(&self) -> Result<Status>

Returns the status mask enabled on the entity. Read more
Source§

fn set_status_mask(&self, mask: Status) -> Result<()>

Sets and enables a status mask on the entity. Read more

Auto Trait Implementations§

§

impl<'domain, 'participant, 'topic, 'reader, T, F> Freeze for QueryCondition<'domain, 'participant, 'topic, 'reader, T, F>

§

impl<'domain, 'participant, 'topic, 'reader, T, F> RefUnwindSafe for QueryCondition<'domain, 'participant, 'topic, 'reader, T, F>

§

impl<'domain, 'participant, 'topic, 'reader, T, F> Send for QueryCondition<'domain, 'participant, 'topic, 'reader, T, F>
where F: Send, T: Sync,

§

impl<'domain, 'participant, 'topic, 'reader, T, F> Sync for QueryCondition<'domain, 'participant, 'topic, 'reader, T, F>
where F: Sync, T: Sync,

§

impl<'domain, 'participant, 'topic, 'reader, T, F> Unpin for QueryCondition<'domain, 'participant, 'topic, 'reader, T, F>
where F: Unpin,

§

impl<'domain, 'participant, 'topic, 'reader, T, F> UnsafeUnpin for QueryCondition<'domain, 'participant, 'topic, 'reader, T, F>

§

impl<'domain, 'participant, 'topic, 'reader, T, F> UnwindSafe for QueryCondition<'domain, 'participant, 'topic, 'reader, T, F>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.