add variable and method modules

This commit is contained in:
lurchi 2016-09-11 03:11:14 +02:00
parent 27dc1292ba
commit 749d0abf79
10 changed files with 365 additions and 4 deletions

View File

@ -4,3 +4,6 @@ version = "1.0.0"
links = "psyc"
build = "build.rs"
description = "rust bindings for libpsyc"
[dependencies]
bitflags = "0.7.0"

36
rust/src/keyword.rs Normal file
View File

@ -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
}
}

View File

@ -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};

45
rust/src/method.rs Normal file
View File

@ -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
}
}
}

61
rust/src/method_types.rs Normal file
View File

@ -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
}

View File

@ -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
}
}
}

69
rust/src/variable.rs Normal file
View File

@ -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()
}
}
}

View File

@ -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,
}

38
rust/tests/test_method.rs Normal file
View File

@ -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()
});
}

View File

@ -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""));
}