1#![cfg_attr(docsrs, feature(doc_cfg))]
45
46#[cfg(feature = "archive")]
47#[cfg_attr(docsrs, doc(cfg(feature = "archive")))]
48pub mod archive;
49
50#[cxx::bridge(namespace = "aeron_rs")]
51pub mod ffi {
52 unsafe extern "C++" {
53 include!("shim.h");
54
55 type ContextWrapper;
56 type AeronWrapper;
57 type PublicationWrapper;
58 type ExclusivePublicationWrapper;
59 type SubscriptionWrapper;
60 type MediaDriverWrapper;
61 type CountersReaderWrapper;
62
63 fn create_context() -> UniquePtr<ContextWrapper>;
64 fn create_aeron(context: UniquePtr<ContextWrapper>) -> Result<UniquePtr<AeronWrapper>>;
65 fn create_media_driver() -> Result<UniquePtr<MediaDriverWrapper>>;
66
67 fn start(self: Pin<&mut AeronWrapper>);
68 fn isClosed(self: &AeronWrapper) -> bool;
69 fn addPublication(
70 self: Pin<&mut AeronWrapper>,
71 channel: &str,
72 stream_id: i32,
73 ) -> Result<UniquePtr<PublicationWrapper>>;
74 fn addExclusivePublication(
75 self: Pin<&mut AeronWrapper>,
76 channel: &str,
77 stream_id: i32,
78 ) -> Result<UniquePtr<ExclusivePublicationWrapper>>;
79 fn addSubscription(
80 self: Pin<&mut AeronWrapper>,
81 channel: &str,
82 stream_id: i32,
83 ) -> Result<UniquePtr<SubscriptionWrapper>>;
84 fn countersReader(self: &AeronWrapper) -> UniquePtr<CountersReaderWrapper>;
85
86 fn start(self: Pin<&mut MediaDriverWrapper>) -> Result<()>;
87
88 fn setDir(self: Pin<&mut MediaDriverWrapper>, dir: &str) -> Result<()>;
89 fn setDirDeleteOnStart(self: Pin<&mut MediaDriverWrapper>, value: bool) -> Result<()>;
90 fn setDirDeleteOnShutdown(self: Pin<&mut MediaDriverWrapper>, value: bool) -> Result<()>;
91 fn setThreadingMode(self: Pin<&mut MediaDriverWrapper>, mode: i32) -> Result<()>;
92 fn setConductorIdleStrategy(self: Pin<&mut MediaDriverWrapper>, name: &str) -> Result<()>;
93 fn setSenderIdleStrategy(self: Pin<&mut MediaDriverWrapper>, name: &str) -> Result<()>;
94 fn setReceiverIdleStrategy(self: Pin<&mut MediaDriverWrapper>, name: &str) -> Result<()>;
95 fn setTermBufferLength(self: Pin<&mut MediaDriverWrapper>, value: usize) -> Result<()>;
96 fn setIpcTermBufferLength(self: Pin<&mut MediaDriverWrapper>, value: usize) -> Result<()>;
97 fn setMtuLength(self: Pin<&mut MediaDriverWrapper>, value: usize) -> Result<()>;
98 fn setIpcMtuLength(self: Pin<&mut MediaDriverWrapper>, value: usize) -> Result<()>;
99 fn setSocketSoRcvbuf(self: Pin<&mut MediaDriverWrapper>, value: usize) -> Result<()>;
100 fn setSocketSoSndbuf(self: Pin<&mut MediaDriverWrapper>, value: usize) -> Result<()>;
101 fn setPrintConfiguration(self: Pin<&mut MediaDriverWrapper>, value: bool) -> Result<()>;
102 fn setConductorCpuAffinity(self: Pin<&mut MediaDriverWrapper>, cpu_id: i32) -> Result<()>;
103 fn setSenderCpuAffinity(self: Pin<&mut MediaDriverWrapper>, cpu_id: i32) -> Result<()>;
104 fn setReceiverCpuAffinity(self: Pin<&mut MediaDriverWrapper>, cpu_id: i32) -> Result<()>;
105
106 fn offer(self: Pin<&mut PublicationWrapper>, buffer: &[u8]) -> i64;
107 fn tryClaim(self: Pin<&mut PublicationWrapper>, length: usize, handler_id: usize) -> i64;
108 fn isConnected(self: &PublicationWrapper) -> bool;
109 fn sessionId(self: &PublicationWrapper) -> i32;
110
111 fn offer(self: Pin<&mut ExclusivePublicationWrapper>, buffer: &[u8]) -> i64;
112 fn tryClaim(
113 self: Pin<&mut ExclusivePublicationWrapper>,
114 length: usize,
115 handler_id: usize,
116 ) -> i64;
117 fn isConnected(self: &ExclusivePublicationWrapper) -> bool;
118
119 fn poll(self: Pin<&mut SubscriptionWrapper>, fragment_limit: i32, handler_id: usize)
120 -> i32;
121 fn pollAssembled(
122 self: Pin<&mut SubscriptionWrapper>,
123 fragment_limit: i32,
124 handler_id: usize,
125 ) -> i32;
126 fn controlledPollAssembled(
127 self: Pin<&mut SubscriptionWrapper>,
128 fragment_limit: i32,
129 handler_id: usize,
130 ) -> i32;
131 fn isConnected(self: &SubscriptionWrapper) -> bool;
132 fn imageCount(self: &SubscriptionWrapper) -> i32;
133 fn imageByIndex(
134 self: Pin<&mut SubscriptionWrapper>,
135 index: usize,
136 ) -> Result<UniquePtr<ImageWrapper>>;
137 fn imageBySessionId(
138 self: Pin<&mut SubscriptionWrapper>,
139 session_id: i32,
140 ) -> Result<UniquePtr<ImageWrapper>>;
141
142 type ImageWrapper;
143 fn sessionId(self: &ImageWrapper) -> i32;
144 fn correlationId(self: &ImageWrapper) -> i64;
145 fn joinPosition(self: &ImageWrapper) -> i64;
146 fn sourceIdentity(self: &ImageWrapper) -> String;
147 fn position(self: &ImageWrapper) -> i64;
148 fn setPosition(self: Pin<&mut ImageWrapper>, new_position: i64);
149 fn isClosed(self: &ImageWrapper) -> bool;
150 fn isEndOfStream(self: &ImageWrapper) -> bool;
151 fn endOfStreamPosition(self: &ImageWrapper) -> i64;
152 fn poll(self: Pin<&mut ImageWrapper>, fragment_limit: i32, handler_id: usize) -> i32;
153 fn controlledPollAssembled(
154 self: Pin<&mut ImageWrapper>,
155 fragment_limit: i32,
156 handler_id: usize,
157 ) -> i32;
158
159 fn maxCounterId(self: &CountersReaderWrapper) -> i32;
160 fn getCounterValue(self: &CountersReaderWrapper, id: i32) -> i64;
161 fn getCounterState(self: &CountersReaderWrapper, id: i32) -> i32;
162 fn getCounterTypeId(self: &CountersReaderWrapper, id: i32) -> i32;
163 fn getCounterLabel(self: &CountersReaderWrapper, id: i32) -> String;
164 fn forEach(self: &CountersReaderWrapper, handler_id: usize);
165 }
166
167 extern "Rust" {
168 fn handle_fragment(handler_id: usize, buffer: &[u8]);
169 fn handle_controlled_fragment(handler_id: usize, buffer: &[u8]) -> i32;
170 fn handle_claim(handler_id: usize, buffer: &mut [u8]) -> bool;
171 fn handle_counters_metadata(
172 handler_id: usize,
173 counter_id: i32,
174 type_id: i32,
175 key: &[u8],
176 label: String,
177 );
178 }
179}
180
181pub struct AeronClient {
186 inner: cxx::UniquePtr<ffi::AeronWrapper>,
187}
188
189impl AeronClient {
190 pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
192 let ctx = ffi::create_context();
193 let aeron = ffi::create_aeron(ctx)?;
194
195 Ok(Self { inner: aeron })
196 }
197
198 pub fn start(&mut self) {
200 self.inner.pin_mut().start();
201 }
202
203 pub fn is_closed(&self) -> bool {
205 self.inner.isClosed()
206 }
207
208 pub fn add_publication(
211 &mut self,
212 channel: &str,
213 stream_id: i32,
214 ) -> Result<Publication, Box<dyn std::error::Error>> {
215 let pub_inner = self.inner.pin_mut().addPublication(channel, stream_id)?;
216 Ok(Publication { inner: pub_inner })
217 }
218
219 pub fn add_exclusive_publication(
222 &mut self,
223 channel: &str,
224 stream_id: i32,
225 ) -> Result<ExclusivePublication, Box<dyn std::error::Error>> {
226 let pub_inner = self
227 .inner
228 .pin_mut()
229 .addExclusivePublication(channel, stream_id)?;
230 Ok(ExclusivePublication { inner: pub_inner })
231 }
232
233 pub fn add_subscription(
235 &mut self,
236 channel: &str,
237 stream_id: i32,
238 ) -> Result<Subscription, Box<dyn std::error::Error>> {
239 let sub_inner = self.inner.pin_mut().addSubscription(channel, stream_id)?;
240 Ok(Subscription { inner: sub_inner })
241 }
242
243 pub fn counters_reader(&self) -> CountersReader {
245 CountersReader {
246 inner: self.inner.countersReader(),
247 }
248 }
249}
250
251pub struct Publication {
255 inner: cxx::UniquePtr<ffi::PublicationWrapper>,
256}
257
258impl Publication {
259 pub fn offer(&mut self, buffer: &[u8]) -> i64 {
262 self.inner.pin_mut().offer(buffer)
263 }
264
265 pub fn try_claim<F>(&mut self, length: usize, mut handler: F) -> i64
269 where
270 F: FnMut(&mut [u8]) -> bool,
271 {
272 let handler_id = &handler as *const _ as usize;
273 let mut_ptr: *mut (dyn FnMut(&mut [u8]) -> bool + 'static) = unsafe {
274 std::mem::transmute::<
275 *mut dyn FnMut(&mut [u8]) -> bool,
276 *mut (dyn FnMut(&mut [u8]) -> bool + 'static),
277 >(&mut handler as *mut dyn FnMut(&mut [u8]) -> bool)
278 };
279
280 CLAIM_HANDLERS.with(|handlers| {
281 handlers.borrow_mut().insert(handler_id, mut_ptr);
282 });
283
284 let result = self.inner.pin_mut().tryClaim(length, handler_id);
285
286 CLAIM_HANDLERS.with(|handlers| {
287 handlers.borrow_mut().remove(&handler_id);
288 });
289
290 result
291 }
292
293 pub fn is_connected(&self) -> bool {
295 self.inner.isConnected()
296 }
297
298 pub fn session_id(&self) -> i32 {
300 self.inner.sessionId()
301 }
302}
303
304pub struct ExclusivePublication {
306 inner: cxx::UniquePtr<ffi::ExclusivePublicationWrapper>,
307}
308
309impl ExclusivePublication {
310 pub fn offer(&mut self, buffer: &[u8]) -> i64 {
313 self.inner.pin_mut().offer(buffer)
314 }
315
316 pub fn try_claim<F>(&mut self, length: usize, mut handler: F) -> i64
320 where
321 F: FnMut(&mut [u8]) -> bool,
322 {
323 let handler_id = &handler as *const _ as usize;
324 let mut_ptr: *mut (dyn FnMut(&mut [u8]) -> bool + 'static) = unsafe {
325 std::mem::transmute::<
326 *mut dyn FnMut(&mut [u8]) -> bool,
327 *mut (dyn FnMut(&mut [u8]) -> bool + 'static),
328 >(&mut handler as *mut dyn FnMut(&mut [u8]) -> bool)
329 };
330
331 CLAIM_HANDLERS.with(|handlers| {
332 handlers.borrow_mut().insert(handler_id, mut_ptr);
333 });
334
335 let result = self.inner.pin_mut().tryClaim(length, handler_id);
336
337 CLAIM_HANDLERS.with(|handlers| {
338 handlers.borrow_mut().remove(&handler_id);
339 });
340
341 result
342 }
343
344 pub fn is_connected(&self) -> bool {
346 self.inner.isConnected()
347 }
348}
349
350use std::cell::RefCell;
351use std::collections::HashMap;
352
353#[repr(i32)]
356#[derive(Debug, Clone, Copy, PartialEq, Eq)]
357pub enum ControlledAction {
358 Abort = 0,
360 Break = 1,
362 Commit = 2,
364 Continue = 3,
366}
367
368pub trait PollAction {
371 fn into_action(self) -> ControlledAction;
372}
373
374impl PollAction for () {
375 #[inline]
376 fn into_action(self) -> ControlledAction {
377 ControlledAction::Continue
378 }
379}
380
381impl PollAction for ControlledAction {
382 #[inline]
383 fn into_action(self) -> ControlledAction {
384 self
385 }
386}
387
388type FragmentHandlerMap = RefCell<HashMap<usize, *mut dyn FnMut(&[u8])>>;
389type ClaimHandlerMap = RefCell<HashMap<usize, *mut dyn FnMut(&mut [u8]) -> bool>>;
390type ControlledHandlerMap = RefCell<HashMap<usize, *mut dyn FnMut(&[u8]) -> ControlledAction>>;
391
392thread_local! {
395 pub(crate) static HANDLERS: FragmentHandlerMap = RefCell::new(HashMap::new());
396 static CLAIM_HANDLERS: ClaimHandlerMap = RefCell::new(HashMap::new());
397 static CONTROLLED_HANDLERS: ControlledHandlerMap = RefCell::new(HashMap::new());
398}
399
400fn handle_fragment(handler_id: usize, buffer: &[u8]) {
401 HANDLERS.with(|handlers| {
402 if let Some(handler_ptr) = handlers.borrow_mut().get_mut(&handler_id) {
403 unsafe {
404 let handler = &mut **handler_ptr;
405 handler(buffer);
406 }
407 }
408 });
409}
410
411fn handle_controlled_fragment(handler_id: usize, buffer: &[u8]) -> i32 {
412 CONTROLLED_HANDLERS.with(|handlers| {
413 if let Some(handler_ptr) = handlers.borrow_mut().get_mut(&handler_id) {
414 unsafe {
415 let handler = &mut **handler_ptr;
416 handler(buffer) as i32
417 }
418 } else {
419 ControlledAction::Abort as i32
420 }
421 })
422}
423
424fn handle_claim(handler_id: usize, buffer: &mut [u8]) -> bool {
425 CLAIM_HANDLERS.with(|handlers| {
426 if let Some(handler_ptr) = handlers.borrow_mut().get_mut(&handler_id) {
427 unsafe {
428 let handler = &mut **handler_ptr;
429 handler(buffer)
430 }
431 } else {
432 false }
434 })
435}
436
437pub struct Subscription {
439 inner: cxx::UniquePtr<ffi::SubscriptionWrapper>,
440}
441
442impl Subscription {
443 pub fn poll<F>(&mut self, limit: i32, mut handler: F) -> i32
446 where
447 F: FnMut(&[u8]),
448 {
449 let handler_id = &handler as *const _ as usize;
450 let mut_ptr: *mut (dyn FnMut(&[u8]) + 'static) = unsafe {
451 std::mem::transmute::<*mut dyn FnMut(&[u8]), *mut (dyn FnMut(&[u8]) + 'static)>(
452 &mut handler as *mut dyn FnMut(&[u8]),
453 )
454 };
455
456 HANDLERS.with(|handlers| {
457 handlers.borrow_mut().insert(handler_id, mut_ptr);
458 });
459
460 let result = self.inner.pin_mut().poll(limit, handler_id);
461
462 HANDLERS.with(|handlers| {
463 handlers.borrow_mut().remove(&handler_id);
464 });
465
466 result
467 }
468
469 pub fn poll_assembled<R, F>(&mut self, limit: i32, mut handler: F) -> i32
476 where
477 R: PollAction,
478 F: FnMut(&[u8]) -> R,
479 {
480 let mut controlled = |data: &[u8]| -> ControlledAction { handler(data).into_action() };
482
483 let handler_id = &controlled as *const _ as usize;
484 let mut_ptr: *mut (dyn FnMut(&[u8]) -> ControlledAction + 'static) = unsafe {
485 std::mem::transmute::<
486 *mut dyn FnMut(&[u8]) -> ControlledAction,
487 *mut (dyn FnMut(&[u8]) -> ControlledAction + 'static),
488 >(&mut controlled as *mut dyn FnMut(&[u8]) -> ControlledAction)
489 };
490
491 CONTROLLED_HANDLERS.with(|handlers| {
492 handlers.borrow_mut().insert(handler_id, mut_ptr);
493 });
494
495 let result = self
496 .inner
497 .pin_mut()
498 .controlledPollAssembled(limit, handler_id);
499
500 CONTROLLED_HANDLERS.with(|handlers| {
501 handlers.borrow_mut().remove(&handler_id);
502 });
503
504 result
505 }
506
507 pub fn is_connected(&self) -> bool {
509 self.inner.isConnected()
510 }
511
512 #[cfg(feature = "archive")]
513 pub(crate) fn inner_pin_mut(&mut self) -> std::pin::Pin<&mut ffi::SubscriptionWrapper> {
514 self.inner.pin_mut()
515 }
516
517 pub fn image_count(&self) -> i32 {
519 self.inner.imageCount()
520 }
521
522 pub fn image_by_index(&mut self, index: usize) -> Result<Image, Box<dyn std::error::Error>> {
524 let img = self.inner.pin_mut().imageByIndex(index)?;
525 Ok(Image { inner: img })
526 }
527
528 pub fn image_by_session_id(
530 &mut self,
531 session_id: i32,
532 ) -> Result<Image, Box<dyn std::error::Error>> {
533 let img = self.inner.pin_mut().imageBySessionId(session_id)?;
534 Ok(Image { inner: img })
535 }
536}
537
538pub struct Image {
543 inner: cxx::UniquePtr<ffi::ImageWrapper>,
544}
545
546impl Image {
547 #[cfg(feature = "archive")]
548 pub(crate) fn from_raw(inner: cxx::UniquePtr<ffi::ImageWrapper>) -> Self {
549 Self { inner }
550 }
551
552 pub fn session_id(&self) -> i32 {
554 self.inner.sessionId()
555 }
556
557 pub fn correlation_id(&self) -> i64 {
559 self.inner.correlationId()
560 }
561
562 pub fn join_position(&self) -> i64 {
564 self.inner.joinPosition()
565 }
566
567 pub fn source_identity(&self) -> String {
569 self.inner.sourceIdentity()
570 }
571
572 pub fn position(&self) -> i64 {
574 self.inner.position()
575 }
576
577 pub fn set_position(&mut self, new_position: i64) {
579 self.inner.pin_mut().setPosition(new_position);
580 }
581
582 pub fn is_closed(&self) -> bool {
584 self.inner.isClosed()
585 }
586
587 pub fn is_end_of_stream(&self) -> bool {
589 self.inner.isEndOfStream()
590 }
591
592 pub fn end_of_stream_position(&self) -> i64 {
594 self.inner.endOfStreamPosition()
595 }
596
597 pub fn poll<F>(&mut self, limit: i32, mut handler: F) -> i32
599 where
600 F: FnMut(&[u8]),
601 {
602 let handler_id = &handler as *const _ as usize;
603 let mut_ptr: *mut (dyn FnMut(&[u8]) + 'static) = unsafe {
604 std::mem::transmute::<*mut dyn FnMut(&[u8]), *mut (dyn FnMut(&[u8]) + 'static)>(
605 &mut handler as *mut dyn FnMut(&[u8]),
606 )
607 };
608
609 HANDLERS.with(|handlers| {
610 handlers.borrow_mut().insert(handler_id, mut_ptr);
611 });
612
613 let result = self.inner.pin_mut().poll(limit, handler_id);
614
615 HANDLERS.with(|handlers| {
616 handlers.borrow_mut().remove(&handler_id);
617 });
618
619 result
620 }
621
622 pub fn poll_assembled<R, F>(&mut self, limit: i32, mut handler: F) -> i32
623 where
624 R: PollAction,
625 F: FnMut(&[u8]) -> R,
626 {
627 let mut controlled = |data: &[u8]| -> ControlledAction { handler(data).into_action() };
628
629 let handler_id = &controlled as *const _ as usize;
630 let mut_ptr: *mut (dyn FnMut(&[u8]) -> ControlledAction + 'static) = unsafe {
631 std::mem::transmute::<
632 *mut dyn FnMut(&[u8]) -> ControlledAction,
633 *mut (dyn FnMut(&[u8]) -> ControlledAction + 'static),
634 >(&mut controlled as *mut dyn FnMut(&[u8]) -> ControlledAction)
635 };
636
637 CONTROLLED_HANDLERS.with(|handlers| {
638 handlers.borrow_mut().insert(handler_id, mut_ptr);
639 });
640
641 let result = self
642 .inner
643 .pin_mut()
644 .controlledPollAssembled(limit, handler_id);
645
646 CONTROLLED_HANDLERS.with(|handlers| {
647 handlers.borrow_mut().remove(&handler_id);
648 });
649
650 result
651 }
652}
653
654pub struct CountersReader {
659 inner: cxx::UniquePtr<ffi::CountersReaderWrapper>,
660}
661
662type MetadataHandlerMap = RefCell<HashMap<usize, *mut dyn FnMut(i32, i32, &[u8], &str)>>;
663
664thread_local! {
665 static METADATA_HANDLERS: MetadataHandlerMap = RefCell::new(HashMap::new());
666}
667
668fn handle_counters_metadata(
669 handler_id: usize,
670 counter_id: i32,
671 type_id: i32,
672 key: &[u8],
673 label: String,
674) {
675 METADATA_HANDLERS.with(|handlers| {
676 if let Some(handler_ptr) = handlers.borrow_mut().get_mut(&handler_id) {
677 unsafe {
678 let handler = &mut **handler_ptr;
679 handler(counter_id, type_id, key, &label);
680 }
681 }
682 });
683}
684
685impl CountersReader {
686 pub fn max_counter_id(&self) -> i32 {
688 self.inner.maxCounterId()
689 }
690
691 pub fn get_counter_value(&self, id: i32) -> i64 {
693 self.inner.getCounterValue(id)
694 }
695
696 pub fn get_counter_state(&self, id: i32) -> i32 {
698 self.inner.getCounterState(id)
699 }
700
701 pub fn get_counter_type_id(&self, id: i32) -> i32 {
703 self.inner.getCounterTypeId(id)
704 }
705
706 pub fn get_counter_label(&self, id: i32) -> String {
708 self.inner.getCounterLabel(id)
709 }
710
711 pub fn for_each<F>(&self, mut handler: F)
713 where
714 F: FnMut(i32, i32, &[u8], &str),
715 {
716 let handler_id = &handler as *const _ as usize;
717 #[allow(clippy::type_complexity)]
718 let mut_ptr: *mut (dyn FnMut(i32, i32, &[u8], &str) + 'static) = unsafe {
719 std::mem::transmute::<
720 *mut dyn FnMut(i32, i32, &[u8], &str),
721 *mut (dyn FnMut(i32, i32, &[u8], &str) + 'static),
722 >(&mut handler as *mut dyn FnMut(i32, i32, &[u8], &str))
723 };
724
725 METADATA_HANDLERS.with(|handlers| {
726 handlers.borrow_mut().insert(handler_id, mut_ptr);
727 });
728
729 self.inner.forEach(handler_id);
730
731 METADATA_HANDLERS.with(|handlers| {
732 handlers.borrow_mut().remove(&handler_id);
733 });
734 }
735}
736
737impl Default for AeronClient {
738 fn default() -> Self {
739 Self::new().expect("Failed to create AeronClient")
740 }
741}
742
743#[repr(i32)]
745#[derive(Debug, Clone, Copy, PartialEq, Eq)]
746pub enum ThreadingMode {
747 Dedicated = 0,
749 SharedNetwork = 1,
751 Shared = 2,
753 Invoker = 3,
755}
756
757#[derive(Debug, Clone, Copy, PartialEq, Eq)]
759pub enum IdleStrategy {
760 Backoff,
762 Spin,
764 Yield,
766 Sleeping,
768 Noop,
770}
771
772impl IdleStrategy {
773 pub fn as_str(&self) -> &'static str {
774 match self {
775 IdleStrategy::Backoff => "backoff",
776 IdleStrategy::Spin => "spin",
777 IdleStrategy::Yield => "yield",
778 IdleStrategy::Sleeping => "sleeping",
779 IdleStrategy::Noop => "noop",
780 }
781 }
782}
783
784pub struct MediaDriver {
787 inner: cxx::UniquePtr<ffi::MediaDriverWrapper>,
788}
789
790impl MediaDriver {
791 pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
793 let inner = ffi::create_media_driver()?;
794 Ok(Self { inner })
795 }
796
797 pub fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
799 self.inner.pin_mut().start()?;
800 Ok(())
801 }
802
803 pub fn set_dir(&mut self, dir: &str) -> Result<(), Box<dyn std::error::Error>> {
805 self.inner.pin_mut().setDir(dir)?;
806 Ok(())
807 }
808
809 pub fn set_dir_delete_on_start(
810 &mut self,
811 value: bool,
812 ) -> Result<(), Box<dyn std::error::Error>> {
813 self.inner.pin_mut().setDirDeleteOnStart(value)?;
814 Ok(())
815 }
816
817 pub fn set_dir_delete_on_shutdown(
818 &mut self,
819 value: bool,
820 ) -> Result<(), Box<dyn std::error::Error>> {
821 self.inner.pin_mut().setDirDeleteOnShutdown(value)?;
822 Ok(())
823 }
824
825 pub fn set_threading_mode(
826 &mut self,
827 mode: ThreadingMode,
828 ) -> Result<(), Box<dyn std::error::Error>> {
829 self.inner.pin_mut().setThreadingMode(mode as i32)?;
830 Ok(())
831 }
832
833 pub fn set_conductor_idle_strategy(
834 &mut self,
835 strategy: IdleStrategy,
836 ) -> Result<(), Box<dyn std::error::Error>> {
837 self.inner
838 .pin_mut()
839 .setConductorIdleStrategy(strategy.as_str())?;
840 Ok(())
841 }
842
843 pub fn set_sender_idle_strategy(
844 &mut self,
845 strategy: IdleStrategy,
846 ) -> Result<(), Box<dyn std::error::Error>> {
847 self.inner
848 .pin_mut()
849 .setSenderIdleStrategy(strategy.as_str())?;
850 Ok(())
851 }
852
853 pub fn set_receiver_idle_strategy(
854 &mut self,
855 strategy: IdleStrategy,
856 ) -> Result<(), Box<dyn std::error::Error>> {
857 self.inner
858 .pin_mut()
859 .setReceiverIdleStrategy(strategy.as_str())?;
860 Ok(())
861 }
862
863 pub fn set_term_buffer_length(
864 &mut self,
865 value: usize,
866 ) -> Result<(), Box<dyn std::error::Error>> {
867 self.inner.pin_mut().setTermBufferLength(value)?;
868 Ok(())
869 }
870
871 pub fn set_ipc_term_buffer_length(
872 &mut self,
873 value: usize,
874 ) -> Result<(), Box<dyn std::error::Error>> {
875 self.inner.pin_mut().setIpcTermBufferLength(value)?;
876 Ok(())
877 }
878
879 pub fn set_mtu_length(&mut self, value: usize) -> Result<(), Box<dyn std::error::Error>> {
880 self.inner.pin_mut().setMtuLength(value)?;
881 Ok(())
882 }
883
884 pub fn set_ipc_mtu_length(&mut self, value: usize) -> Result<(), Box<dyn std::error::Error>> {
885 self.inner.pin_mut().setIpcMtuLength(value)?;
886 Ok(())
887 }
888
889 pub fn set_socket_so_rcvbuf(&mut self, value: usize) -> Result<(), Box<dyn std::error::Error>> {
890 self.inner.pin_mut().setSocketSoRcvbuf(value)?;
891 Ok(())
892 }
893
894 pub fn set_socket_so_sndbuf(&mut self, value: usize) -> Result<(), Box<dyn std::error::Error>> {
895 self.inner.pin_mut().setSocketSoSndbuf(value)?;
896 Ok(())
897 }
898
899 pub fn set_print_configuration(
900 &mut self,
901 value: bool,
902 ) -> Result<(), Box<dyn std::error::Error>> {
903 self.inner.pin_mut().setPrintConfiguration(value)?;
904 Ok(())
905 }
906
907 pub fn set_conductor_cpu_affinity(
908 &mut self,
909 cpu_id: i32,
910 ) -> Result<(), Box<dyn std::error::Error>> {
911 self.inner.pin_mut().setConductorCpuAffinity(cpu_id)?;
912 Ok(())
913 }
914
915 pub fn set_sender_cpu_affinity(
916 &mut self,
917 cpu_id: i32,
918 ) -> Result<(), Box<dyn std::error::Error>> {
919 self.inner.pin_mut().setSenderCpuAffinity(cpu_id)?;
920 Ok(())
921 }
922
923 pub fn set_receiver_cpu_affinity(
924 &mut self,
925 cpu_id: i32,
926 ) -> Result<(), Box<dyn std::error::Error>> {
927 self.inner.pin_mut().setReceiverCpuAffinity(cpu_id)?;
928 Ok(())
929 }
930}
931
932impl Default for MediaDriver {
933 fn default() -> Self {
934 Self::new().expect("Failed to create MediaDriver")
935 }
936}
937
938pub struct ChannelBuilder {
955 media: &'static str,
956 params: Vec<(String, String)>,
957}
958
959impl ChannelBuilder {
960 pub fn ipc() -> Self {
962 Self {
963 media: "ipc",
964 params: Vec::new(),
965 }
966 }
967
968 pub fn udp() -> Self {
970 Self {
971 media: "udp",
972 params: Vec::new(),
973 }
974 }
975
976 pub fn endpoint(self, value: &str) -> Self {
978 self.param("endpoint", value)
979 }
980 pub fn control(self, value: &str) -> Self {
981 self.param("control", value)
982 }
983 pub fn control_mode(self, value: &str) -> Self {
984 self.param("control-mode", value)
985 }
986 pub fn interface(self, value: &str) -> Self {
987 self.param("interface", value)
988 }
989 pub fn mtu(self, bytes: usize) -> Self {
990 self.param("mtu", &bytes.to_string())
991 }
992 pub fn term_length(self, bytes: usize) -> Self {
993 self.param("term-length", &bytes.to_string())
994 }
995 pub fn session_id(self, id: i32) -> Self {
996 self.param("session-id", &id.to_string())
997 }
998 pub fn ttl(self, hops: u8) -> Self {
999 self.param("ttl", &hops.to_string())
1000 }
1001 pub fn reliable(self, value: bool) -> Self {
1002 self.param("reliable", if value { "true" } else { "false" })
1003 }
1004 pub fn sparse(self, value: bool) -> Self {
1005 self.param("sparse", if value { "true" } else { "false" })
1006 }
1007 pub fn linger(self, ns: u64) -> Self {
1008 self.param("linger", &ns.to_string())
1009 }
1010 pub fn tether(self, value: bool) -> Self {
1011 self.param("tether", if value { "true" } else { "false" })
1012 }
1013 pub fn rejoin(self, value: bool) -> Self {
1014 self.param("rejoin", if value { "true" } else { "false" })
1015 }
1016 pub fn flow_control(self, value: &str) -> Self {
1017 self.param("fc", value)
1018 }
1019 pub fn congestion_control(self, value: &str) -> Self {
1020 self.param("cc", value)
1021 }
1022 pub fn socket_sndbuf(self, bytes: usize) -> Self {
1023 self.param("so-sndbuf", &bytes.to_string())
1024 }
1025 pub fn socket_rcvbuf(self, bytes: usize) -> Self {
1026 self.param("so-rcvbuf", &bytes.to_string())
1027 }
1028 pub fn receiver_window(self, bytes: usize) -> Self {
1029 self.param("rcv-wnd", &bytes.to_string())
1030 }
1031
1032 pub fn param(mut self, key: &str, value: &str) -> Self {
1034 self.params.push((key.to_string(), value.to_string()));
1035 self
1036 }
1037
1038 pub fn build(&self) -> String {
1040 let mut uri = format!("aeron:{}", self.media);
1041 for (i, (key, value)) in self.params.iter().enumerate() {
1042 uri.push(if i == 0 { '?' } else { '|' });
1043 uri.push_str(key);
1044 uri.push('=');
1045 uri.push_str(value);
1046 }
1047 uri
1048 }
1049}
1050
1051#[cfg(test)]
1052mod tests {
1053 use super::*;
1054
1055 #[test]
1056 fn test_aeron_creation_with_driver() {
1057 let mut driver = MediaDriver::new().expect("Failed to create MediaDriver");
1059 driver.start().expect("Failed to start MediaDriver");
1060
1061 std::thread::sleep(std::time::Duration::from_millis(100));
1063
1064 let mut client = AeronClient::new().expect("Failed to connect to media driver");
1066 client.start();
1067 assert!(!client.is_closed());
1068
1069 let mut publ = client
1071 .add_publication("aeron:ipc", 10)
1072 .expect("add pub failed");
1073 let mut sub = client
1074 .add_subscription("aeron:ipc", 10)
1075 .expect("add sub failed");
1076
1077 let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5);
1079 while !sub.is_connected() && std::time::Instant::now() < deadline {
1080 std::thread::sleep(std::time::Duration::from_millis(10));
1081 }
1082 assert!(sub.is_connected(), "subscription should connect");
1083
1084 while publ.offer(b"hello") < 0 {
1086 std::thread::yield_now();
1087 }
1088
1089 assert_eq!(sub.image_count(), 1);
1090 let image = sub.image_by_index(0).expect("image_by_index failed");
1091 assert!(image.session_id() != 0);
1092 assert!(image.position() >= 0);
1093 assert!(!image.is_closed());
1094 assert!(!image.is_end_of_stream());
1095
1096 let sid = image.session_id();
1098 let image2 = sub
1099 .image_by_session_id(sid)
1100 .expect("image_by_session_id failed");
1101 assert_eq!(image2.session_id(), sid);
1102 }
1103
1104 #[test]
1105 fn test_channel_builder_ipc() {
1106 assert_eq!(ChannelBuilder::ipc().build(), "aeron:ipc");
1107 }
1108
1109 #[test]
1110 fn test_channel_builder_udp() {
1111 let uri = ChannelBuilder::udp().endpoint("localhost:20121").build();
1112 assert_eq!(uri, "aeron:udp?endpoint=localhost:20121");
1113 }
1114
1115 #[test]
1116 fn test_channel_builder_multiple_params() {
1117 let uri = ChannelBuilder::udp()
1118 .endpoint("localhost:20121")
1119 .mtu(8192)
1120 .term_length(65536)
1121 .reliable(true)
1122 .build();
1123 assert_eq!(
1124 uri,
1125 "aeron:udp?endpoint=localhost:20121|mtu=8192|term-length=65536|reliable=true"
1126 );
1127 }
1128
1129 #[test]
1130 fn test_channel_builder_multicast() {
1131 let uri = ChannelBuilder::udp()
1132 .endpoint("224.0.1.1:40456")
1133 .interface("localhost")
1134 .ttl(4)
1135 .build();
1136 assert_eq!(
1137 uri,
1138 "aeron:udp?endpoint=224.0.1.1:40456|interface=localhost|ttl=4"
1139 );
1140 }
1141
1142 #[test]
1143 fn test_channel_builder_mdc() {
1144 let uri = ChannelBuilder::udp()
1145 .control("localhost:40456")
1146 .control_mode("dynamic")
1147 .build();
1148 assert_eq!(
1149 uri,
1150 "aeron:udp?control=localhost:40456|control-mode=dynamic"
1151 );
1152 }
1153
1154 #[test]
1155 fn test_channel_builder_custom_param() {
1156 let uri = ChannelBuilder::ipc().param("alias", "my-channel").build();
1157 assert_eq!(uri, "aeron:ipc?alias=my-channel");
1158 }
1159}