rusteron_code_gen

Constant COMMON_CODE

Source
pub const COMMON_CODE: &str = "use crate::AeronErrorType::Unknown;\n#[cfg(debug_assertions)]\nuse std::backtrace::Backtrace;\nuse std::collections::BTreeMap;\nuse std::fmt::{Debug, Formatter};\nuse std::ops::{Deref, DerefMut};\nuse std::{any, fmt, ptr};\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.\npub struct ManagedCResource<T> {\n    resource: *mut T,\n    cleanup: Option<Box<dyn FnMut(*mut *mut T) -> i32>>,\n    cleanup_struct: bool,\n    borrowed: bool,\n}\n\nimpl<T> Debug for ManagedCResource<T> {\n    fn fmt(&self, f: &mut Formatter<\'_>) -> fmt::Result {\n        f.debug_struct(\"ManagedCResource\")\n            .field(\"resource\", &self.resource)\n            .field(\"type\", &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: impl FnMut(*mut *mut T) -> i32 + \'static,\n        cleanup_struct: bool,\n    ) -> Result<Self, AeronCError> {\n        let mut resource: *mut T = 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\n        let result = Self {\n            resource,\n            cleanup: Some(Box::new(cleanup)),\n            cleanup_struct,\n            borrowed: false,\n        };\n        log::info!(\"created c resource: {:?}\", result);\n        Ok(result)\n    }\n\n    pub fn new_borrowed(value: *const T) -> Self {\n        Self {\n            resource: value as *mut _,\n            cleanup: None,\n            cleanup_struct: false,\n            borrowed: true,\n        }\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    /// 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 let Some(mut cleanup) = self.cleanup.take() {\n            if !self.resource.is_null() {\n                let result = cleanup(&mut self.resource);\n                if result < 0 {\n                    return Err(AeronCError::from_code(result));\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() && !self.borrowed {\n            let resource = self.resource.clone();\n            // Ensure the clean-up function is called when the resource is dropped.\n            log::info!(\"closing c resource: {:?}\", self);\n            let _ = self.close(); // Ignore errors during an automatic drop to avoid panics.\n\n            if self.cleanup_struct {\n                log::info!(\"closing rust struct resource: {:?}\", self);\n                unsafe {\n                    let _ = Box::from_raw(resource);\n                }\n            }\n        }\n    }\n}\n\n#[derive(Debug)]\npub enum AeronErrorType {\n    NullOrNotConnected,\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::NullOrNotConnected => -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 from_code(code: i32) -> Self {\n        match code {\n            -1 => AeronErrorType::NullOrNotConnected,\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::NullOrNotConnected => \"Null Value or Not Connected\",\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_message()` to retrieve a human-readable message, if available.\n#[derive(Eq, PartialEq)]\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(debug_assertions)]\n        {\n            if code < 0 {\n                let backtrace = Backtrace::capture();\n                log::error!(\n                    \"Aeron C error code: {}, kind: \'{:?}\' - {:#?}\",\n                    code,\n                    AeronErrorType::from_code(code),\n                    backtrace\n                );\n\n                let backtrace = format!(\"{:?}\", backtrace);\n                // Regular expression to match the function, file, and line\n                let re =\n                    regex::Regex::new(r#\"fn: \"([^\"]+)\", file: \"([^\"]+)\", line: (\\d+)\"#).unwrap();\n\n                // Extract and print in IntelliJ format with function\n                for cap in re.captures_iter(&backtrace) {\n                    let function = &cap[1];\n                    let file = &cap[2];\n                    let line = &cap[3];\n                    log::warn!(\"ERROR: {file}:{line} in {function}\");\n                }\n            }\n        }\n        AeronCError { code }\n    }\n\n    pub fn kind(&self) -> AeronErrorType {\n        AeronErrorType::from_code(self.code)\n    }\n}\n\nimpl fmt::Display for AeronCError {\n    fn fmt(&self, f: &mut fmt::Formatter<\'_>) -> fmt::Result {\n        write!(f, \"Aeron error {}: {:?}\", self.code, self.kind())\n    }\n}\n\nimpl fmt::Debug for AeronCError {\n    fn fmt(&self, f: &mut fmt::Formatter<\'_>) -> fmt::Result {\n        f.debug_struct(\"AeronCError\")\n            .field(\"code\", &self.code)\n            .field(\"kind\", &self.kind())\n            .finish()\n    }\n}\n\nimpl std::error::Error for AeronCError {}\n\n// fn cleanup_closure<T>(clientd: *mut ::std::os::raw::c_void) {\n//     if !clientd.is_null() {\n//         unsafe {\n//             // Convert the raw pointer back into a Box and drop it.\n//             Box::from_raw(clientd as *mut T);\n//             // The Box is dropped when it goes out of scope, automatically calling the destructor (drop).\n//         }\n//     }\n// }\n\n/// # Handler\n///\n/// `Handler` is a struct that wraps a raw pointer and a drop flag.\n///\n/// **Important:** `Handler` does not get dropped automatically.\n/// You need to call the `release` method if you want to clear the memory manually.\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\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        Self {\n            raw_ptr,\n            should_drop: true,\n        }\n    }\n\n    pub fn wrap(handler: Box<&T>) -> Self {\n        let raw_ptr = Box::into_raw(handler) as *mut T;\n        Self {\n            raw_ptr,\n            should_drop: false,\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(self) {\n        if self.should_drop && !self.raw_ptr.is_null() {\n            unsafe {\n                let _ = Box::from_raw(self.raw_ptr as *mut Box<T>);\n            }\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    use std::net::UdpSocket;\n\n    let end_port = u16::MAX;\n\n    for port in start_port..=end_port {\n        if UdpSocket::bind((\"127.0.0.1\", port)).is_ok() {\n            return Some(port);\n        }\n    }\n\n    None\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\n/// Common constants and utilities for Aeron context.\n///\n/// This module provides configuration properties, default values, and a builder for creating Aeron URIs.\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/// Builder for constructing Aeron URIs.\n#[derive(Default, Debug)]\npub struct ChannelUriBuilder {\n    prefix: Option<String>,\n    media: Option<Media>,\n    endpoint: Option<String>,\n    network_interface: Option<String>,\n    control_endpoint: Option<String>,\n    control_mode: Option<ControlMode>,\n    tags: Option<String>,\n    reliable: Option<bool>,\n    ttl: Option<u8>,\n    mtu: Option<u32>,\n    term_length: Option<u32>,\n    initial_term_id: Option<i32>,\n    term_id: Option<i32>,\n    term_offset: Option<u32>,\n    session_id: Option<i32>,\n    linger: Option<u64>,\n    sparse: Option<bool>,\n    additional_params: BTreeMap<String, String>,\n}\n\nimpl ChannelUriBuilder {\n    /// Create a new builder.\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// Set the prefix (e.g., \"aeron-spy\").\n    pub fn prefix(mut self, prefix: &str) -> Self {\n        self.prefix = Some(prefix.to_string());\n        self\n    }\n\n    /// Set the media type.\n    pub fn media(mut self, media: Media) -> Self {\n        self.media = Some(media);\n        self\n    }\n\n    /// Set the endpoint (address:port).\n    pub fn endpoint(mut self, endpoint: &str) -> Self {\n        self.endpoint = Some(endpoint.to_string());\n        self\n    }\n\n    /// Set the network interface.\n    pub fn network_interface(mut self, network_interface: &str) -> Self {\n        self.network_interface = Some(network_interface.to_string());\n        self\n    }\n\n    /// Set the control endpoint (address:port).\n    pub fn control_endpoint(mut self, control_endpoint: &str) -> Self {\n        self.control_endpoint = Some(control_endpoint.to_string());\n        self\n    }\n\n    /// Set the control mode.\n    pub fn control_mode(mut self, control_mode: ControlMode) -> Self {\n        self.control_mode = Some(control_mode);\n        self\n    }\n\n    /// Set tags for the channel.\n    pub fn tags(mut self, tags: &str) -> Self {\n        self.tags = Some(tags.to_string());\n        self\n    }\n\n    /// Set the reliable flag.\n    pub fn reliable(mut self, reliable: bool) -> Self {\n        self.reliable = Some(reliable);\n        self\n    }\n\n    /// Set the Time To Live (TTL).\n    pub fn ttl(mut self, ttl: u8) -> Self {\n        self.ttl = Some(ttl);\n        self\n    }\n\n    /// Set the Maximum Transmission Unit (MTU).\n    pub fn mtu(mut self, mtu: u32) -> Self {\n        self.mtu = Some(mtu);\n        self\n    }\n\n    /// Set the term length.\n    pub fn term_length(mut self, term_length: u32) -> Self {\n        self.term_length = Some(term_length);\n        self\n    }\n\n    /// Set the initial term ID.\n    pub fn initial_term_id(mut self, initial_term_id: i32) -> Self {\n        self.initial_term_id = Some(initial_term_id);\n        self\n    }\n\n    /// Set the term ID.\n    pub fn term_id(mut self, term_id: i32) -> Self {\n        self.term_id = Some(term_id);\n        self\n    }\n\n    /// Set the term offset.\n    pub fn term_offset(mut self, term_offset: u32) -> Self {\n        self.term_offset = Some(term_offset);\n        self\n    }\n\n    /// Set the session ID.\n    pub fn session_id(mut self, session_id: i32) -> Self {\n        self.session_id = Some(session_id);\n        self\n    }\n\n    /// Set the linger timeout.\n    pub fn linger(mut self, linger: u64) -> Self {\n        self.linger = Some(linger);\n        self\n    }\n\n    /// Set the sparse flag.\n    pub fn sparse(mut self, sparse: bool) -> Self {\n        self.sparse = Some(sparse);\n        self\n    }\n\n    /// Add a custom parameter to the URI.\n    pub fn add_param(mut self, key: &str, value: &str) -> Self {\n        self.additional_params\n            .insert(key.to_string(), value.to_string());\n        self\n    }\n\n    /// Build the Aeron URI as a string.\n    pub fn build(self) -> Result<String, String> {\n        let media = self\n            .media\n            .map(|m| m.as_str())\n            .ok_or_else(|| \"Media must be specified\".to_string())?;\n        let mut uri = String::new();\n\n        if let Some(prefix) = self.prefix {\n            uri.push_str(&format!(\"{}:\", prefix));\n        }\n\n        uri.push_str(&format!(\"aeron:{}?\", media));\n\n        if let Some(endpoint) = self.endpoint {\n            uri.push_str(&format!(\"endpoint={}|\", endpoint));\n        }\n\n        if let Some(control_endpoint) = self.control_endpoint {\n            uri.push_str(&format!(\"control={}|\", control_endpoint));\n        }\n\n        if let Some(control_mode) = self.control_mode {\n            uri.push_str(&format!(\"control-mode={}|\", control_mode.as_str()));\n        }\n\n        if let Some(tags) = self.tags {\n            uri.push_str(&format!(\"tags={}|\", tags));\n        }\n\n        if let Some(reliable) = self.reliable {\n            uri.push_str(&format!(\"reliable={}|\", reliable));\n        }\n\n        if let Some(ttl) = self.ttl {\n            uri.push_str(&format!(\"ttl={}|\", ttl));\n        }\n\n        if let Some(mtu) = self.mtu {\n            uri.push_str(&format!(\"mtu={}|\", mtu));\n        }\n\n        if let Some(term_length) = self.term_length {\n            uri.push_str(&format!(\"term-length={}|\", term_length));\n        }\n\n        if let Some(initial_term_id) = self.initial_term_id {\n            uri.push_str(&format!(\"initial-term-id={}|\", initial_term_id));\n        }\n\n        if let Some(term_id) = self.term_id {\n            uri.push_str(&format!(\"term-id={}|\", term_id));\n        }\n\n        if let Some(term_offset) = self.term_offset {\n            uri.push_str(&format!(\"term-offset={}|\", term_offset));\n        }\n\n        if let Some(session_id) = self.session_id {\n            uri.push_str(&format!(\"session-id={}|\", session_id));\n        }\n\n        if let Some(linger) = self.linger {\n            uri.push_str(&format!(\"linger={}|\", linger));\n        }\n\n        if let Some(sparse) = self.sparse {\n            uri.push_str(&format!(\"sparse={}|\", sparse));\n        }\n\n        for (key, value) in self.additional_params {\n            uri.push_str(&format!(\"{}={}|\", key, value));\n        }\n\n        uri.pop();\n        Ok(uri)\n    }\n}\n";