Constant COMMON_CODE

Source
pub const COMMON_CODE: &str = "use crate::AeronErrorType::Unknown;\n#[cfg(feature = \"backtrace\")]\nuse std::backtrace::Backtrace;\nuse std::cell::UnsafeCell;\nuse std::fmt::Formatter;\nuse std::mem::MaybeUninit;\nuse std::ops::{Deref, DerefMut};\n\npub enum CResource<T> {\n    OwnedOnHeap(std::rc::Rc<ManagedCResource<T>>),\n    /// stored on stack, unsafe, use with care\n    OwnedOnStack(std::mem::MaybeUninit<T>),\n    Borrowed(*mut T),\n}\n\nimpl<T: Clone> Clone for CResource<T> {\n    fn clone(&self) -> Self {\n        unsafe {\n            match self {\n                CResource::OwnedOnHeap(r) => CResource::OwnedOnHeap(r.clone()),\n                CResource::OwnedOnStack(r) => {\n                    CResource::OwnedOnStack(MaybeUninit::new(r.assume_init_ref().clone()))\n                }\n                CResource::Borrowed(r) => CResource::Borrowed(r.clone()),\n            }\n        }\n    }\n}\n\nimpl<T> CResource<T> {\n    #[inline]\n    pub fn get(&self) -> *mut T {\n        match self {\n            CResource::OwnedOnHeap(r) => r.get(),\n            CResource::OwnedOnStack(r) => r.as_ptr() as *mut T,\n            CResource::Borrowed(r) => *r,\n        }\n    }\n\n    #[inline]\n    // to prevent the dependencies from being dropped as you have a copy here\n    pub fn add_dependency<D: std::any::Any>(&self, dep: D) {\n        match self {\n            CResource::OwnedOnHeap(r) => r.add_dependency(dep),\n            CResource::OwnedOnStack(_) | CResource::Borrowed(_) => {\n                unreachable!(\"only owned on heap\")\n            }\n        }\n    }\n    #[inline]\n    pub fn get_dependency<V: Clone + \'static>(&self) -> Option<V> {\n        match self {\n            CResource::OwnedOnHeap(r) => r.get_dependency(),\n            CResource::OwnedOnStack(_) | CResource::Borrowed(_) => None,\n        }\n    }\n\n    #[inline]\n    pub fn as_owned(&self) -> Option<&std::rc::Rc<ManagedCResource<T>>> {\n        match self {\n            CResource::OwnedOnHeap(r) => Some(r),\n            CResource::OwnedOnStack(_) | CResource::Borrowed(_) => None,\n        }\n    }\n}\n\nimpl<T> std::fmt::Debug for CResource<T> {\n    fn fmt(&self, f: &mut Formatter<\'_>) -> std::fmt::Result {\n        let name = std::any::type_name::<T>();\n\n        match self {\n            CResource::OwnedOnHeap(r) => {\n                write!(f, \"{name} heap({:?})\", r)\n            }\n            CResource::OwnedOnStack(r) => {\n                write!(f, \"{name} stack({:?})\", *r)\n            }\n            CResource::Borrowed(r) => {\n                write!(f, \"{name} borrowed ({:?})\", r)\n            }\n        }\n    }\n}\n\n/// A custom struct for managing C resources with automatic cleanup.\n///\n/// It handles initialisation and clean-up of the resource and ensures that resources\n/// are properly released when they go out of scope.\n#[allow(dead_code)]\npub struct ManagedCResource<T> {\n    resource: *mut T,\n    cleanup: Option<Box<dyn FnMut(*mut *mut T) -> i32>>,\n    cleanup_struct: bool,\n    /// if someone externally rusteron calls close\n    close_already_called: std::cell::Cell<bool>,\n    /// if there is a c method to verify it someone has closed it, only few structs have this functionality\n    check_for_is_closed: Option<fn(*mut T) -> bool>,\n    /// this will be called if closed hasn\'t already happened even if its borrowed\n    auto_close: std::cell::Cell<bool>,\n    /// to prevent the dependencies from being dropped as you have a copy here,\n    /// for example, you want to have a dependency to aeron for any async jobs so aeron doesnt get dropped first\n    /// when you have a publication/subscription\n    /// Note empty vec does not allocate on heap\n    dependencies: UnsafeCell<Vec<std::rc::Rc<dyn std::any::Any>>>,\n}\n\nimpl<T> std::fmt::Debug for ManagedCResource<T> {\n    fn fmt(&self, f: &mut std::fmt::Formatter<\'_>) -> std::fmt::Result {\n        let mut debug_struct = f.debug_struct(\"ManagedCResource\");\n\n        if !self.close_already_called.get()\n            && !self.resource.is_null()\n            && !self\n                .check_for_is_closed\n                .as_ref()\n                .map_or(false, |f| f(self.resource))\n        {\n            debug_struct.field(\"resource\", &self.resource);\n        }\n\n        debug_struct\n            .field(\"type\", &std::any::type_name::<T>())\n            .finish()\n    }\n}\n\nimpl<T> ManagedCResource<T> {\n    /// Creates a new ManagedCResource with a given initializer and cleanup function.\n    ///\n    /// The initializer is a closure that attempts to initialize the resource.\n    /// If initialization fails, the initializer should return an error code.\n    /// The cleanup function is used to release the resource when it\'s no longer needed.\n    /// `cleanup_struct` where it should clean up the struct in rust\n    pub fn new(\n        init: impl FnOnce(*mut *mut T) -> i32,\n        cleanup: Option<Box<dyn FnMut(*mut *mut T) -> i32>>,\n        cleanup_struct: bool,\n        check_for_is_closed: Option<fn(*mut T) -> bool>,\n    ) -> Result<Self, AeronCError> {\n        let resource = Self::initialise(init)?;\n\n        let result = Self {\n            resource,\n            cleanup,\n            cleanup_struct,\n            close_already_called: std::cell::Cell::new(false),\n            check_for_is_closed,\n            auto_close: std::cell::Cell::new(false),\n            dependencies: UnsafeCell::new(vec![]),\n        };\n        #[cfg(feature = \"extra-logging\")]\n        log::info!(\"created c resource: {:?}\", result);\n        Ok(result)\n    }\n\n    pub fn initialise(\n        init: impl FnOnce(*mut *mut T) -> i32 + Sized,\n    ) -> Result<*mut T, AeronCError> {\n        let mut resource: *mut T = std::ptr::null_mut();\n        let result = init(&mut resource);\n        if result < 0 || resource.is_null() {\n            return Err(AeronCError::from_code(result));\n        }\n        Ok(resource)\n    }\n\n    pub fn is_closed_already_called(&self) -> bool {\n        self.close_already_called.get()\n            || self.resource.is_null()\n            || self\n                .check_for_is_closed\n                .as_ref()\n                .map_or(false, |f| f(self.resource))\n    }\n\n    /// Gets a raw pointer to the resource.\n    #[inline(always)]\n    pub fn get(&self) -> *mut T {\n        self.resource\n    }\n\n    #[inline(always)]\n    pub fn get_mut(&self) -> &mut T {\n        unsafe { &mut *self.resource }\n    }\n\n    #[inline]\n    // to prevent the dependencies from being dropped as you have a copy here\n    pub fn add_dependency<D: std::any::Any>(&self, dep: D) {\n        if let Some(dep) =\n            (&dep as &dyn std::any::Any).downcast_ref::<std::rc::Rc<dyn std::any::Any>>()\n        {\n            unsafe {\n                (*self.dependencies.get()).push(dep.clone());\n            }\n        } else {\n            unsafe {\n                (*self.dependencies.get()).push(std::rc::Rc::new(dep));\n            }\n        }\n    }\n\n    #[inline]\n    pub fn get_dependency<V: Clone + \'static>(&self) -> Option<V> {\n        unsafe {\n            (*self.dependencies.get())\n                .iter()\n                .filter_map(|x| x.as_ref().downcast_ref::<V>().cloned())\n                .next()\n        }\n    }\n\n    /// Closes the resource by calling the cleanup function.\n    ///\n    /// If cleanup fails, it returns an `AeronError`.\n    pub fn close(&mut self) -> Result<(), AeronCError> {\n        if self.close_already_called.get() {\n            return Ok(());\n        }\n        self.close_already_called.set(true);\n\n        let already_closed = self\n            .check_for_is_closed\n            .as_ref()\n            .map_or(false, |f| f(self.resource));\n\n        if let Some(mut cleanup) = self.cleanup.take() {\n            if !self.resource.is_null() {\n                if !already_closed {\n                    let result = cleanup(&mut self.resource);\n                    if result < 0 {\n                        return Err(AeronCError::from_code(result));\n                    }\n                }\n                self.resource = std::ptr::null_mut();\n            }\n        }\n\n        Ok(())\n    }\n}\n\nimpl<T> Drop for ManagedCResource<T> {\n    fn drop(&mut self) {\n        if !self.resource.is_null() {\n            let already_closed = self.close_already_called.get()\n                || self\n                    .check_for_is_closed\n                    .as_ref()\n                    .map_or(false, |f| f(self.resource));\n\n            let resource = if already_closed {\n                self.resource\n            } else {\n                self.resource.clone()\n            };\n\n            if !already_closed {\n                // Ensure the clean-up function is called when the resource is dropped.\n                #[cfg(feature = \"extra-logging\")]\n                log::info!(\"closing c resource: {:?}\", self);\n                let _ = self.close(); // Ignore errors during an automatic drop to avoid panics.\n            }\n            self.close_already_called.set(true);\n\n            if self.cleanup_struct {\n                #[cfg(feature = \"extra-logging\")]\n                log::info!(\"closing rust struct resource: {:?}\", resource);\n                unsafe {\n                    let _ = Box::from_raw(resource);\n                }\n            }\n        }\n    }\n}\n\n#[derive(Debug, PartialOrd, Eq, PartialEq, Clone)]\npub enum AeronErrorType {\n    GenericError,\n    ClientErrorDriverTimeout,\n    ClientErrorClientTimeout,\n    ClientErrorConductorServiceTimeout,\n    ClientErrorBufferFull,\n    PublicationBackPressured,\n    PublicationAdminAction,\n    PublicationClosed,\n    PublicationMaxPositionExceeded,\n    PublicationError,\n    TimedOut,\n    Unknown(i32),\n}\n\nimpl From<AeronErrorType> for AeronCError {\n    fn from(value: AeronErrorType) -> Self {\n        AeronCError::from_code(value.code())\n    }\n}\n\nimpl AeronErrorType {\n    pub fn code(&self) -> i32 {\n        match self {\n            AeronErrorType::GenericError => -1,\n            AeronErrorType::ClientErrorDriverTimeout => -1000,\n            AeronErrorType::ClientErrorClientTimeout => -1001,\n            AeronErrorType::ClientErrorConductorServiceTimeout => -1002,\n            AeronErrorType::ClientErrorBufferFull => -1003,\n            AeronErrorType::PublicationBackPressured => -2,\n            AeronErrorType::PublicationAdminAction => -3,\n            AeronErrorType::PublicationClosed => -4,\n            AeronErrorType::PublicationMaxPositionExceeded => -5,\n            AeronErrorType::PublicationError => -6,\n            AeronErrorType::TimedOut => -234324,\n            AeronErrorType::Unknown(code) => *code,\n        }\n    }\n\n    pub fn is_back_pressured(&self) -> bool {\n        self == &AeronErrorType::PublicationBackPressured\n    }\n\n    pub fn is_admin_action(&self) -> bool {\n        self == &AeronErrorType::PublicationAdminAction\n    }\n\n    pub fn is_back_pressured_or_admin_action(&self) -> bool {\n        self.is_back_pressured() || self.is_admin_action()\n    }\n\n    pub fn from_code(code: i32) -> Self {\n        match code {\n            -1 => AeronErrorType::GenericError,\n            -1000 => AeronErrorType::ClientErrorDriverTimeout,\n            -1001 => AeronErrorType::ClientErrorClientTimeout,\n            -1002 => AeronErrorType::ClientErrorConductorServiceTimeout,\n            -1003 => AeronErrorType::ClientErrorBufferFull,\n            -2 => AeronErrorType::PublicationBackPressured,\n            -3 => AeronErrorType::PublicationAdminAction,\n            -4 => AeronErrorType::PublicationClosed,\n            -5 => AeronErrorType::PublicationMaxPositionExceeded,\n            -6 => AeronErrorType::PublicationError,\n            -234324 => AeronErrorType::TimedOut,\n            _ => Unknown(code),\n        }\n    }\n\n    pub fn to_string(&self) -> &\'static str {\n        match self {\n            AeronErrorType::GenericError => \"Generic Error\",\n            AeronErrorType::ClientErrorDriverTimeout => \"Client Error Driver Timeout\",\n            AeronErrorType::ClientErrorClientTimeout => \"Client Error Client Timeout\",\n            AeronErrorType::ClientErrorConductorServiceTimeout => {\n                \"Client Error Conductor Service Timeout\"\n            }\n            AeronErrorType::ClientErrorBufferFull => \"Client Error Buffer Full\",\n            AeronErrorType::PublicationBackPressured => \"Publication Back Pressured\",\n            AeronErrorType::PublicationAdminAction => \"Publication Admin Action\",\n            AeronErrorType::PublicationClosed => \"Publication Closed\",\n            AeronErrorType::PublicationMaxPositionExceeded => \"Publication Max Position Exceeded\",\n            AeronErrorType::PublicationError => \"Publication Error\",\n            AeronErrorType::TimedOut => \"Timed Out\",\n            AeronErrorType::Unknown(_) => \"Unknown Error\",\n        }\n    }\n}\n\n/// Represents an Aeron-specific error with a code and an optional message.\n///\n/// The error code is derived from Aeron C API calls.\n/// Use `get_last_err_message()` to retrieve the last human-readable message, if available.\n#[derive(Eq, PartialEq, Clone)]\npub struct AeronCError {\n    pub code: i32,\n}\n\nimpl AeronCError {\n    /// Creates an AeronError from the error code returned by Aeron.\n    ///\n    /// Error codes below zero are considered failure.\n    pub fn from_code(code: i32) -> Self {\n        #[cfg(feature = \"backtrace\")]\n        {\n            if code < 0 {\n                let backtrace = Backtrace::capture();\n                let backtrace = format!(\"{:?}\", backtrace);\n\n                let re =\n                    regex::Regex::new(r#\"fn: \"([^\"]+)\", file: \"([^\"]+)\", line: (\\d+)\"#).unwrap();\n                let mut lines = String::new();\n                re.captures_iter(&backtrace).for_each(|cap| {\n                    let function = &cap[1];\n                    let mut file = cap[2].to_string();\n                    let line = &cap[3];\n                    if file.starts_with(\"./\") {\n                        file = format!(\"{}/{}\", env!(\"CARGO_MANIFEST_DIR\"), &file[2..]);\n                    } else if file.starts_with(\"/rustc/\") {\n                        file = file.split(\"/\").last().unwrap().to_string();\n                    }\n                    // log in intellij friendly error format so can hyperlink to source code in stack trace\n                    lines.push_str(&format!(\" {file}:{line} in {function}\\n\"));\n                });\n\n                log::error!(\n                    \"Aeron C error code: {}, kind: \'{:?}\'\\n{}\",\n                    code,\n                    AeronErrorType::from_code(code),\n                    lines\n                );\n            }\n        }\n        AeronCError { code }\n    }\n\n    pub fn kind(&self) -> AeronErrorType {\n        AeronErrorType::from_code(self.code)\n    }\n\n    pub fn is_back_pressured(&self) -> bool {\n        self.kind().is_back_pressured()\n    }\n\n    pub fn is_admin_action(&self) -> bool {\n        self.kind().is_admin_action()\n    }\n\n    pub fn is_back_pressured_or_admin_action(&self) -> bool {\n        self.kind().is_back_pressured_or_admin_action()\n    }\n}\n\n/// # Handler\n///\n/// `Handler` is a struct that wraps a raw pointer and a drop flag.\n///\n/// **Important:** `Handler` *MAY* not get dropped automatically. It depends if aeron takes ownership.\n/// For example for global level handlers e.g. error handler aeron will release this handle when closing.\n///\n/// You need to call the `release` method if you want to clear the memory manually.\n/// Its important that you test this out as aeron may do it when closing aeron client.\n///\n/// ## Example\n///\n/// ```no_compile\n/// use rusteron_code_gen::Handler;\n/// let handler = Handler::leak(your_value);\n/// // When you are done with the handler\n/// handler.release();\n/// ```\npub struct Handler<T> {\n    raw_ptr: *mut T,\n    should_drop: bool,\n}\n\nunsafe impl<T> Send for Handler<T> {}\nunsafe impl<T> Sync for Handler<T> {}\n\n/// Utility method for setting empty handlers\npub struct Handlers;\n\nimpl<T> Handler<T> {\n    pub fn leak(handler: T) -> Self {\n        let raw_ptr = Box::into_raw(Box::new(handler)) as *mut _;\n        #[cfg(feature = \"extra-logging\")]\n        log::info!(\"creating handler {:?}\", raw_ptr);\n        Self {\n            raw_ptr,\n            should_drop: true,\n        }\n    }\n\n    pub fn is_none(&self) -> bool {\n        self.raw_ptr.is_null()\n    }\n\n    pub fn as_raw(&self) -> *mut std::os::raw::c_void {\n        self.raw_ptr as *mut std::os::raw::c_void\n    }\n\n    pub fn release(&mut self) {\n        if self.should_drop && !self.raw_ptr.is_null() {\n            unsafe {\n                #[cfg(feature = \"extra-logging\")]\n                log::info!(\"dropping handler {:?}\", self.raw_ptr);\n                let _ = Box::from_raw(self.raw_ptr as *mut T);\n                self.should_drop = false;\n            }\n        }\n    }\n\n    pub unsafe fn new(raw_ptr: *mut T, should_drop: bool) -> Self {\n        Self {\n            raw_ptr,\n            should_drop,\n        }\n    }\n}\n\nimpl<T> Deref for Handler<T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        unsafe { &*self.raw_ptr as &T }\n    }\n}\n\nimpl<T> DerefMut for Handler<T> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        unsafe { &mut *self.raw_ptr as &mut T }\n    }\n}\n\npub fn find_unused_udp_port(start_port: u16) -> Option<u16> {\n    let end_port = u16::MAX;\n\n    for port in start_port..=end_port {\n        if is_udp_port_available(port) {\n            return Some(port);\n        }\n    }\n\n    None\n}\n\npub fn is_udp_port_available(port: u16) -> bool {\n    std::net::UdpSocket::bind((\"127.0.0.1\", port)).is_ok()\n}\n\n/// Represents the Aeron URI parser and handler.\npub struct ChannelUri {}\n\nimpl ChannelUri {\n    pub const AERON_SCHEME: &\'static str = \"aeron\";\n    pub const SPY_QUALIFIER: &\'static str = \"aeron-spy\";\n    pub const MAX_URI_LENGTH: usize = 4095;\n}\n\npub const DRIVER_TIMEOUT_MS_DEFAULT: u64 = 10_000;\npub const AERON_DIR_PROP_NAME: &str = \"aeron.dir\";\npub const AERON_IPC_MEDIA: &str = \"aeron:ipc\";\npub const AERON_UDP_MEDIA: &str = \"aeron:udp\";\npub const SPY_PREFIX: &str = \"aeron-spy:\";\npub const TAG_PREFIX: &str = \"tag:\";\n\n/// Enum for media types.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum Media {\n    Ipc,\n    Udp,\n}\n\nimpl Media {\n    pub fn as_str(&self) -> &\'static str {\n        match self {\n            Media::Ipc => \"ipc\",\n            Media::Udp => \"udp\",\n        }\n    }\n}\n\n/// Enum for control modes.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\npub enum ControlMode {\n    Manual,\n    Dynamic,\n    /// this is a beta feature useful when dealing with docker containers and networking\n    Response,\n}\n\nimpl ControlMode {\n    pub fn as_str(&self) -> &\'static str {\n        match self {\n            ControlMode::Manual => \"manual\",\n            ControlMode::Dynamic => \"dynamic\",\n            ControlMode::Response => \"response\",\n        }\n    }\n}\n\n#[cfg(test)]\n#[allow(dead_code)]\npub(crate) mod test_alloc {\n    use std::alloc::{GlobalAlloc, Layout, System};\n    use std::sync::atomic::{AtomicIsize, Ordering};\n\n    /// A simple global allocator that tracks the net allocation count.\n    /// For very simple examples can do allocation count before and after your test.\n    /// This does not work well with logger, running media driver, etc. Only for the most\n    /// basic controlled examples\n    pub struct CountingAllocator {\n        allocs: AtomicIsize,\n    }\n\n    impl CountingAllocator {\n        pub const fn new() -> Self {\n            Self {\n                allocs: AtomicIsize::new(0),\n            }\n        }\n        /// Returns the current allocation counter value.\n        fn current(&self) -> isize {\n            self.allocs.load(Ordering::SeqCst)\n        }\n    }\n\n    unsafe impl GlobalAlloc for CountingAllocator {\n        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {\n            self.allocs.fetch_add(1, Ordering::SeqCst);\n            System.alloc(layout)\n        }\n        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {\n            self.allocs.fetch_sub(1, Ordering::SeqCst);\n            System.dealloc(ptr, layout)\n        }\n    }\n\n    #[global_allocator]\n    static GLOBAL: CountingAllocator = CountingAllocator::new();\n\n    /// Returns the current allocation counter value.\n    pub fn current_allocs() -> isize {\n        GLOBAL.current()\n    }\n}\n\npub trait IntoCString {\n    fn into_c_string(self) -> std::ffi::CString;\n}\n\nimpl IntoCString for std::ffi::CString {\n    fn into_c_string(self) -> std::ffi::CString {\n        self\n    }\n}\n\nimpl IntoCString for &str {\n    fn into_c_string(self) -> std::ffi::CString {\n        #[cfg(feature = \"extra-logging\")]\n        log::info!(\"created c string on heap: {:?}\", self);\n\n        std::ffi::CString::new(self).expect(\"failed to create CString\")\n    }\n}\n\nimpl IntoCString for String {\n    fn into_c_string(self) -> std::ffi::CString {\n        #[cfg(feature = \"extra-logging\")]\n        log::info!(\"created c string on heap: {:?}\", self);\n\n        std::ffi::CString::new(self).expect(\"failed to create CString\")\n    }\n}\n";