//! C functions for interacting with [SPConnection]s //! //! prefix `sp_connection_` //! //! A connection to the display. //! //! # Examples //! //! ```C //! CConnection connection = sp_connection_open("172.23.42.29:2342"); //! if (connection != NULL) //! sp_connection_send_command(connection, sp_command_clear()); //! ``` use servicepoint::{Connection, Packet, TypedCommand, UdpConnection}; use std::ffi::{c_char, CStr}; /// Creates a new instance of [SPConnection]. /// /// returns: NULL if connection fails, or connected instance /// /// # Panics /// /// - when `host` is null or an invalid host /// /// # Safety /// /// The caller has to make sure that: /// /// - the returned instance is freed in some way, either by using a consuming function or /// by explicitly calling `sp_connection_free`. #[no_mangle] pub unsafe extern "C" fn sp_connection_open( host: *const c_char, ) -> *mut UdpConnection { assert!(!host.is_null()); let host = unsafe { CStr::from_ptr(host) } .to_str() .expect("Bad encoding"); let connection = match UdpConnection::open(host) { Err(_) => return std::ptr::null_mut(), Ok(value) => value, }; Box::into_raw(Box::new(connection)) } //#[no_mangle] //pub unsafe extern "C" fn sp_connection_open_ipv4( // host: SocketAddrV4, //) -> *mut SPConnection { // let connection = match servicepoint::UdpConnection::open(host) { // Err(_) => return std::ptr::null_mut(), // Ok(value) => value, // }; // // Box::into_raw(Box::new(SPConnection(connection))) //} // /// Creates a new instance of [SPUdpConnection] for testing that does not actually send anything. // /// // /// returns: a new instance. Will never return NULL. // /// // /// # Safety // /// // /// The caller has to make sure that: // /// // /// - the returned instance is freed in some way, either by using a consuming function or // /// by explicitly calling `sp_connection_free`. // #[no_mangle] // pub unsafe extern "C" fn sp_connection_fake() -> NonNull { // let result = Box::new(SPUdpConnection(servicepoint::Connection::Fake)); // NonNull::from(Box::leak(result)) // } /// Sends a [SPPacket] to the display using the [SPConnection]. /// /// The passed `packet` gets consumed. /// /// returns: true in case of success /// /// # Panics /// /// - when `connection` is NULL /// - when `packet` is NULL /// /// # Safety /// /// The caller has to make sure that: /// /// - `connection` points to a valid instance of [SPConnection] /// - `packet` points to a valid instance of [SPPacket] /// - `packet` is not used concurrently or after this call #[no_mangle] pub unsafe extern "C" fn sp_connection_send_packet( connection: *const UdpConnection, packet: *mut Packet, ) -> bool { assert!(!connection.is_null()); assert!(!packet.is_null()); let packet = unsafe { Box::from_raw(packet) }; unsafe { (*connection).send(*packet) }.is_ok() } /// Sends a [SPCommand] to the display using the [SPConnection]. /// /// The passed `command` gets consumed. /// /// returns: true in case of success /// /// # Panics /// /// - when `connection` is NULL /// - when `command` is NULL /// /// # Safety /// /// The caller has to make sure that: /// /// - `connection` points to a valid instance of [SPConnection] /// - `command` points to a valid instance of [SPPacket] /// - `command` is not used concurrently or after this call #[no_mangle] pub unsafe extern "C" fn sp_connection_send_command( connection: *const UdpConnection, command: *mut TypedCommand, ) -> bool { assert!(!connection.is_null()); assert!(!command.is_null()); let command = *unsafe { Box::from_raw(command) }; unsafe { (*connection).send(command) }.is_ok() } /// Closes and deallocates a [SPConnection]. /// /// # Panics /// /// - when `connection` is NULL /// /// # Safety /// /// The caller has to make sure that: /// /// - `connection` points to a valid [SPConnection] /// - `connection` is not used concurrently or after this call #[no_mangle] pub unsafe extern "C" fn sp_connection_free(connection: *mut UdpConnection) { assert!(!connection.is_null()); _ = unsafe { Box::from_raw(connection) }; }