From 749d0abf7973ac0d6612d7357e8aa1b00f13cf3d Mon Sep 17 00:00:00 2001 From: lurchi Date: Sun, 11 Sep 2016 03:11:14 +0200 Subject: [PATCH] add variable and method modules --- rust/Cargo.toml | 3 ++ rust/src/keyword.rs | 36 +++++++++++++++++++ rust/src/lib.rs | 19 ++++++++-- rust/src/method.rs | 45 ++++++++++++++++++++++++ rust/src/method_types.rs | 61 ++++++++++++++++++++++++++++++++ rust/src/types.rs | 15 +++++++- rust/src/variable.rs | 69 +++++++++++++++++++++++++++++++++++++ rust/src/variable_types.rs | 39 +++++++++++++++++++++ rust/tests/test_method.rs | 38 ++++++++++++++++++++ rust/tests/test_variable.rs | 44 +++++++++++++++++++++++ 10 files changed, 365 insertions(+), 4 deletions(-) create mode 100644 rust/src/keyword.rs create mode 100644 rust/src/method.rs create mode 100644 rust/src/method_types.rs create mode 100644 rust/src/variable.rs create mode 100644 rust/src/variable_types.rs create mode 100644 rust/tests/test_method.rs create mode 100644 rust/tests/test_variable.rs diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 38b5801..5302866 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -4,3 +4,6 @@ version = "1.0.0" links = "psyc" build = "build.rs" description = "rust bindings for libpsyc" + +[dependencies] +bitflags = "0.7.0" diff --git a/rust/src/keyword.rs b/rust/src/keyword.rs new file mode 100644 index 0000000..494dbd2 --- /dev/null +++ b/rust/src/keyword.rs @@ -0,0 +1,36 @@ +use std::os::raw::{c_char, c_int}; + +extern "C" { + fn psyc_inherits(sho: *const c_char, + slen: usize, + lon: *const c_char, + llen: usize) + -> c_int; + fn psyc_matches(sho: *const c_char, + slen: usize, + lon: *const c_char, + llen: usize) + -> c_int; +} + +pub trait Keyword { + fn keyword(&self) -> &[u8]; + + fn inherits(&self, other: &[u8]) -> bool { + let keyword_ptr = self.keyword().as_ptr() as *const c_char; + let other_ptr = other.as_ptr() as *const c_char; + let result = unsafe { + psyc_inherits(other_ptr, other.len(), keyword_ptr, self.keyword().len()) + }; + result == 0 + } + + fn matches(&self, other: &[u8]) -> bool { + let keyword_ptr = self.keyword().as_ptr() as *const c_char; + let other_ptr = other.as_ptr() as *const c_char; + let result = unsafe { + psyc_matches(other_ptr, other.len(), keyword_ptr, self.keyword().len()) + }; + result == 0 + } +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 1850e8e..9630c5f 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,17 +1,30 @@ #![allow(dead_code)] -mod types; -mod util; -mod uniform_types; +#[macro_use] +extern crate bitflags; + +mod keyword; +mod method_types; mod packet_types; mod parser_types; +mod types; +mod uniform_types; +mod util; +mod variable_types; +pub mod method; pub mod parser; pub mod packet; pub mod packet_id; pub mod uniform; +pub mod variable; +pub use keyword::Keyword; +pub use method::Method; +pub use method_types::*; pub use parser::*; pub use packet::*; pub use packet_id::*; pub use uniform::*; pub use uniform_types::{UniformParseError, PsycScheme, PsycEntity}; pub use packet_types::{PsycOperator, PsycStateOp}; +pub use variable::*; +pub use variable_types::{PsycRoutingVar, PsycType}; diff --git a/rust/src/method.rs b/rust/src/method.rs new file mode 100644 index 0000000..e1b5cbe --- /dev/null +++ b/rust/src/method.rs @@ -0,0 +1,45 @@ +use method_types::{PsycMethod, PsycMethodFlags, MethodInfo}; +use keyword::Keyword; +use std::mem; +use std::os::raw::{c_char, c_uint}; + +extern "C" { + fn psyc_method(method: *const c_char, + methodlen: usize, + family: *mut PsycMethod, + flag: *mut c_uint) + -> PsycMethod; +} + +pub struct Method<'a> { + pub method: &'a [u8] +} + +impl<'a> Keyword for Method<'a> { + fn keyword(&self) -> &[u8] { + self.method + } +} + +impl<'a> Method<'a> { + pub fn lookup(&self) -> MethodInfo { + let method_ptr = self.method.as_ptr() as *const c_char; + let lookup_result: PsycMethod; + let mut family: PsycMethod; + let mut flags: PsycMethodFlags; + unsafe { + family = mem::uninitialized(); + flags = mem::uninitialized(); + let flags_ptr = &mut flags as *mut PsycMethodFlags as *mut c_uint; + lookup_result = psyc_method(method_ptr, + self.method.len(), + &mut family as *mut PsycMethod, + flags_ptr) + } + MethodInfo { + lookup_result: lookup_result, + family: family, + flags: flags + } + } +} diff --git a/rust/src/method_types.rs b/rust/src/method_types.rs new file mode 100644 index 0000000..b8a44d4 --- /dev/null +++ b/rust/src/method_types.rs @@ -0,0 +1,61 @@ +use std::os::raw::c_int; + +bitflags! { + pub flags PsycMethodFlags: c_int { + const PSYC_METHOD_TEMPLATE = 1 << 0, + const PSYC_METHOD_REPLY = 1 << 1, + const PSYC_METHOD_VISIBLE = 1 << 2, + const PSYC_METHOD_LOGGABLE = 1 << 3, + const PSYC_METHOD_MANUAL = 1 << 4 + } +} + + +#[repr(C)] +#[derive(Debug, PartialEq)] +pub enum PsycMethod { + PSYC_MC_UNKNOWN, + + PSYC_MC_CONVERSE, + PSYC_MC_DATA, + PSYC_MC_ECHO, + PSYC_MC_ECHO_CONTEXT_ENTER, + PSYC_MC_ECHO_CONTEXT_LEAVE, + PSYC_MC_ECHO_HELLO, + PSYC_MC_ERROR, + PSYC_MC_FAILURE, + PSYC_MC_FAILURE_ALIAS_NONEXISTANT, + PSYC_MC_FAILURE_ALIAS_UNAVAILABLE, + PSYC_MC_INFO, + PSYC_MC_MESSAGE, // deprecated, use _converse + PSYC_MC_MESSAGE_ACTION, // deprecated, use _converse + PSYC_MC_NOTICE, + PSYC_MC_NOTICE_ALIAS_ADD, + PSYC_MC_NOTICE_ALIAS_CHANGE, + PSYC_MC_NOTICE_ALIAS_REMOVE, + PSYC_MC_NOTICE_CONTEXT_ENTER, + PSYC_MC_NOTICE_CONTEXT_LEAVE, + PSYC_MC_NOTICE_FRIENDSHIP, + PSYC_MC_NOTICE_LINK, + PSYC_MC_NOTICE_PEER_CONNECT, + PSYC_MC_NOTICE_PEER_DISCONNECT, + PSYC_MC_NOTICE_SET, + PSYC_MC_NOTICE_UNLINK, + PSYC_MC_REQUEST, + PSYC_MC_REQUEST_CONTEXT_ENTER, + PSYC_MC_REQUEST_CONTEXT_LEAVE, + PSYC_MC_REQUEST_FRIENDSHIP, + PSYC_MC_STATUS, + PSYC_MC_STATUS_CONTEXTS_ENTERED, + PSYC_MC_STATUS_HELLO, + PSYC_MC_WARNING, + + PSYC_METHODS_NUM, +} + +#[derive(Debug, PartialEq)] +pub struct MethodInfo { + pub lookup_result: PsycMethod, + pub family: PsycMethod, + pub flags: PsycMethodFlags +} diff --git a/rust/src/types.rs b/rust/src/types.rs index 4011d8c..b23cfa3 100644 --- a/rust/src/types.rs +++ b/rust/src/types.rs @@ -7,6 +7,12 @@ pub enum PsycRC { PSYC_ERROR = -1, } +#[repr(C)] +pub enum PsycBool { + PSYC_FALSE = 0, + PSYC_TRUE = 1, +} + #[derive(Debug)] #[repr(C)] pub struct PsycString { @@ -14,4 +20,11 @@ pub struct PsycString { pub data: *const c_char } - +impl PsycBool { + pub fn to_bool(self) -> bool { + match self { + PsycBool::PSYC_FALSE => false, + PsycBool::PSYC_TRUE => true + } + } +} diff --git a/rust/src/variable.rs b/rust/src/variable.rs new file mode 100644 index 0000000..155c8a9 --- /dev/null +++ b/rust/src/variable.rs @@ -0,0 +1,69 @@ +use types::PsycBool; +use variable_types::*; +use keyword::Keyword; +use std::os::raw::c_char; + +extern "C" { + fn psyc_var_routing(name: *const c_char, len: usize) -> PsycRoutingVar; + fn psyc_var_type(name: *const c_char, len: usize) -> PsycType; + fn psyc_var_is_list(name: *const c_char, len: usize) -> PsycBool; +} + +pub struct RoutingVariable<'a> { + pub variable: &'a [u8] +} + +pub struct EntityVariable<'a> { + pub variable: &'a [u8] +} + +impl<'a> Variable for RoutingVariable<'a> { + fn variable(&self) -> &[u8] { + self.variable + } +} + +impl<'a> Variable for EntityVariable<'a> { + fn variable(&self) -> &[u8] { + self.variable + } +} + +impl<'a> Keyword for RoutingVariable<'a> { + fn keyword(&self) -> &[u8] { + self.variable + } +} + +impl<'a> Keyword for EntityVariable<'a> { + fn keyword(&self) -> &[u8] { + self.variable + } +} + +impl<'a> RoutingVariable<'a> { + pub fn lookup(&self) -> PsycRoutingVar { + let variable_ptr = self.variable().as_ptr() as *const c_char; + unsafe { + psyc_var_routing(variable_ptr, self.variable().len()) + } + } +} + +pub trait Variable { + fn variable(&self) -> &[u8]; + + fn datatype(&self) -> PsycType { + let variable_ptr = self.variable().as_ptr() as *const c_char; + unsafe { + psyc_var_type(variable_ptr, self.variable().len()) + } + } + + fn is_list(&self) -> bool { + let variable_ptr = self.variable().as_ptr() as *const c_char; + unsafe { + psyc_var_is_list(variable_ptr, self.variable().len()).to_bool() + } + } +} diff --git a/rust/src/variable_types.rs b/rust/src/variable_types.rs new file mode 100644 index 0000000..02baab2 --- /dev/null +++ b/rust/src/variable_types.rs @@ -0,0 +1,39 @@ +#[repr(C)] +#[derive(Debug, PartialEq)] +pub enum PsycRoutingVar { + PSYC_RVAR_UNKNOWN, + + PSYC_RVAR_AMOUNT_FRAGMENTS, + PSYC_RVAR_CONTEXT, + PSYC_RVAR_COUNTER, + PSYC_RVAR_FRAGMENT, + PSYC_RVAR_SOURCE, + PSYC_RVAR_SOURCE_RELAY, + PSYC_RVAR_TAG, + PSYC_RVAR_TAG_RELAY, + PSYC_RVAR_TARGET, + PSYC_RVAR_TARGET_RELAY, + + PSYC_RVARS_NUM, +} + +#[repr(C)] +#[derive(Debug, PartialEq)] +pub enum PsycType { + PSYC_TYPE_UNKNOWN, + PSYC_TYPE_AMOUNT, + PSYC_TYPE_COLOR, + PSYC_TYPE_COUNTER, + PSYC_TYPE_DATE, + PSYC_TYPE_DEGREE, + PSYC_TYPE_DICT, + PSYC_TYPE_ENTITY, + PSYC_TYPE_FLAG, + PSYC_TYPE_LANGUAGE, + PSYC_TYPE_LIST, + PSYC_TYPE_NICK, + PSYC_TYPE_PAGE, + PSYC_TYPE_STRUCT, + PSYC_TYPE_TIME, + PSYC_TYPE_UNIFORM, +} diff --git a/rust/tests/test_method.rs b/rust/tests/test_method.rs new file mode 100644 index 0000000..1372106 --- /dev/null +++ b/rust/tests/test_method.rs @@ -0,0 +1,38 @@ +extern crate psyc; +use psyc::*; + +#[test] +fn test_method_matching() { + let m = Method {method: b"_notice_context_enter"}; + + assert!(m.inherits(b"_notice_context")); + assert!(m.matches(b"_context")); +} + +#[test] +fn test_method_lookup() { + let m = Method {method: b"_notice_context_enter"}; + + let expected_flags = PSYC_METHOD_TEMPLATE | + PSYC_METHOD_VISIBLE | + PSYC_METHOD_LOGGABLE; + + assert_eq!(m.lookup(), + MethodInfo { + lookup_result: PsycMethod::PSYC_MC_NOTICE_CONTEXT_ENTER, + family: PsycMethod::PSYC_MC_NOTICE, + flags: expected_flags + }); +} + +#[test] +fn test_lookup_empty() { + let m = Method {method: b""}; + + assert_eq!(m.lookup(), + MethodInfo { + lookup_result: PsycMethod::PSYC_MC_UNKNOWN, + family: PsycMethod::PSYC_MC_UNKNOWN, + flags: PsycMethodFlags::empty() + }); +} diff --git a/rust/tests/test_variable.rs b/rust/tests/test_variable.rs new file mode 100644 index 0000000..0848af9 --- /dev/null +++ b/rust/tests/test_variable.rs @@ -0,0 +1,44 @@ +extern crate psyc; +use psyc::*; + +#[test] +fn test_routing_variable() { + let r = RoutingVariable {variable: b"_amount_fragments"}; + + assert_eq!(r.lookup(), PsycRoutingVar::PSYC_RVAR_AMOUNT_FRAGMENTS); + assert_eq!(r.datatype(), PsycType::PSYC_TYPE_AMOUNT); + assert_eq!(r.is_list(), false); +} + +#[test] +fn test_entity_variable() { + let e = EntityVariable {variable: b"_nick_family"}; + + assert_eq!(e.datatype(), PsycType::PSYC_TYPE_NICK); + assert!(! e.is_list()); +} + +#[test] +fn test_empty() { + let r = RoutingVariable {variable: b""}; + + assert_eq!(r.lookup(), PsycRoutingVar::PSYC_RVAR_UNKNOWN); + assert_eq!(r.datatype(), PsycType::PSYC_TYPE_UNKNOWN); + assert!(! r.is_list()); +} + +#[test] +fn test_inherits() { + let r = RoutingVariable {variable: b"_target_relay"}; + + assert!(r.inherits(b"_target")); + assert!(! r.inherits(b"")); +} + +#[test] +fn test_matches() { + let r = RoutingVariable {variable: b"_target_relay"}; + + assert!(r.matches(b"_relay")); + assert!(! r.matches(b"")); +}