Skip to content

Commit

Permalink
Merge pull request #442 from pact-foundation/feat/add-async-message-iter
Browse files Browse the repository at this point in the history
feat(ffi): add async message iterator
  • Loading branch information
rholshausen authored Jun 16, 2024
2 parents 37bc38f + 598377d commit 3900dfa
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 1 deletion.
28 changes: 27 additions & 1 deletion rust/pact_ffi/src/mock_server/handles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ use crate::mock_server::bodies::{
get_content_type_hint,
part_body_replace_marker
};
use crate::models::iterators::{PactMessageIterator, PactSyncHttpIterator, PactSyncMessageIterator};
use crate::models::iterators::{PactAsyncMessageIterator, PactMessageIterator, PactSyncHttpIterator, PactSyncMessageIterator};
use crate::ptr;

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -2487,6 +2487,32 @@ ffi_fn! {
}
}

ffi_fn! {
/// Get an iterator over all the asynchronous messages of the Pact.
/// The returned iterator needs to be freed with `pactffi_pact_async_message_iter_delete`.
///
/// # Safety
///
/// The iterator contains a copy of the Pact, so it is always safe to use.
///
/// # Error Handling
///
/// On failure, this function will return a NULL pointer.
///
/// This function may fail if any of the Rust strings contain embedded
/// null ('\0') bytes.
fn pactffi_pact_handle_get_async_message_iter(pact: PactHandle) -> *mut PactAsyncMessageIterator {
let v4_pact = pact.with_pact(&|_, inner| {
// Ok to unwrap this, as any non-v4 pact will be upgraded
inner.pact.as_v4_pact().unwrap()
}).ok_or_else(|| anyhow!("Pact handle is not valid"))?;
let iter = PactAsyncMessageIterator::new(v4_pact);
ptr::raw_to(iter)
} {
std::ptr::null_mut()
}
}

ffi_fn! {
/// Get an iterator over all the synchronous request/response messages of the Pact.
/// The returned iterator needs to be freed with `pactffi_pact_sync_message_iter_delete`.
Expand Down
69 changes: 69 additions & 0 deletions rust/pact_ffi/src/models/iterators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use tracing::trace;
use pact_models::message::Message;
use pact_models::message_pact::MessagePact;
use pact_models::v4::pact::V4Pact;
use pact_models::v4::async_message::AsynchronousMessage;
use pact_models::v4::sync_message::SynchronousMessage;
use pact_models::v4::synch_http::SynchronousHttp;
use pact_models::v4::V4InteractionType;
Expand Down Expand Up @@ -77,6 +78,74 @@ ffi_fn! {
}
}

/// An iterator over asynchronous messages in a V4 pact.
#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub struct PactAsyncMessageIterator {
current: usize,
messages: Vec<AsynchronousMessage>
}

impl PactAsyncMessageIterator {
/// Create a new iterator over all asynchronous messages in the pact
pub fn new(pact: V4Pact) -> Self {
PactAsyncMessageIterator {
current: 0,
messages: pact.filter_interactions(V4InteractionType::Asynchronous_Messages)
.iter()
.map(|i| i.as_v4_async_message().unwrap())
.collect()
}
}

/// Get the next message in the pact.
fn next(&mut self) -> Option<&mut AsynchronousMessage> {
let idx = self.current;
self.current += 1;
self.messages.get_mut(idx)
}
}

ffi_fn! {
/// Get the next asynchronous from the V4 pact. As the messages returned are
/// owned by the iterator, they do not need to be deleted but will be
/// cleaned up when the iterator is deleted.
///
/// Will return a NULL pointer when the iterator has advanced past the end
/// of the list.
///
/// # Safety
///
/// This function is safe.
///
/// Deleting a message returned by the iterator can lead to undefined
/// behaviour.
///
/// # Error Handling
///
/// This function will return a NULL pointer if passed a NULL pointer or if
/// an error occurs.
fn pactffi_pact_async_message_iter_next(iter: *mut PactAsyncMessageIterator) -> *mut AsynchronousMessage {
let iter = as_mut!(iter);
match iter.next() {
Some(message) => message as *mut AsynchronousMessage,
None => {
trace!("iter past the end of messages");
std::ptr::null_mut()
}
}
} {
std::ptr::null_mut()
}
}

ffi_fn! {
/// Free the iterator when you're done using it.
fn pactffi_pact_async_message_iter_delete(iter: *mut PactAsyncMessageIterator) {
ptr::drop_raw(iter);
}
}

/// An iterator over synchronous request/response messages in a V4 pact.
#[derive(Debug)]
#[allow(missing_copy_implementations)]
Expand Down

0 comments on commit 3900dfa

Please sign in to comment.