aboutsummaryrefslogtreecommitdiff
path: root/bindings/c/src
diff options
context:
space:
mode:
Diffstat (limited to 'bindings/c/src')
-rw-r--r--bindings/c/src/data_c/common.rs6
-rw-r--r--bindings/c/src/data_c/connection_callback_message_c.rs129
-rw-r--r--bindings/c/src/data_c/connection_message_c.rs95
-rw-r--r--bindings/c/src/data_c/control_message_c.rs150
-rw-r--r--bindings/c/src/data_c/game_message_c.rs114
-rw-r--r--bindings/c/src/data_c/game_profile_c.rs101
-rw-r--r--bindings/c/src/data_c/mod.rs11
-rw-r--r--bindings/c/src/data_c/player_info_c.rs95
-rw-r--r--bindings/c/src/data_c/player_info_list_c.rs8
-rw-r--r--bindings/c/src/lib.rs41
-rw-r--r--bindings/c/src/service_c/common.rs4
-rw-r--r--bindings/c/src/service_c/mod.rs4
-rw-r--r--bindings/c/src/service_c/padclient.rs126
-rw-r--r--bindings/c/src/service_c/padserver.rs174
14 files changed, 1058 insertions, 0 deletions
diff --git a/bindings/c/src/data_c/common.rs b/bindings/c/src/data_c/common.rs
new file mode 100644
index 0000000..58c34c4
--- /dev/null
+++ b/bindings/c/src/data_c/common.rs
@@ -0,0 +1,6 @@
+#[repr(C)]
+#[allow(unused_imports)]
+#[derive(Copy, Clone)]
+pub struct KeyData {
+ pub(crate) key: u8
+} \ No newline at end of file
diff --git a/bindings/c/src/data_c/connection_callback_message_c.rs b/bindings/c/src/data_c/connection_callback_message_c.rs
new file mode 100644
index 0000000..9ded18b
--- /dev/null
+++ b/bindings/c/src/data_c/connection_callback_message_c.rs
@@ -0,0 +1,129 @@
+use crate::data_c::game_profile_c::GameProfileC;
+use nogamepads_lib_rs::pad_data::pad_messages::nogamepads_messages::{ConnectionCallbackMessage, ConnectionErrorType};
+use std::ffi::c_void;
+use std::mem::ManuallyDrop;
+use std::ptr::null_mut;
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub struct ConnectionCallbackMessageC {
+ pub tag: ConnCallbackMsgCTag,
+ pub data: ConnCallbackMsgCUnion,
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub enum ConnCallbackMsgCTag {
+ Profile, Deny, Fail, Ok, Welcome, Err
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub union ConnCallbackMsgCUnion {
+ nul: *mut c_void,
+ profile: ManuallyDrop<GameProfileC>,
+ conn_err: ConnErrTypeC
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+#[derive(Copy, Clone)]
+pub enum ConnErrTypeC {
+ ContainSamePlayer, PlayerBanned, Timeout, GameLocked, WhatTheHell
+}
+
+impl From<ConnErrTypeC> for ConnectionErrorType {
+ fn from(value: ConnErrTypeC) -> Self {
+ match value {
+ ConnErrTypeC::ContainSamePlayer => { ConnectionErrorType::ContainSamePlayer }
+ ConnErrTypeC::PlayerBanned => { ConnectionErrorType::PlayerBanned }
+ ConnErrTypeC::Timeout => { ConnectionErrorType::Timeout }
+ ConnErrTypeC::GameLocked => { ConnectionErrorType::GameLocked }
+ ConnErrTypeC::WhatTheHell => { ConnectionErrorType::WhatTheHell }
+ }
+ }
+}
+
+impl From<ConnectionErrorType> for ConnErrTypeC {
+ fn from(value: ConnectionErrorType) -> Self {
+ match value {
+ ConnectionErrorType::ContainSamePlayer => { ConnErrTypeC::ContainSamePlayer }
+ ConnectionErrorType::PlayerBanned => { ConnErrTypeC::PlayerBanned }
+ ConnectionErrorType::Timeout => { ConnErrTypeC::Timeout }
+ ConnectionErrorType::GameLocked => { ConnErrTypeC::GameLocked }
+ ConnectionErrorType::WhatTheHell => { ConnErrTypeC::WhatTheHell }
+ }
+ }
+}
+
+impl From<ConnectionCallbackMessageC> for ConnectionCallbackMessage {
+ fn from(mut value: ConnectionCallbackMessageC) -> Self {
+ match value.tag {
+ ConnCallbackMsgCTag::Profile => unsafe {
+ let profile = ManuallyDrop::take(&mut value.data.profile);
+ ConnectionCallbackMessage::Profile(profile.into())
+ }
+ ConnCallbackMsgCTag::Deny => unsafe {
+ ConnectionCallbackMessage::Deny(value.data.conn_err.into())
+ }
+ ConnCallbackMsgCTag::Fail => unsafe {
+ ConnectionCallbackMessage::Fail(value.data.conn_err.into())
+ }
+ ConnCallbackMsgCTag::Ok => {
+ ConnectionCallbackMessage::Ok
+
+ }
+ ConnCallbackMsgCTag::Welcome => {
+ ConnectionCallbackMessage::Welcome
+ }
+ ConnCallbackMsgCTag::Err => {
+ ConnectionCallbackMessage::Err
+ }
+ }
+ }
+}
+
+impl From<ConnectionCallbackMessage> for ConnectionCallbackMessageC {
+ fn from(value: ConnectionCallbackMessage) -> Self {
+ match value {
+ ConnectionCallbackMessage::Profile(profile) => {
+ ConnectionCallbackMessageC {
+ tag: ConnCallbackMsgCTag::Profile,
+ data: ConnCallbackMsgCUnion {
+ profile: ManuallyDrop::new(profile.into())
+ }
+ }
+ }
+ ConnectionCallbackMessage::Deny(conn_err) => {
+ ConnectionCallbackMessageC {
+ tag: ConnCallbackMsgCTag::Deny,
+ data: ConnCallbackMsgCUnion { conn_err: conn_err.into() }
+ }
+ }
+ ConnectionCallbackMessage::Fail(conn_err) => {
+ ConnectionCallbackMessageC {
+ tag: ConnCallbackMsgCTag::Fail,
+ data: ConnCallbackMsgCUnion { conn_err: conn_err.into() }
+ }
+ }
+ ConnectionCallbackMessage::Ok => {
+ ConnectionCallbackMessageC {
+ tag: ConnCallbackMsgCTag::Ok,
+ data: ConnCallbackMsgCUnion { nul: null_mut() }
+ }
+ }
+ ConnectionCallbackMessage::Welcome => {
+ ConnectionCallbackMessageC {
+ tag: ConnCallbackMsgCTag::Welcome,
+ data: ConnCallbackMsgCUnion { nul: null_mut() }
+ }
+ }
+ ConnectionCallbackMessage::Err => {
+ ConnectionCallbackMessageC {
+ tag: ConnCallbackMsgCTag::Err,
+ data: ConnCallbackMsgCUnion { nul: null_mut() }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/bindings/c/src/data_c/connection_message_c.rs b/bindings/c/src/data_c/connection_message_c.rs
new file mode 100644
index 0000000..b3b54d4
--- /dev/null
+++ b/bindings/c/src/data_c/connection_message_c.rs
@@ -0,0 +1,95 @@
+use crate::data_c::connection_message_c::ConnMsgCTag::{Connection, Ready, RequestLayoutConfigure, RequestProfile, RequestSkinPackage};
+use std::ffi::c_void;
+use std::mem::ManuallyDrop;
+use std::ptr::null_mut;
+use nogamepads_lib_rs::pad_data::pad_messages::nogamepads_messages::ConnectionMessage;
+use nogamepads_lib_rs::pad_data::pad_player_info::nogamepads_player_info::PlayerInfo;
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub struct ConnectionMessageC {
+ pub tag: ConnMsgCTag,
+ pub data: ConnMsgCUnion
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub enum ConnMsgCTag {
+ Connection, RequestProfile, RequestLayoutConfigure, RequestSkinPackage, Ready, Err
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub union ConnMsgCUnion {
+ nul: *mut c_void,
+ info: ManuallyDrop<PlayerInfo>
+}
+
+impl From<ConnectionMessageC> for ConnectionMessage {
+ fn from(mut value: ConnectionMessageC) -> Self {
+ match value.tag {
+ Connection => unsafe {
+ let info = ManuallyDrop::take(&mut value.data.info);
+ ConnectionMessage::Connection(info)
+ }
+ RequestProfile => {
+ ConnectionMessage::RequestProfile
+ }
+ RequestLayoutConfigure => {
+ ConnectionMessage::RequestLayoutConfigure
+ }
+ RequestSkinPackage => {
+ ConnectionMessage::RequestSkinPackage
+ }
+ Ready => {
+ ConnectionMessage::Ready
+ }
+ ConnMsgCTag::Err => {
+ ConnectionMessage::Err
+ }
+ }
+ }
+}
+
+impl From<ConnectionMessage> for ConnectionMessageC {
+ fn from(value: ConnectionMessage) -> Self {
+ match value {
+ ConnectionMessage::Connection(info) => {
+ ConnectionMessageC {
+ tag: Connection,
+ data: ConnMsgCUnion { info: ManuallyDrop::new(info) }
+ }
+ }
+ ConnectionMessage::RequestProfile => {
+ ConnectionMessageC {
+ tag: RequestProfile,
+ data: ConnMsgCUnion { nul: null_mut() }
+ }
+ }
+ ConnectionMessage::RequestLayoutConfigure => {
+ ConnectionMessageC {
+ tag: RequestLayoutConfigure,
+ data: ConnMsgCUnion { nul: null_mut() }
+ }
+ }
+ ConnectionMessage::RequestSkinPackage => {
+ ConnectionMessageC {
+ tag: RequestSkinPackage,
+ data: ConnMsgCUnion { nul: null_mut() }
+ }
+ }
+ ConnectionMessage::Ready => {
+ ConnectionMessageC {
+ tag: Ready,
+ data: ConnMsgCUnion { nul: null_mut() }
+ }
+ }
+ ConnectionMessage::Err => {
+ ConnectionMessageC {
+ tag: ConnMsgCTag::Err,
+ data: ConnMsgCUnion { nul: null_mut() }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/bindings/c/src/data_c/control_message_c.rs b/bindings/c/src/data_c/control_message_c.rs
new file mode 100644
index 0000000..6868459
--- /dev/null
+++ b/bindings/c/src/data_c/control_message_c.rs
@@ -0,0 +1,150 @@
+use crate::data_c::common::KeyData;
+use crate::{str_c_to_rs, str_rs_to_c};
+use nogamepads_lib_rs::pad_data::pad_messages::nogamepads_messages::ControlMessage;
+use std::ffi::{c_char, c_void};
+use std::ptr::null_mut;
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub struct ControlMessageC {
+ pub tag: CtrlMsgCTag,
+ pub data: CtrlMsgCUnion
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub enum CtrlMsgCTag {
+ Msg, Pressed, Released, Axis, Dir, Exit, Err
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub union CtrlMsgCUnion {
+ nul: *mut c_void,
+ key: KeyData,
+ axis: AxisData,
+ dir: DirData,
+ str: StrData
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+#[derive(Copy, Clone)]
+pub struct AxisData {
+ key: u8,
+ ax: f64
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+#[derive(Copy, Clone)]
+pub struct DirData {
+ key: u8,
+ x: f64,
+ y: f64
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+#[derive(Copy, Clone)]
+pub struct StrData {
+ str: *const c_char
+}
+
+impl From<ControlMessageC> for ControlMessage {
+ fn from(msg_c: ControlMessageC) -> Self {
+ match msg_c.tag {
+ CtrlMsgCTag::Msg => unsafe {
+ let str = str_c_to_rs(msg_c.data.str.str);
+ if str.is_some() {
+ ControlMessage::Msg(str.unwrap())
+ } else {
+ ControlMessage::Err
+ }
+ }
+ CtrlMsgCTag::Pressed => unsafe {
+ ControlMessage::Pressed(msg_c.data.key.key)
+ }
+ CtrlMsgCTag::Released => unsafe {
+ ControlMessage::Released(msg_c.data.key.key)
+ }
+ CtrlMsgCTag::Axis => unsafe {
+ let data = msg_c.data.axis;
+ ControlMessage::Axis(data.key, data.ax)
+ }
+ CtrlMsgCTag::Dir => unsafe {
+ let data = msg_c.data.dir;
+ ControlMessage::Dir(data.key, (data.x, data.y))
+ }
+ CtrlMsgCTag::Exit => {
+ ControlMessage::Exit
+ }
+ CtrlMsgCTag::Err => {
+ ControlMessage::Err
+ }
+ }
+ }
+}
+
+impl From<ControlMessage> for ControlMessageC {
+ fn from(msg_rs: ControlMessage) -> Self {
+ match msg_rs {
+ ControlMessage::Msg(str_msg) => {
+ ControlMessageC {
+ tag: CtrlMsgCTag::Msg,
+ data: CtrlMsgCUnion {
+ str: StrData { str: str_rs_to_c(str_msg).1 },
+ }
+ }
+ }
+ ControlMessage::Pressed(key) => {
+ ControlMessageC {
+ tag: CtrlMsgCTag::Pressed,
+ data: CtrlMsgCUnion {
+ key: KeyData { key },
+ }
+ }
+ }
+ ControlMessage::Released(key) => {
+ ControlMessageC {
+ tag: CtrlMsgCTag::Released,
+ data: CtrlMsgCUnion {
+ key: KeyData { key },
+ }
+ }
+ }
+ ControlMessage::Axis(key, ax) => {
+ ControlMessageC {
+ tag: CtrlMsgCTag::Axis,
+ data: CtrlMsgCUnion {
+ axis: AxisData { key, ax }
+ }
+ }
+ }
+ ControlMessage::Dir(key, (x, y)) => {
+ ControlMessageC {
+ tag: CtrlMsgCTag::Dir,
+ data: CtrlMsgCUnion {
+ dir: DirData { key, x, y }
+ }
+ }
+ }
+ ControlMessage::Exit => {
+ ControlMessageC {
+ tag: CtrlMsgCTag::Exit,
+ data: CtrlMsgCUnion {
+ nul: null_mut(),
+ }
+ }
+ }
+ ControlMessage::Err => {
+ ControlMessageC {
+ tag: CtrlMsgCTag::Err,
+ data: CtrlMsgCUnion {
+ nul: null_mut(),
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/bindings/c/src/data_c/game_message_c.rs b/bindings/c/src/data_c/game_message_c.rs
new file mode 100644
index 0000000..946ce60
--- /dev/null
+++ b/bindings/c/src/data_c/game_message_c.rs
@@ -0,0 +1,114 @@
+use std::ffi::c_void;
+use std::ptr::null_mut;
+use nogamepads_lib_rs::pad_data::pad_messages::nogamepads_messages::{GameMessage, LeaveReason};
+use crate::data_c::common::KeyData;
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub struct GameMessageC {
+ pub tag: GameMsgCTag,
+ pub data: GameMsgCUnion
+}
+
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub enum GameMsgCTag {
+ SkinEventTrigger, DisableKey, EnableKey, Leave, Err
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+pub union GameMsgCUnion {
+ nul: *mut c_void,
+ key: KeyData,
+ reason: LeaveReasonData
+}
+
+#[repr(C)]
+#[allow(unused_imports)]
+#[derive(Copy, Clone)]
+pub enum LeaveReasonData {
+ GameOver, ServerClosed, YouAreKicked, YouAreBanned
+}
+
+impl From<LeaveReasonData> for LeaveReason {
+ fn from(value: LeaveReasonData) -> Self {
+ match value {
+ LeaveReasonData::GameOver => { LeaveReason::GameOver }
+ LeaveReasonData::ServerClosed => { LeaveReason::ServerClosed }
+ LeaveReasonData::YouAreKicked => { LeaveReason::YouAreKicked }
+ LeaveReasonData::YouAreBanned => { LeaveReason::YouAreBanned }
+ }
+ }
+}
+
+impl From<LeaveReason> for LeaveReasonData {
+ fn from(value: LeaveReason) -> Self {
+ match value {
+ LeaveReason::GameOver => { LeaveReasonData::GameOver }
+ LeaveReason::ServerClosed => { LeaveReasonData::ServerClosed }
+ LeaveReason::YouAreKicked => { LeaveReasonData::YouAreKicked }
+ LeaveReason::YouAreBanned => { LeaveReasonData::YouAreBanned }
+ }
+ }
+}
+
+impl From<GameMessageC> for GameMessage {
+ fn from(msg: GameMessageC) -> Self {
+ match msg.tag {
+ GameMsgCTag::SkinEventTrigger => unsafe {
+ GameMessage::SkinEventTrigger(msg.data.key.key)
+ }
+ GameMsgCTag::DisableKey => unsafe {
+ GameMessage::DisableKey(msg.data.key.key)
+ }
+ GameMsgCTag::EnableKey => unsafe {
+ GameMessage::EnableKey(msg.data.key.key)
+ }
+ GameMsgCTag::Leave => unsafe {
+ GameMessage::Leave(msg.data.reason.into())
+ }
+ GameMsgCTag::Err => {
+ GameMessage::Err
+ }
+ }
+ }
+}
+
+impl From<GameMessage> for GameMessageC {
+ fn from(msg: GameMessage) -> Self {
+ match msg {
+ GameMessage::SkinEventTrigger(key) => {
+ GameMessageC {
+ tag: GameMsgCTag::SkinEventTrigger,
+ data: GameMsgCUnion { key: KeyData { key } }
+ }
+ }
+ GameMessage::DisableKey(key) => {
+ GameMessageC {
+ tag: GameMsgCTag::DisableKey,
+ data: GameMsgCUnion { key: KeyData { key } }
+ }
+ }
+ GameMessage::EnableKey(key) => {
+ GameMessageC {
+ tag: GameMsgCTag::EnableKey,
+ data: GameMsgCUnion { key: KeyData { key } }
+ }
+ }
+ GameMessage::Leave(reason) => {
+ GameMessageC {
+ tag: GameMsgCTag::Leave,
+ data: GameMsgCUnion { reason: reason.into() }
+ }
+ }
+ GameMessage::Err => {
+ GameMessageC {
+ tag: GameMsgCTag::Err,
+ data: GameMsgCUnion { nul: null_mut() }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/bindings/c/src/data_c/game_profile_c.rs b/bindings/c/src/data_c/game_profile_c.rs
new file mode 100644
index 0000000..1dd11f7
--- /dev/null
+++ b/bindings/c/src/data_c/game_profile_c.rs
@@ -0,0 +1,101 @@
+use crate::{str_c_to_rs, str_rs_to_c};
+use nogamepads_lib_rs::pad_data::game_profile::game_profile::GameProfile;
+use std::ffi::c_char;
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+#[allow(unused_imports)]
+pub struct GameProfileC {
+ pub game_name: *const c_char,
+ pub game_description: *const c_char,
+ pub organization: *const c_char,
+ pub version: *const c_char,
+ pub website: *const c_char,
+ pub email: *const c_char
+}
+
+impl From<GameProfileC> for GameProfile {
+ fn from(value: GameProfileC) -> Self {
+ let unknown = "".to_string();
+ GameProfile {
+ game_name: str_c_to_rs(value.game_name).unwrap_or(unknown.clone()),
+ game_description: str_c_to_rs(value.game_description).unwrap_or(unknown.clone()),
+ organization: str_c_to_rs(value.organization).unwrap_or(unknown.clone()),
+ version: str_c_to_rs(value.version).unwrap_or(unknown.clone()),
+ website: str_c_to_rs(value.website).unwrap_or(unknown.clone()),
+ email: str_c_to_rs(value.email).unwrap_or(unknown.clone())
+ }
+ }
+}
+
+impl From<GameProfile> for GameProfileC {
+ fn from(value: GameProfile) -> Self {
+ GameProfileC {
+ game_name: str_rs_to_c(value.game_name).1,
+ game_description: str_rs_to_c(value.game_description).1,
+ organization: str_rs_to_c(value.organization).1,
+ version: str_rs_to_c(value.version).1,
+ website: str_rs_to_c(value.website).1,
+ email: str_rs_to_c(value.email).1
+ }
+ }
+}
+
+impl From<&GameProfileC> for &GameProfile {
+ fn from(value: &GameProfileC) -> Self {
+ value.into()
+ }
+}
+
+impl From<&GameProfile> for &GameProfileC {
+ fn from(value: &GameProfile) -> Self {
+ value.into()
+ }
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn init_game_profile() -> GameProfileC {
+ GameProfile::default().into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_game_profile_name(game_profile: GameProfileC, value: *const c_char) -> GameProfileC {
+ let value = str_c_to_rs(value).unwrap_or_default();
+ let mut raw = GameProfile::from(game_profile);
+ raw.game_name(value.as_str()).to_owned().into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_game_profile_description(game_profile: GameProfileC, value: *const c_char) -> GameProfileC {
+ let value = str_c_to_rs(value).unwrap_or_default();
+ let mut raw = GameProfile::from(game_profile);
+ raw.game_description(value.as_str()).to_owned().into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_game_profile_organization(game_profile: GameProfileC, value: *const c_char) -> GameProfileC {
+ let value = str_c_to_rs(value).unwrap_or_default();
+ let mut raw = GameProfile::from(game_profile);
+ raw.organization(value.as_str()).to_owned().into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_game_profile_version(game_profile: GameProfileC, value: *const c_char) -> GameProfileC {
+ let value = str_c_to_rs(value).unwrap_or_default();
+ let mut raw = GameProfile::from(game_profile);
+ raw.version(value.as_str()).to_owned().into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_game_profile_website(game_profile: GameProfileC, value: *const c_char) -> GameProfileC {
+ let value = str_c_to_rs(value).unwrap_or_default();
+ let mut raw = GameProfile::from(game_profile);
+ raw.website(value.as_str()).to_owned().into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_game_profile_email(game_profile: GameProfileC, value: *const c_char) -> GameProfileC {
+ let value = str_c_to_rs(value).unwrap_or_default();
+ let mut raw = GameProfile::from(game_profile);
+ raw.email(value.as_str()).to_owned().into()
+} \ No newline at end of file
diff --git a/bindings/c/src/data_c/mod.rs b/bindings/c/src/data_c/mod.rs
new file mode 100644
index 0000000..afe8728
--- /dev/null
+++ b/bindings/c/src/data_c/mod.rs
@@ -0,0 +1,11 @@
+pub mod common;
+
+pub mod control_message_c;
+pub mod game_message_c;
+pub mod connection_message_c;
+pub mod connection_callback_message_c;
+
+
+pub mod game_profile_c;
+pub mod player_info_c;
+pub mod player_info_list_c; \ No newline at end of file
diff --git a/bindings/c/src/data_c/player_info_c.rs b/bindings/c/src/data_c/player_info_c.rs
new file mode 100644
index 0000000..b8a54e6
--- /dev/null
+++ b/bindings/c/src/data_c/player_info_c.rs
@@ -0,0 +1,95 @@
+use crate::{str_c_to_rs, str_rs_to_c};
+use nogamepads_lib_rs::pad_data::pad_player_info::nogamepads_player_info::{PlayerAccountInfo, PlayerCustomizeInfo, PlayerInfo};
+use std::ffi::c_char;
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+#[allow(unused_imports)]
+pub struct PlayerInfoC {
+ pub account_id: *const c_char,
+ pub account_hash: *const c_char,
+
+ pub customize_nickname: *const c_char,
+ pub customize_color_hue: i32,
+ pub customize_color_saturation: f64,
+ pub customize_color_value: f64,
+}
+
+impl From<PlayerInfoC> for PlayerInfo {
+ fn from(value: PlayerInfoC) -> Self {
+ let unknown = "unknown".to_string();
+ PlayerInfo {
+ account : PlayerAccountInfo {
+ id: str_c_to_rs(value.account_id).unwrap_or(unknown.clone()),
+ player_hash: str_c_to_rs(value.account_hash).unwrap_or(unknown.clone()),
+ },
+ customize: PlayerCustomizeInfo {
+ nickname: str_c_to_rs(value.customize_nickname).unwrap_or(unknown.clone()),
+ color_hue: value.customize_color_hue,
+ color_saturation: value.customize_color_saturation,
+ color_value: value.customize_color_value,
+ }
+ }
+ }
+}
+
+impl From<PlayerInfo> for PlayerInfoC {
+ fn from(value: PlayerInfo) -> Self {
+ PlayerInfoC {
+ account_id: str_rs_to_c(value.account.id).1,
+ account_hash: str_rs_to_c(value.account.player_hash).1,
+ customize_nickname: str_rs_to_c(value.customize.nickname).1,
+ customize_color_hue: value.customize.color_hue,
+ customize_color_saturation: value.customize.color_saturation,
+ customize_color_value: value.customize.color_value,
+ }
+ }
+}
+
+impl From<&PlayerInfoC> for &PlayerInfo {
+ fn from(value: &PlayerInfoC) -> Self {
+ value.into()
+ }
+}
+
+impl From<&PlayerInfo> for &PlayerInfoC {
+ fn from(value: &PlayerInfo) -> Self {
+ value.into()
+ }
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn init_player_info() -> PlayerInfoC {
+ PlayerInfo::new().into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_player_info_account(
+ info: PlayerInfoC, id: *const c_char, password: *const c_char) -> PlayerInfoC {
+
+ let id = str_c_to_rs(id).unwrap_or("".to_string());
+ let password = str_c_to_rs(password).unwrap_or("".to_string());
+
+ let mut raw_info = PlayerInfo::from(info);
+ raw_info.setup_account_info(id.as_str(), password.as_str());
+ raw_info.into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_player_info_color(
+ info: PlayerInfoC, h: i32, s: f64, v: f64) -> PlayerInfoC {
+
+ let mut raw_info = PlayerInfo::from(info);
+ raw_info.set_customize_color_hsv(h, s, v);
+ raw_info.into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_player_info_nickname(
+ info: PlayerInfoC, nickname: *const c_char) -> PlayerInfoC {
+ let nickname = str_c_to_rs(nickname).unwrap_or("".to_string());
+
+ let mut raw_info = PlayerInfo::from(info);
+ raw_info.set_nickname(nickname.as_str());
+ raw_info.into()
+} \ No newline at end of file
diff --git a/bindings/c/src/data_c/player_info_list_c.rs b/bindings/c/src/data_c/player_info_list_c.rs
new file mode 100644
index 0000000..99d5c35
--- /dev/null
+++ b/bindings/c/src/data_c/player_info_list_c.rs
@@ -0,0 +1,8 @@
+use crate::data_c::player_info_c::PlayerInfoC;
+
+#[repr(C)]
+pub struct PlayerList {
+ pub(crate) players: *mut PlayerInfoC,
+ pub(crate) len: usize,
+ pub(crate) capacity: usize,
+} \ No newline at end of file
diff --git a/bindings/c/src/lib.rs b/bindings/c/src/lib.rs
new file mode 100644
index 0000000..6efd0e9
--- /dev/null
+++ b/bindings/c/src/lib.rs
@@ -0,0 +1,41 @@
+use std::ffi::{c_char, CStr, CString};
+
+pub mod data_c;
+pub mod service_c;
+
+pub fn str_rs_to_c(s: String) -> (CString, *const c_char) {
+ let c_string = CString::new(s).expect("");
+ let ptr = c_string.as_ptr();
+ (c_string, ptr)
+}
+
+pub fn str_c_to_rs(ptr: *const c_char) -> Option<String> {
+ if ptr.is_null() {
+ return None;
+ }
+ unsafe {
+ CStr::from_ptr(ptr)
+ .to_str()
+ .ok()
+ .map(|s| s.to_owned())
+ }
+}
+
+#[macro_export]
+macro_rules! box_into_raw {
+ ($expr:expr) => {
+ $crate::box_into_raw!(@inner $expr)
+ };
+
+ ($expr:expr => $t:ty) => {
+ $crate::box_into_raw!(@inner ($expr) as $t)
+ };
+
+ (@inner $expr:expr) => {
+ ::std::boxed::Box::into_raw(::std::boxed::Box::new($expr))
+ };
+
+ (@inner ($expr:expr) as $t:ty) => {
+ ::std::boxed::Box::into_raw(::std::boxed::Box::new($expr) as ::std::boxed::Box<$t>)
+ };
+} \ No newline at end of file
diff --git a/bindings/c/src/service_c/common.rs b/bindings/c/src/service_c/common.rs
new file mode 100644
index 0000000..8b13da0
--- /dev/null
+++ b/bindings/c/src/service_c/common.rs
@@ -0,0 +1,4 @@
+use nogamepads_lib_rs::DEFAULT_PORT;
+
+#[unsafe(no_mangle)]
+pub extern "C" fn get_default_port() -> u16 { DEFAULT_PORT } \ No newline at end of file
diff --git a/bindings/c/src/service_c/mod.rs b/bindings/c/src/service_c/mod.rs
new file mode 100644
index 0000000..674baf7
--- /dev/null
+++ b/bindings/c/src/service_c/mod.rs
@@ -0,0 +1,4 @@
+pub mod common;
+
+pub mod padclient;
+pub mod padserver; \ No newline at end of file
diff --git a/bindings/c/src/service_c/padclient.rs b/bindings/c/src/service_c/padclient.rs
new file mode 100644
index 0000000..b7bac43
--- /dev/null
+++ b/bindings/c/src/service_c/padclient.rs
@@ -0,0 +1,126 @@
+use crate::data_c::control_message_c::ControlMessageC;
+use crate::data_c::game_message_c::GameMessageC;
+use crate::data_c::player_info_c::PlayerInfoC;
+use crate::{box_into_raw, str_c_to_rs, str_rs_to_c};
+use nogamepads_lib_rs::pad_data::pad_messages::nogamepads_messages::GameMessage;
+use nogamepads_lib_rs::pad_service::client::nogamepads_client::PadClient;
+use nogamepads_lib_rs::DEFAULT_PORT;
+use std::ffi::c_char;
+use std::net::{IpAddr, Ipv4Addr};
+use std::str::FromStr;
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+#[allow(unused_imports)]
+pub struct PadClientC {
+ pub target_address: *const c_char,
+ pub target_port: u16,
+ pub bind_player: PlayerInfoC,
+ pub enable_console: bool,
+ pub quiet: bool
+}
+
+impl From<PadClientC> for PadClient {
+ fn from(value: PadClientC) -> Self {
+ let address = IpAddr::from_str(str_c_to_rs(value.target_address).unwrap_or("".to_string()).as_str()).unwrap_or(
+ IpAddr::from(Ipv4Addr::new(127, 0, 0, 1))
+ );
+ let port = value.target_port;
+ let mut client = PadClient::bind_addr_with_port(address, port);
+ client.bind_player(value.bind_player.into());
+ if value.enable_console { client.enable_console(); }
+ if value.quiet { client.quiet(); }
+ client
+ }
+}
+
+impl From<PadClient> for PadClientC {
+ fn from(mut value: PadClient) -> Self {
+ let (addr, port) = value.clone_addr();
+
+ PadClientC {
+ target_address: str_rs_to_c(addr.to_string()).1,
+ target_port: port,
+ bind_player: value.unbind_player().into(),
+ enable_console: value.is_enable_console(),
+ quiet: value.is_quiet(),
+ }
+ }
+}
+impl From<&mut PadClient> for PadClientC {
+ fn from(value: &mut PadClient) -> Self {
+ value.into()
+ }
+}
+
+// 构建
+
+#[unsafe(no_mangle)]
+pub extern "C" fn init_client(address: *const c_char) -> PadClientC {
+ let addr_str = str_c_to_rs(address).unwrap_or("127.0.0.1".to_string());
+ let addr_v4 = Ipv4Addr::from_str(addr_str.as_str()).unwrap_or(
+ Ipv4Addr::new(127, 0, 0, 1));
+ PadClient::bind_addr_with_port(IpAddr::from(addr_v4), DEFAULT_PORT).into()
+}
+
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn init_client_with_port(address: *const c_char, port: u16) -> PadClientC {
+ let addr_str = str_c_to_rs(address).unwrap_or("127.0.0.1".to_string());
+ let addr_v4 = Ipv4Addr::from_str(addr_str.as_str()).unwrap_or(
+ Ipv4Addr::new(127, 0, 0, 1));
+ PadClient::bind_addr_with_port(IpAddr::from(addr_v4), port).into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_client_quiet(client: PadClientC) -> PadClientC {
+ let mut raw: PadClient = client.into();
+ raw.quiet().into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn enable_client_console(client: PadClientC) -> PadClientC {
+ let mut raw: PadClient = client.into();
+ raw.enable_console().into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn bind_player_to_client(client: PadClientC, info: PlayerInfoC) -> PadClientC {
+ let mut raw: PadClient = client.into();
+ raw.bind_player(info.into()).into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn complete(client: PadClientC) -> *mut PadClient {
+ let client: PadClient = client.into();
+ box_into_raw!(client)
+}
+
+// 状态控制
+
+#[unsafe(no_mangle)]
+pub extern "C" fn connect_client_to_server(client: &mut PadClient) {
+ let client = unsafe { Box::from_raw(client) };
+ client.connect();
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn exit_client_from_server(client: &PadClient) {
+ client.exit_server();
+}
+
+// 消息管理
+
+#[unsafe(no_mangle)]
+pub extern "C" fn put_a_msg_to_server(client: &PadClient, msg: ControlMessageC) {
+ client.put_msg(msg.into())
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn pop_a_msg_from_server(client: &PadClient) -> GameMessageC {
+ client.pop_a_msg().unwrap_or(GameMessage::Err).into()
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn pop_msg_from_server_or(client: &PadClient, or: GameMessageC) -> GameMessageC {
+ client.pop_msg_or(or.into()).into()
+} \ No newline at end of file
diff --git a/bindings/c/src/service_c/padserver.rs b/bindings/c/src/service_c/padserver.rs
new file mode 100644
index 0000000..98c5792
--- /dev/null
+++ b/bindings/c/src/service_c/padserver.rs
@@ -0,0 +1,174 @@
+use crate::data_c::game_message_c::GameMessageC;
+use crate::data_c::game_profile_c::GameProfileC;
+use crate::data_c::player_info_c::PlayerInfoC;
+use crate::data_c::player_info_list_c::PlayerList;
+use crate::{box_into_raw, str_c_to_rs};
+use nogamepads_lib_rs::pad_data::pad_player_info::nogamepads_player_info::PlayerInfo;
+use nogamepads_lib_rs::pad_service::server::nogamepads_server::PadServer;
+use nogamepads_lib_rs::DEFAULT_PORT;
+use std::collections::HashMap;
+use std::ffi::c_char;
+use std::net::{IpAddr, Ipv4Addr};
+use std::str::FromStr;
+use std::sync::{Arc, MutexGuard, PoisonError};
+
+// 构建
+
+#[unsafe(no_mangle)]
+pub extern "C" fn init_server(address: *const c_char) -> *mut PadServer {
+ let addr_str = str_c_to_rs(address).unwrap_or("127.0.0.1".to_string());
+ let addr_v4 = Ipv4Addr::from_str(addr_str.as_str()).unwrap_or(
+ Ipv4Addr::new(127, 0, 0, 1));
+ let mut server = PadServer::default();
+ server.addr(IpAddr::from(addr_v4), DEFAULT_PORT);
+ box_into_raw!(server)
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn init_server_with_port(address: *const c_char, port: u16) -> *mut PadServer {
+ let addr_str = str_c_to_rs(address).unwrap_or("127.0.0.1".to_string());
+ let addr_v4 = Ipv4Addr::from_str(addr_str.as_str()).unwrap_or(
+ Ipv4Addr::new(127, 0, 0, 1));
+ let mut server = PadServer::default();
+ server.addr(IpAddr::from(addr_v4), port);
+ box_into_raw!(server)
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn set_server_quiet(server: &mut PadServer) {
+ server.quiet();
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn enable_server_console(server: &mut PadServer) {
+ server.enable_console();
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn bind_profile_to_server(server: &mut PadServer, profile: &GameProfileC) {
+ server.put_profile(profile.clone().into());
+}
+
+// 状态控制
+
+#[unsafe(no_mangle)]
+pub extern "C" fn start_server(server: *mut PadServer) {
+ let server = unsafe { Box::from_raw(server) };
+ let arc = Arc::new(server.as_ref().clone());
+ PadServer::start_server(arc);
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn stop_server(server: *mut PadServer) {
+ let server = unsafe { Box::from_raw(server) };
+ server.stop_server();
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn lock_game_on_server(server: *mut PadServer) {
+ let server = unsafe { Box::from_raw(server) };
+ server.lock_game();
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn unlock_game_on_server(server: *mut PadServer) {
+ let server = unsafe { Box::from_raw(server) };
+ server.unlock_game();
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn is_server_game_locked(server: *mut PadServer) -> bool {
+ let server = unsafe { Box::from_raw(server) };
+ server.is_game_locked()
+}
+
+// 消息管理
+#[unsafe(no_mangle)]
+pub extern "C" fn put_a_msg_to_player(server: *mut PadServer, msg: GameMessageC, player: &PlayerInfoC) {
+ let server = unsafe { Box::from_raw(server) };
+ server.put_msg_to(msg.into(), player.into());
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn put_msg_to_all_players(server: *mut PadServer, msg: GameMessageC) {
+ let server = unsafe { Box::from_raw(server) };
+ server.put_msg_to_all(&msg.into());
+}
+
+// #[unsafe(no_mangle)]
+// pub extern "C" fn pop_a_msg(server: *mut PadServer) -> ControlMessageC {
+// let server = unsafe { Box::from_raw(server) };
+// let msg = server.pop_a_msg();
+// if msg.is_some() {
+// let (player, msg) = msg.unwrap();
+// }
+// }
+
+// 玩家管理
+#[unsafe(no_mangle)]
+pub extern "C" fn is_player_online(server: *mut PadServer, player: &PlayerInfoC) -> bool {
+ let server = unsafe { Box::from_raw(server) };
+ server.is_player_online(player.into())
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn is_player_banned(server: *mut PadServer, player: &PlayerInfoC) -> bool {
+ let server = unsafe { Box::from_raw(server) };
+ server.is_player_banned(player.into())
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn kick_player(server: *mut PadServer, player: &PlayerInfoC) {
+ let server = unsafe { Box::from_raw(server) };
+ server.kick_player(player.into());
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn ban_player(server: *mut PadServer, player: &PlayerInfoC) {
+ let server = unsafe { Box::from_raw(server) };
+ server.ban_player(player.into());
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn pardon_player(server: *mut PadServer, player: &PlayerInfoC) {
+ let server = unsafe { Box::from_raw(server) };
+ server.pardon_player(player.into());
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn list_online_players(server: *mut PadServer) -> PlayerList {
+ let server = unsafe { Box::from_raw(server) };
+ let list = server.list_players();
+ process_list_result(list)
+}
+
+#[unsafe(no_mangle)]
+pub extern "C" fn list_banned_players(server: *mut PadServer) -> PlayerList {
+ let server = unsafe { Box::from_raw(server) };
+ let list = server.list_players_banned();
+ process_list_result(list)
+}
+
+fn process_list_result(list: Result<Vec<PlayerInfo>, PoisonError<MutexGuard<HashMap<String, PlayerInfo>>>>) -> PlayerList {
+ let result : Vec<PlayerInfo>;
+ if list.is_ok() {
+ result = list.unwrap();
+ } else {
+ result = vec![];
+ }
+ let mut result_c: Vec<PlayerInfoC> = Vec::new();
+ for item in result {
+ result_c.push(item.into());
+ }
+
+ let mut vec = result_c.into_boxed_slice();
+ let ptr = vec.as_mut_ptr();
+ let len = vec.len();
+ let capacity = vec.len();
+
+ PlayerList {
+ players: ptr,
+ len,
+ capacity
+ }
+} \ No newline at end of file